[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help Razor improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Please include if you are using the standard OSI client or using ClassicUO.**\n\nRemember, **Great Bug Reports** tend to have:\n\n- A quick summary and/or background of the issue\n- Steps to reproduce\n  - Be specific! This can be challenging at times in a game like UO, but the more specific you are, the easier it is to fix\n  - Include screenshots, gifs, videos if possible. Free apps like ShareX and Greenshot make it easy.\n- What you expected would happen\n- What actually happens\n- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for Razor\ntitle: \"[FEATURE]\"\nlabels: enhancement\nassignees: ''\n\n---\n\nAll feature requests will be considered, but not all will be implemented but please don't let that discourage you from submitting more.\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/build-only.yml",
    "content": "name: Build Only\n\non:\n  pull_request:\n    branches:\n      - master\n    paths-ignore:\n      - 'help/**'\n      - '**/build-site.yml'     \n\njobs:\n\n  build:\n\n    strategy:\n      matrix:\n        configuration: [Release]\n\n    runs-on: windows-2022\n\n    env:\n      Solution_Name: Razor.sln       \n\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v2\n      with:\n        fetch-depth: 0\n    \n    - name: Install .NET\n      uses: actions/setup-dotnet@v1\n      with:\n        dotnet-version: 6.0.x\n\n    - name: Setup MSBuild.exe\n      uses: microsoft/setup-msbuild@v1.1\n\n    - name: Restore Razor\n      run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration\n      env:\n        Configuration: ${{ matrix.configuration }}\n\n    - name: Build Razor\n      run: msbuild $env:Solution_Name /t:Build /p:Configuration=$env:Configuration\n      env:\n        Configuration: ${{ matrix.configuration }}\n\n\n"
  },
  {
    "path": ".github/workflows/build-site.yml",
    "content": "name: Build Site\n\non:\n  push:\n    branches:\n      - master\n    paths:\n    - 'help/**'\n    - '**/build-site.yml'\n  pull_request:\n    branches:\n      - master\n    paths:\n    - 'help/**'\n    - '**/build-site.yml'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: ./help\n    strategy:\n      matrix:\n        python-version: [3.10.9]\n    \n    steps:\n      - uses: actions/checkout@v3\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v4\n        with:\n          python-version: ${{ matrix.python-version }}\n          \n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          pip install mkdocs\n          pip install mkdocs-material                    \n          pip install mkdocs-git-revision-date-localized-plugin\n          pip install pillow\n          pip install cairosvg \n          sudo apt-get install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev\n      \n      - name: Install and modify Pygments\n        run: |\n\n          git clone https://github.com/pygments/pygments.git\n          \n          # Replace with Razor files\n          rm ./pygments/pygments/lexers/_mapping.py\n          cp pygments.mapping.razor ./pygments/pygments/lexers/_mapping.py\n          \n          cp pygments.lexers.razor ./pygments/pygments/lexers/razor.py          \n          cp pygments.styles.razor ./pygments/pygments/styles/razor.py\n\n          pip install -e ./pygments/          \n\n      # Runs a single command using the runners shell\n      - name: Build site\n        run: mkdocs build\n\n      - name: Generate robots.txt\n        run: |\n          cat > ./site/robots.txt <<EOF\n          User-agent: *\n          Allow: /\n\n          Sitemap: https://www.razorce.com/sitemap.xml\n          EOF          \n\n      # Setup AWS\n      - name: Configure AWS Credentials\n        uses: aws-actions/configure-aws-credentials@v1\n        with:\n          aws-access-key-id: ${{ secrets.AWS_ACCESS_ID }}\n          aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}\n          aws-region: us-east-1\n\n      - name: Deploy static site to S3 bucket\n        run: aws s3 sync ./site s3://www.razorce.com\n\n      # Invalidate the distributons\n      - name: Create CloudFront Invalidation\n        run: |\n          aws cloudfront create-invalidation --distribution-id ${{ secrets.DISTRIBUTION_A }} --paths \"/*\" \n          aws cloudfront create-invalidation --distribution-id ${{ secrets.DISTRIBUTION_B }} --paths \"/*\" "
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build Dev Preview\n\non:\n  push:\n    branches:\n      - master\n    paths-ignore:\n      - 'help/**'\n      - '**/build-site.yml'\n\njobs:\n\n  build:\n\n    strategy:\n      matrix:\n        configuration: [Release]\n\n    runs-on: windows-2022\n\n    env:\n      Solution_Name: Razor.sln       \n\n    steps:\n    - name: Checkout\n      uses: actions/checkout@v2\n      with:\n        fetch-depth: 0\n    \n    - name: Install .NET\n      uses: actions/setup-dotnet@v1\n      with:\n        dotnet-version: 6.0.x\n\n    - name: Setup MSBuild.exe\n      uses: microsoft/setup-msbuild@v1.1\n\n    - name: Restore Razor\n      run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration\n      env:\n        Configuration: ${{ matrix.configuration }}\n        \n    - name: Set AssemblyInfo\n      uses: dannevesdantas/set-version-assemblyinfo@v.1.0.0\n      with:                     \n        version: '1.10.${{ github.run_number }}.0'\n\n    - name: Build Razor (x86)\n      run: msbuild $env:Solution_Name /t:Build /p:Configuration=$env:Configuration /p:Platform=\"Any CPU\"\n      env:\n        Configuration: ${{ matrix.configuration }}\n\n    - name: Build Razor (x64)\n      run: msbuild $env:Solution_Name /t:Build /p:Configuration=$env:Configuration /p:Platform=x64\n      env:\n        Configuration: ${{ matrix.configuration }}\n\n    - name: Archive Razor x86 build artifacts      \n      run: |\n        cd bin/Win32/Release/\n        7z a -tzip \"Razor-dev-x86-preview.zip\" \"*\"\n\n    - name: Archive Razor x64 build artifacts      \n      run: |\n        cd bin/x64/Release/\n        7z a -tzip \"Razor-dev-x64-preview.zip\" \"*\"\n\n    - name: Delete Dev Release\n      uses: dev-drprasad/delete-tag-and-release@v0.2.1\n      with:\n        delete_release: true\n        tag_name: Razor-dev-preview\n        github_token: ${{ secrets.GITHUB_TOKEN }}\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Create Dev Release\n      uses: ncipollo/release-action@v1\n      with:\n        name: \"Razor Dev Preview\"\n        body: \"This is built automatically after each commit to master, so it may contain bugs and/or unfinished features but is generally considered stable. Use at your own risk.\"\n        artifacts: \"bin/Win32/Release/Razor-dev-x86-preview.zip,bin/x64/Release/Razor-dev-x64-preview.zip\"          \n        prerelease: true\n        tag: Razor-dev-preview\n        token: ${{ secrets.GITHUB_TOKEN }}\n\n"
  },
  {
    "path": ".gitignore",
    "content": "# Visual Studio\n*.vs\n*.vscode\n*.vcxproj.user\n*.csproj.user\n.vscode\npackages/\n\n# Rider\n.idea\n\n# Build Output\n[Dd]ebug/\n[Rr]elease/\n/Crypt.quick\n/wiki-github.txt\n/Razor.sln.DotSettings.user\n/Razor.sln.DotSettings\nCSharpGuidelines.Layer.DotSettings\n/help/site\n/help/pygments\n.cache\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"ScriptEngine/Steam\"]\n\tpath = ScriptEngine/Steam\n\turl = https://github.com/jaedan/steam-engine\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "## Code of Conduct\n\n### Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\n### Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the project and community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n### Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n### Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n### Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n### Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nWe want to make contributing to this project as easy and transparent as possible, whether it's:\n\n- Reporting a bug\n- Discussing the current state of the code\n- Submitting a fix\n- Proposing new features\n- Testing the compiled version\n\nWhen contributing to this repository, either through a bug report or a pull request, please first discuss the change or bug via Discord or any other method with the owners of this repository.\n\n[![Chat on Discord status](https://img.shields.io/discord/458277173208547350.svg?logo=discord)](https://discord.gg/VdyCpjQ)\n\nPlease note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with this project.\n\n### Pull Request Process\n\n1. Fork the repo and create your own branch from master\n2. Make your code changes. If you plan on adding multiple changes, please create commits for each change instead of one commit with all the changes.\n3. Create a pull request based on your branch\n\nThe pull request will be reviewed, tested and a decision to merge or not will be made.\n\n### Your Contributions\n\nWhen you submit code changes, your submissions are understood to be under the same [GPLv3](LICENSE) that covers the project."
  },
  {
    "path": "Crypt/Crypt.cpp",
    "content": "#include \"stdafx.h\"\r\n#include \"Crypt.h\"\r\n#include \"uo_huffman.h\"\r\n#include \"PacketInfo.h\"\r\n#include \"OSIEncryption.h\"\r\n#include \"LoginEncryption.h\"\r\n#include \"MemFinder.h\"\r\n\r\n//*************************************************************************************\r\n//**************************************Variables**************************************\r\n//*************************************************************************************\r\nHHOOK hWndProcRetHook = NULL;\r\nHHOOK hGetMsgHook = NULL;\r\nHWND hUOWindow = NULL;\r\nHWND hRazorWnd = NULL;\r\nHWND hMapWnd = NULL;\r\nDWORD UOProcId = 0;\r\n\r\nHANDLE hFileMap = NULL;\r\nHMODULE hInstance = NULL;\r\nSOCKET CurrentConnection = 0;\r\n\r\nHANDLE CommMutex = NULL;\r\n\r\nchar *tempBuff = NULL;\r\n\r\nSharedMemory *pShared = NULL;\r\n\r\nLARGE_INTEGER PerfFreq, Counter;\r\n\r\nHWND hUOAWnd = NULL;\r\n\r\nSIZE DesiredSize = {800,600};\r\n\r\nunsigned long OldRecv, OldSend, OldConnect, OldCloseSocket, OldSelect, OldCreateFileA;\r\nunsigned long RecvAddress, SendAddress, ConnectAddress, CloseSocketAddress, SelectAddress, CreateFileAAddress;\r\n\r\nbool Seeded = false;\r\nbool FirstRecv = true;\r\nbool FirstSend = true;\r\nbool LoginServer = false;\r\nbool Active = true;\r\nbool SmartCPU = false;\r\nbool ServerNegotiated = false;\r\nbool InGame = false;\r\nbool CopyFailed = true;\r\nbool Forwarding = false;\r\nbool Forwarded = false;\r\nbool ClientEncrypted = false;\r\nbool ServerEncrypted = false;\r\n\r\nenum CLIENT_TYPE { TWOD = 1, THREED = 2 };\r\nCLIENT_TYPE ClientType = TWOD;\r\n\r\n//**************************************OSI Only Stuff*********************************\r\nDWORD CryptSeed = 0x7f000001;\r\nOSIEncryption *ClientCrypt = NULL;\r\nOSIEncryption *ServerCrypt = NULL;\r\nLoginEncryption *ClientLogin = NULL;\r\nLoginEncryption *ServerLogin = NULL;\r\n//*************************************************************************************\r\n\r\n//*************************************************************************************\r\n//**************************************Functions**************************************\r\n//*************************************************************************************\r\nLRESULT CALLBACK WndProcRetHookFunc( int, WPARAM, LPARAM );\r\nLRESULT CALLBACK GetMsgHookFunc( int, WPARAM, LPARAM );\r\n\r\nbool HookFunction( const char *, const char *, int, unsigned long, unsigned long *, unsigned long * );\r\nvoid FlushSendData();\r\n\r\nbool CreateSharedMemory();\r\nvoid CloseSharedMemory();\r\n\r\n//Hooks:\r\nint HookRecv( SOCKET, char *, int, int );\r\nint HookSend( SOCKET, char *, int, int );\r\nint HookConnect( SOCKET, const sockaddr *, int );\r\nint HookCloseSocket( SOCKET );\r\nint HookSelect( int, fd_set*, fd_set*, fd_set*, const struct timeval * );\r\n\r\ntypedef int (*NetIOFunc)(SOCKET, char *, int, int);\r\ntypedef int (*ConnFunc)(SOCKET, const sockaddr *, int);\r\ntypedef int (*CLSFunc)(SOCKET);\r\ntypedef int (*SelectFunc)( int, fd_set*, fd_set*, fd_set*, const struct timeval* );\r\ntypedef HANDLE (*CreateFileAFunc)(LPCTSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);\r\ntypedef char *(__cdecl *GetUOVersionFunc)();\r\n\r\nGetUOVersionFunc NativeGetUOVersion = NULL;\r\n\r\nBOOL APIENTRY DllMain( HANDLE hModule, DWORD dwReason, LPVOID )\r\n{\r\n\tDWORD postID, thisID;\r\n\r\n\thInstance = (HMODULE)hModule;\r\n\tswitch (dwReason)\r\n\t{\r\n\tcase DLL_PROCESS_ATTACH:\r\n\t\tDisableThreadLibraryCalls( hInstance );\r\n\t\tQueryPerformanceFrequency( &PerfFreq );\r\n\t\tQueryPerformanceCounter( &Counter );\r\n\t\tbreak;\r\n\r\n\tcase DLL_PROCESS_DETACH:\r\n\t\tpostID = 0;\r\n\t\tthisID = GetCurrentProcessId();\r\n\t\tif ( IsWindow( hRazorWnd ) )\r\n\t\t\tGetWindowThreadProcessId( hRazorWnd, &postID );\r\n\r\n\t\tif ( thisID == postID || thisID == UOProcId )\r\n\t\t{\r\n\t\t\tif ( IsWindow( hRazorWnd ) )\r\n\t\t\t\tPostMessage( hRazorWnd, WM_UONETEVENT, CLOSE, 0 );\r\n\r\n\t\t\tif ( IsWindow( hUOWindow ) )\r\n\t\t\t{\r\n\t\t\t\tPostMessage( hUOWindow, WM_QUIT, 0, 0 );\r\n\t\t\t\tSetForegroundWindow( hUOWindow );\r\n\t\t\t\tSetFocus( hUOWindow );\r\n\t\t\t}\r\n\r\n\t\t\tCloseSharedMemory();\r\n\t\t}\r\n\t\tbreak;\r\n\r\n\tcase DLL_THREAD_ATTACH:\r\n\tcase DLL_THREAD_DETACH:\r\n\t\tbreak;\r\n\t}\r\n\r\n\treturn TRUE;\r\n}\r\n\r\nDLLFUNCTION void *GetSharedAddress()\r\n{\r\n\tLog( \"Get shared address [0x%x]\", pShared );\r\n\treturn pShared;\r\n}\r\n\r\nDLLFUNCTION HWND FindUOWindow( void )\r\n{\r\n\tif ( hUOWindow == NULL || !IsWindow(hUOWindow) )\r\n\t{\r\n\t\tHWND hWnd = FindWindow( \"Ultima Online\", NULL );\r\n\t\tif (hWnd == NULL)\r\n\t\t\thWnd = FindWindow( \"Ultima Online Third Dawn\", NULL );\r\n\t\treturn hWnd;\r\n\t}\r\n\telse\r\n\t{\r\n\t\treturn hUOWindow;\r\n\t}\r\n}\r\n\r\nDLLFUNCTION void SetDataPath( const char *path )\r\n{\r\n\tWaitForSingleObject( CommMutex, INFINITE );\r\n\tstrncpy( pShared->DataPath, path, MAX_PATH);\r\n\tReleaseMutex( CommMutex );\r\n}\r\n\r\nDLLFUNCTION int InstallLibrary( HWND PostWindow, DWORD pid, int flags )\r\n{\r\n\tDWORD UOTId = 0;\r\n\r\n\tLog( \"Initialize library...\" );\r\n\r\n\tHWND hWnd = NULL;\r\n\tif ( pid != 0 )\r\n\t{\r\n\t\thWnd = FindWindow( \"Ultima Online\", NULL );\r\n\t\twhile ( hWnd != NULL )\r\n\t\t{\r\n\t\t\tUOTId = GetWindowThreadProcessId( hWnd, &UOProcId );\r\n\t\t\tif ( UOProcId == pid )\r\n\t\t\t\tbreak;\r\n\t\t\thWnd = FindWindowEx( NULL, hWnd, \"Ultima Online\", NULL );\r\n\t\t}\r\n\r\n\t\tif ( UOProcId != pid || hWnd == NULL )\r\n\t\t{\r\n\t\t\thWnd = FindWindow( \"Ultima Online Third Dawn\", NULL );\r\n\t\t\twhile ( hWnd != NULL )\r\n\t\t\t{\r\n\t\t\t\tUOTId = GetWindowThreadProcessId( hWnd, &UOProcId );\r\n\t\t\t\tif (UOProcId == pid)\r\n\t\t\t\t\tbreak;\r\n\t\t\t\thWnd = FindWindowEx( NULL, hWnd, \"Ultima Online Third Dawn\", NULL );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif ( UOProcId != pid )\r\n\t\t\treturn NO_TID;\r\n\t}\r\n\telse\r\n\t{\r\n\t\thWnd = FindUOWindow();\r\n\t\tif ( hWnd != NULL )\r\n\t\t\tUOTId = GetWindowThreadProcessId( hWnd, &UOProcId );\r\n\t}\r\n\r\n\thUOWindow = hWnd;\r\n\thRazorWnd = PostWindow;\r\n\r\n\tif ( hUOWindow == NULL )\r\n\t\treturn NO_UOWND;\r\n\r\n\tif ( !UOTId || !UOProcId )\r\n\t\treturn NO_TID;\r\n\r\n\tif ( !CreateSharedMemory() )\r\n\t\treturn NO_SHAREMEM;\r\n\r\n\tpShared->Reserved0 = false;\r\n\r\n\thWndProcRetHook = SetWindowsHookEx( WH_CALLWNDPROCRET, WndProcRetHookFunc, hInstance, UOTId );\r\n\tif ( !hWndProcRetHook )\r\n\t\treturn NO_HOOK;\r\n\r\n\thGetMsgHook = SetWindowsHookEx( WH_GETMESSAGE, GetMsgHookFunc, hInstance, UOTId );\r\n\tif ( !hGetMsgHook )\r\n\t\treturn NO_HOOK;\r\n\r\n\tWNDCLASS wc;\r\n\twc.style = 0;\r\n\twc.lpfnWndProc = (WNDPROC)UOAWndProc;\r\n\twc.cbClsExtra = 0;\r\n\twc.cbWndExtra = 0;\r\n\twc.hInstance = hInstance;\r\n\twc.hIcon = LoadIcon(NULL, IDI_WINLOGO);\r\n\twc.hCursor = LoadCursor(NULL, IDC_ARROW);\r\n\twc.hbrBackground = NULL;\r\n\twc.lpszMenuName = NULL;\r\n\twc.lpszClassName = \"UOASSIST-TP-MSG-WND\";\r\n\tRegisterClass(&wc);\r\n\tDWORD error = GetLastError();\r\n\r\n\thUOAWnd = CreateWindow(\"UOASSIST-TP-MSG-WND\", \"UOASSIST-TP-MSG-WND\", WS_OVERLAPPEDWINDOW, 0, 0, 50, 50, NULL, NULL, hInstance, 0);\r\n\tif (hUOAWnd)\r\n\t\tShowWindow(hUOAWnd, FALSE);\r\n\r\n\tServerEncrypted = (flags&0x10) != 0;\r\n\tClientEncrypted = (flags&0x08) != 0;\r\n\r\n\tPostMessage( hUOWindow, WM_PROCREADY, (WPARAM)flags, (LPARAM)hRazorWnd );\r\n\treturn SUCCESS;\r\n}\r\n\r\nDLLFUNCTION void WaitForWindow( DWORD pid )\r\n{\r\n\tDWORD UOTId = 0;\r\n\tDWORD exitCode;\r\n\tHANDLE hProc = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid );\r\n\r\n\tUOProcId = 0;\r\n\r\n\tdo\r\n\t{\r\n\t\tSleep( 10 );\r\n\t\tHWND hWnd = FindWindow( \"Ultima Online\", NULL );\r\n\t\twhile ( hWnd != NULL )\r\n\t\t{\r\n\t\t\tUOTId = GetWindowThreadProcessId( hWnd, &UOProcId );\r\n\t\t\tif ( UOProcId == pid )\r\n\t\t\t\tbreak;\r\n\t\t\thWnd = FindWindowEx( NULL, hWnd, \"Ultima Online\", NULL );\r\n\t\t}\r\n\r\n\t\tif ( UOProcId != pid || hWnd == NULL )\r\n\t\t{\r\n\t\t\thWnd = FindWindow( \"Ultima Online Third Dawn\", NULL );\r\n\t\t\twhile ( hWnd != NULL )\r\n\t\t\t{\r\n\t\t\t\tUOTId = GetWindowThreadProcessId( hWnd, &UOProcId );\r\n\t\t\t\tif (UOProcId == pid)\r\n\t\t\t\t\tbreak;\r\n\t\t\t\thWnd = FindWindowEx( NULL, hWnd, \"Ultima Online Third Dawn\", NULL );\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tGetExitCodeProcess( hProc, &exitCode );\r\n\t} while ( UOProcId != pid && exitCode == STILL_ACTIVE );\r\n\r\n\tCloseHandle( hProc );\r\n}\r\n\r\nDLLFUNCTION void Shutdown( bool close )\r\n{\r\n\tLog( \"Shutdown\" );\r\n\r\n\tif (hUOAWnd && IsWindow(hUOAWnd))\r\n\t{\r\n\t\tUnregisterClass(\"UOASSIST-TP-MSG-WND\", hInstance);\r\n\t\tSendMessage(hUOAWnd, WM_CLOSE, 0, 0);\r\n\t\thUOAWnd = NULL;\r\n\t}\r\n\r\n\tif ( hUOWindow && IsWindow( hUOWindow ) )\r\n\t\tPostMessage( hUOWindow, WM_QUIT, 0, 0 );\r\n}\r\n\r\nDLLFUNCTION int GetUOProcId()\r\n{\r\n\treturn UOProcId;\r\n}\r\n\r\nDLLFUNCTION HANDLE GetCommMutex()\r\n{\r\n\treturn CommMutex;\r\n}\r\n\r\n// totalsend and totalrecv are NOT mutex sync'd\r\nDLLFUNCTION unsigned int TotalOut()\r\n{\r\n\tif ( pShared )\r\n\t\treturn pShared->TotalSend;\r\n\telse\r\n\t\treturn 0;\r\n}\r\n\r\nDLLFUNCTION unsigned int TotalIn()\r\n{\r\n\tif ( pShared )\r\n\t\treturn pShared->TotalRecv;\r\n\telse\r\n\t\treturn 0;\r\n}\r\n\r\nDLLFUNCTION void CalibratePosition( uint16_t x, uint16_t y, uint16_t z )\r\n{\r\n\tPosition pos;\r\n\tCOPYDATASTRUCT copydata;\r\n\r\n\tpos.x = x;\r\n\tpos.y = y;\r\n\tpos.z = z;\r\n\r\n\tcopydata.dwData = (ULONG_PTR)UONET_MESSAGE_COPYDATA::POSITION;\r\n\tcopydata.cbData = sizeof(pos);\r\n\tcopydata.lpData = &pos;\r\n\r\n\tSendMessage(hUOWindow, WM_COPYDATA, (WPARAM)hRazorWnd, (LPARAM)&copydata);\r\n}\r\n\r\n/* These variables are used in the UO client process address space */\r\n\r\n/* 7.0.15.1 Client, Modified for Outlands\r\n   Located at 0x00A72BD8 */\r\n#pragma pack(1)\r\nstruct PositionOutlands {\r\n\tuint16_t x;\r\n\tuint16_t y;\r\n\tuint16_t z;\r\n};\r\nstatic_assert(sizeof(struct PositionOutlands) == 6, \"Incorrect size\\n\");\r\n\r\n/* 5.0.8.3 Client, UO Renaissance\r\n   Located at address 0x007D7C58 */\r\n#pragma pack(1)\r\nstruct PositionUOR {\r\n\tuint32_t z;\r\n\tuint32_t y;\r\n\tuint32_t x;\r\n};\r\nstatic_assert(sizeof(struct PositionUOR) == 12, \"Incorrect size\\n\");\r\n// UOR client this is at 0x007D7C60 (x is)\r\n\r\n// Fall back search. Not always reliable.\r\n#pragma pack(1)\r\nstruct PositionGeneric {\r\n\tuint32_t z;\r\n\tuint32_t y;\r\n\tuint32_t x;\r\n};\r\nstatic_assert(sizeof(struct PositionGeneric) == 12, \"Incorrect size\\n\");\r\n\r\nPosition g_TestPosition = {};\r\nPosition g_LastPosition = {};\r\nvoid *g_ClientMem = nullptr;\r\n\r\nstatic void CheckPosition()\r\n{\r\n\tif (g_ClientMem == nullptr) {\r\n\t\tif (strncmp(pShared->UOVersion, \"5.0.8.3\", sizeof(pShared->UOVersion)) == 0) {\r\n\t\t\t/* On UOR, we know exactly where the position is. */\r\n\t\t\tg_ClientMem = (void *)(0x007D7C60);\r\n\t\t}\r\n\t\telse if (strncmp(pShared->UOVersion, \"7.0.15.1\", sizeof(pShared->UOVersion)) == 0) {\r\n\t\t\t/* Similarly on Outlands, we know where the position is. */\r\n\t\t\tg_ClientMem = (void *)(0x00A72BD8);\r\n\t\t} else {\r\n\t\t\t/* Scan the region of memory in the client known to hold the player's position */\r\n\t\t\tfor (uintptr_t addr = 0x00500000; addr < 0x00C00000; addr += 2)\r\n\t\t\t{\r\n\t\t\t\tif (IsBadReadPtr((void*)addr, sizeof(PositionGeneric))) {\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tPositionGeneric* mem = (PositionGeneric*)addr;\r\n\r\n\t\t\t\tif (mem->x == g_TestPosition.x && mem->y == g_TestPosition.y && mem->z == g_TestPosition.z) {\r\n\t\t\t\t\tg_ClientMem = mem;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (g_ClientMem != nullptr) {\r\n\t\tPosition pos;\r\n\t\tif (strncmp(pShared->UOVersion, \"5.0.8.3\", sizeof(pShared->UOVersion)) == 0) {\r\n\t\t\tPositionUOR *mem = (PositionUOR*)g_ClientMem;\r\n\t\t\tpos.x = mem->x;\r\n\t\t\tpos.y = mem->y;\r\n\t\t\tpos.z = mem->z;\r\n\t\t} else if (strncmp(pShared->UOVersion, \"7.0.15.1\", sizeof(pShared->UOVersion)) == 0) {\r\n\t\t\t/* Similarly on Outlands, we know where the position is. */\r\n\t\t\tPositionOutlands *mem = (PositionOutlands*)g_ClientMem;\r\n\t\t\tpos.x = mem->x;\r\n\t\t\tpos.y = mem->y;\r\n\t\t\tpos.z = mem->z;\r\n\t\t} else {\r\n\t\t\tPositionGeneric *mem = (PositionGeneric*)g_ClientMem;\r\n\t\t\tpos.x = mem->x;\r\n\t\t\tpos.y = mem->y;\r\n\t\t\tpos.z = mem->z;\r\n\t\t}\r\n\r\n\t\tif (pos.x != g_LastPosition.x || pos.y != g_LastPosition.y || pos.z != g_LastPosition.z) {\r\n\t\t\t/* Inform Razor of a position change */\r\n\r\n\t\t\tCOPYDATASTRUCT copydata;\r\n\r\n\t\t\tcopydata.dwData = (ULONG_PTR)UONET_MESSAGE_COPYDATA::POSITION;\r\n\t\t\tcopydata.cbData = sizeof(pos);\r\n\t\t\tcopydata.lpData = &pos;\r\n\r\n\t\t\tSendMessage(hRazorWnd, WM_COPYDATA, (WPARAM)hUOWindow, (LPARAM)&copydata);\r\n\t\t}\r\n\r\n\t\tg_LastPosition = pos;\r\n\t}\r\n}\r\n\r\nVOID CALLBACK OnTick(HWND hwnd, UINT Message, UINT TimerId, DWORD dwTime) {\r\n\t/* Scan client memory for position updates */\r\n\tCheckPosition();\r\n\r\n\t/* Post a message to Razor to indicate a game loop tick.*/\r\n\tPostMessage(hRazorWnd, WM_UONETEVENT, ON_TICK, 0);\r\n}\r\n\r\nSIZE *SizePtr = NULL;\r\nvoid OnSetUOWindowSize( int width )\r\n{\r\n\tif ( width != 800 && width != 600 ) // in case it actually the height for some reason\r\n\t{\r\n\t\tSizePtr->cx = 640;\r\n\t\tSizePtr->cy = 480;\r\n\t}\r\n\telse\r\n\t{\r\n\t\t*SizePtr = DesiredSize;\r\n\t}\r\n}\r\n\r\nDLLFUNCTION void OnAttach( void *params, int paramsLen )\r\n{\r\n\tint count = 0;\r\n\tDWORD addr = 0, oldProt;\r\n\tMemFinder mf;\r\n\r\n\tUOProcId = GetCurrentProcessId();\r\n\r\n\tif ( !CreateSharedMemory() )\r\n\t\treturn;\r\n\r\n\t\tCopyFailed = false;\r\n\t\tmf.AddEntry(\"UoClientApp\", 12, 0x00500000);\r\n\t\tmf.AddEntry(\"report\\0\", 8, 0x00500000);\r\n\t\tmf.AddEntry(\"Another copy of \", 16, 0x00500000);\r\n\t\tmf.AddEntry(\"\\x00\\x68\\x88\\x13\\x00\\x00\\x56\\xE8\", 8);\r\n\t\tmf.AddEntry(\"\\x68\\x88\\x13\\x00\\x00\", 5, 16, 0x00400000); // (end of a push offset), push 5000, push esi\r\n\t\tmf.AddEntry(\"Electronic Arts Inc.\", 20);\r\n\t\tmf.AddEntry(\"intro.bik\", 10);\r\n\t\tmf.AddEntry(\"osilogo.bik\", 12);\r\n\t\tmf.AddEntry(\"\\x80\\x02\\x00\\x00\\xE0\\x01\\x00\\x00\", 8, 0x00500000); // current screen size\r\n\t\tmf.AddEntry(\"\\x8B\\x44\\x24\\x04\\xBA\\x80\\x02\\x00\\x00\\x3B\\xC2\\xB9\\xE0\\x01\\x00\\x00\", 16); // resize screen function\r\n\t\tmf.AddEntry(\"\\x57\\x56\\x6A\\x00\\x6A\\x00\\xE8\", 7); // redraw screen/edge function\r\n\t\tmf.AddEntry(PACKET_TBL_STR, PACKET_TS_LEN, 10, 0x00500000);\r\n\t\tmf.AddEntry(CRYPT_KEY_STR, CRYPT_KEY_LEN);\r\n\t\tmf.AddEntry(CRYPT_KEY_STR_3D, CRYPT_KEY_3D_LEN);\r\n\t\tmf.AddEntry(CRYPT_KEY_STR_NEW, CRYPT_KEY_NEW_LEN);\r\n\t\tmf.AddEntry(CRYPT_KEY_STR_MORE_NEW, CRYPT_KEY_MORE_NEW_LEN);\r\n\t\tmf.AddEntry(\"UO Version %s\", 12);\r\n\t\tmf.AddEntry(\"Multiple Instances Running\", 26, 0x00500000);\r\n\r\n\t\tmemcpy( pShared->PacketTable, StaticPacketTable, 256*sizeof(short) );\r\n\r\n\t\tmf.Execute();\r\n\r\n\t\tSizePtr = (SIZE*)mf.GetAddress(\"\\x80\\x02\\x00\\x00\\xE0\\x01\\x00\\x00\", 8);\r\n\t\tif (SizePtr)\r\n\t\t{\r\n\t\t\taddr = mf.GetAddress(\"\\x8B\\x44\\x24\\x04\\xBA\\x80\\x02\\x00\\x00\\x3B\\xC2\\xB9\\xE0\\x01\\x00\\x00\", 16);\r\n\t\t\tif (addr)\r\n\t\t\t{\r\n\t\t\t\tint i;\r\n\t\t\t\tDWORD origAddr = addr;\r\n\r\n\t\t\t\tVirtualProtect((void*)origAddr, 128, PAGE_EXECUTE_READWRITE, &oldProt);\r\n\t\t\t\tfor (i = 16; i < 128; i++)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (*((BYTE*)(addr + i)) == 0xE9) // find the first jmp\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemset((void*)addr, 0x90, i); // nop\r\n\r\n\t\t\t\t\t\t// mov eax, dword [esp+4]\r\n\t\t\t\t\t\t*((BYTE*)(addr + 0)) = 0x8B; // mov\r\n\t\t\t\t\t\t*((BYTE*)(addr + 1)) = 0x44; //  eax\r\n\t\t\t\t\t\t*((BYTE*)(addr + 2)) = 0x24; //  [esp\r\n\t\t\t\t\t\t*((BYTE*)(addr + 3)) = 0x04; //      +4]\r\n\t\t\t\t\t\taddr += 4;\r\n\r\n\t\t\t\t\t\t*((BYTE*)addr) = 0x50; // push eax\r\n\t\t\t\t\t\taddr++;\r\n\t\t\t\t\t\t// call OnSetUOWindowSize\r\n\t\t\t\t\t\t*((BYTE*)addr) = 0xE8;\r\n\t\t\t\t\t\t*((DWORD*)(addr + 1)) = ((DWORD)OnSetUOWindowSize) - (addr + 5);\r\n\t\t\t\t\t\taddr += 5;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tVirtualProtect((void*)origAddr, 128, oldProt, &oldProt);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tint i = 0;\r\n\t\twhile ((addr = mf.GetAddress(PACKET_TBL_STR, PACKET_TS_LEN, i++)) != 0)\r\n\t\t{\r\n\t\t\tmemset(pShared->PacketTable, 0xFF, 512);\r\n\r\n\t\t\taddr += PACKET_TBL_OFFSET;\r\n\t\t\tif (IsBadReadPtr((void*)addr, sizeof(ClientPacketInfo) * 128))\r\n\t\t\t\tcontinue;\r\n\t\t\tClientPacketInfo *tbl = (ClientPacketInfo*)addr;\r\n\r\n\t\t\tif (tbl[0].Id == 1 || tbl[0].Id == 2 || tbl[0].Id >= 256)\r\n\t\t\t\tcontinue;\r\n\r\n\t\t\t// this one isnt in order because OSI are idiots (0xF8)\r\n\t\t\tpShared->PacketTable[tbl[0].Id] = tbl[0].Length;\r\n\r\n\t\t\tint idx = 1;\r\n\t\t\tbool got1 = false, got2 = false;\r\n\t\t\tfor (int prev = 0; prev < 255 && idx < 256; idx++)\r\n\t\t\t{\r\n\t\t\t\tif (IsBadReadPtr((void*)(tbl + idx), sizeof(ClientPacketInfo)) ||\r\n\t\t\t\t\ttbl[idx].Id <= prev || tbl[idx].Id >= 256)\r\n\t\t\t\t{\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgot1 |= tbl[idx].Id == 1 && tbl[idx].Length == StaticPacketTable[1];\r\n\t\t\t\tgot2 |= tbl[idx].Id == 2 && tbl[idx].Length == StaticPacketTable[2];\r\n\r\n\t\t\t\tprev = tbl[idx].Id;\r\n\t\t\t\tif (pShared->PacketTable[prev] == 0xFFFF)\r\n\t\t\t\t\tpShared->PacketTable[prev] = tbl[idx].Length;\r\n\t\t\t}\r\n\r\n\t\t\tif (idx < 128 || !got1 || !got2)\r\n\t\t\t\tcontinue;\r\n\t\t\telse\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tif (!addr)\r\n\t\t\tCopyFailed = true;\r\n\r\n\t\taddr = mf.GetAddress(CRYPT_KEY_STR, CRYPT_KEY_LEN);\r\n\t\tif (!addr)\r\n\t\t{\r\n\t\t\taddr = mf.GetAddress(CRYPT_KEY_STR_NEW, CRYPT_KEY_NEW_LEN);\r\n\r\n\t\t\tif (!addr)\r\n\t\t\t{\r\n\t\t\t\taddr = mf.GetAddress(CRYPT_KEY_STR_MORE_NEW, CRYPT_KEY_MORE_NEW_LEN);\r\n\t\t\t\tif (!addr)\r\n\t\t\t\t{\r\n\t\t\t\t\taddr = mf.GetAddress(CRYPT_KEY_STR_3D, CRYPT_KEY_3D_LEN);\r\n\t\t\t\t\tif (addr)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tLoginEncryption::SetKeys((const DWORD*)(addr + CRYPT_KEY_3D_LEN), (const DWORD*)(addr + CRYPT_KEY_3D_LEN + 19));\r\n\t\t\t\t\t\tClientType = THREED;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\tCopyFailed = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\taddr += CRYPT_KEY_MORE_NEW_LEN;\r\n\r\n\t\t\t\t\tconst DWORD *pKey1 = *((DWORD**)addr);\r\n\t\t\t\t\tconst DWORD *pKey2 = pKey1 + 1;\r\n\t\t\t\t\tif (IsBadReadPtr(pKey2, 4) || IsBadReadPtr(pKey1, 4))\r\n\t\t\t\t\t\tCopyFailed = true;\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\tLoginEncryption::SetKeys(pKey1, pKey2);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\taddr += CRYPT_KEY_NEW_LEN;\r\n\r\n\t\t\t\tconst DWORD *pKey1 = *((DWORD**)addr);\r\n\t\t\t\tconst DWORD *pKey2 = pKey1 - 1;\r\n\t\t\t\tif (IsBadReadPtr(pKey2, 4) || IsBadReadPtr(pKey1, 4))\r\n\t\t\t\t\tCopyFailed = true;\r\n\t\t\t\telse\r\n\t\t\t\t\tLoginEncryption::SetKeys(pKey1, pKey2);\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tLoginEncryption::SetKeys((const DWORD*)(addr + CRYPT_KEY_LEN), (const DWORD*)(addr + CRYPT_KEY_LEN + 6));\r\n\t\t}\r\n\r\n\t\t// Multi UO\r\n\t\taddr = mf.GetAddress(\"UoClientApp\", 12);\r\n\t\tif (addr)\r\n\t\t{\r\n\t\t\tVirtualProtect((void*)addr, 12, PAGE_READWRITE, &oldProt);\r\n\t\t\t_snprintf((char*)addr, 12, \"UoApp%d\", UOProcId);\r\n\t\t\tVirtualProtect((void*)addr, 12, oldProt, &oldProt);\r\n\t\t}\r\n\r\n\t\taddr = mf.GetAddress(\"Another copy of \", 16);\r\n\t\tif (addr)\r\n\t\t{\r\n\t\t\tchar buff[5];\r\n\r\n\t\t\tbuff[0] = 0x68; // push\r\n\t\t\t*((DWORD*)(&buff[1])) = addr;\r\n\r\n\t\t\taddr = 0x00400000;\r\n\t\t\tdo {\r\n\t\t\t\taddr = MemFinder::Find(buff, 5, addr, 0x00600000);\r\n\t\t\t\tif (addr)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((*((unsigned char*)(addr - 5))) == 0x74) // jz?\r\n\t\t\t\t\t\tMemoryPatch(addr - 5, 0xEB, 1); // change to jmp\r\n\t\t\t\t\taddr += 5; // skip ahead to find the next instance\r\n\t\t\t\t}\r\n\t\t\t} while (addr > 0 && addr < 0x00600000);\r\n\t\t}\r\n\r\n\t\taddr = mf.GetAddress(\"Multiple Instances Running\", 26);\r\n\t\tif (addr)\r\n\t\t{\r\n\t\t\tchar buff[5];\r\n\r\n\t\t\tbuff[0] = 0x68; // push\r\n\t\t\t*((DWORD*)(&buff[1])) = addr;\r\n\r\n\t\t\taddr = 0x00400000;\r\n\t\t\tdo {\r\n\t\t\t\taddr = MemFinder::Find(buff, 5, addr, 0x00600000);\r\n\t\t\t\tif (addr)\r\n\t\t\t\t{\r\n\t\t\t\t\tchar in = (*((unsigned char*)(addr - 4)));\r\n\t\t\t\t\tif (in == 0x74 || in == 0x75) { // jz or jnz\r\n\t\t\t\t\t\tMemoryPatch(addr - 4, 0xEB, 1); // change to jmp\r\n\t\t\t\t\t}\r\n\t\t\t\t\taddr += 5; // skip ahead to find the next instance\r\n\t\t\t\t}\r\n\t\t\t} while (addr > 0 && addr < 0x00600000);\r\n\t\t}\r\n\r\n\t\taddr = mf.GetAddress(\"report\\0\", 8);\r\n\t\tif (addr)\r\n\t\t{\r\n\t\t\tVirtualProtect((void*)addr, 12, PAGE_READWRITE, &oldProt);\r\n\t\t\t_snprintf((char*)addr, 8, \"r%d\", UOProcId);\r\n\t\t\tVirtualProtect((void*)addr, 12, oldProt, &oldProt);\r\n\t\t}\r\n\r\n\t\t// Splash screen crap:\r\n\t\tfor (int i = 0; i < 16; i++)\r\n\t\t{\r\n\t\t\taddr = mf.GetAddress(\"\\x68\\x88\\x13\\x00\\x00\", 5, i);\r\n\t\t\tif (!addr)\r\n\t\t\t\tbreak;\r\n\t\t\tfor (int e = 5; e < 24; e++)\r\n\t\t\t{\r\n\t\t\t\tif (*((BYTE*)(addr + e)) == 0x8B && *((BYTE*)(addr + e + 1)) == 0x3D)\r\n\t\t\t\t{\r\n\t\t\t\t\tMemoryPatch(addr + 1, 0x00000001); // change 5000ms to 1ms\r\n\t\t\t\t\ti = 99;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\taddr = mf.GetAddress(\"intro.bik\", 10);\r\n\t\tif (addr)\r\n\t\t\tMemoryPatch(addr, \"intro.SUX\", 10);\r\n\t\taddr = mf.GetAddress(\"ostlogo.bik\", 12);\r\n\t\tif (addr)\r\n\t\t\tMemoryPatch(addr, \"osilogo.SUX\", 12);\r\n\r\n\t\taddr = mf.GetAddress(\"Electronic Arts Inc.\", 20);\r\n\t\tif (addr)\r\n\t\t{\r\n\t\t\taddr -= 7;\r\n\t\t\tVirtualProtect((void*)addr, 52, PAGE_EXECUTE_READWRITE, &oldProt);\r\n\t\t\tstrncpy((char*)addr, \"[Powered by Razor - The cutting edge UO Assistant]\\0\", 52);\r\n\t\t\tVirtualProtect((void*)addr, 52, oldProt, &oldProt);\r\n\t\t}\r\n\r\n\t\tNativeGetUOVersion = NULL;\r\n\t\tif (ClientType == TWOD)\r\n\t\t{\r\n\t\t\taddr = mf.GetAddress(\"UO Version %s\", 12);\r\n\t\t\tif (addr)\r\n\t\t\t{\r\n\t\t\t\tchar temp[8];\r\n\t\t\t\ttemp[0] = 0x68;\r\n\t\t\t\t*((DWORD*)&temp[1]) = addr;\r\n\r\n\t\t\t\taddr = MemFinder::Find(temp, 5);\r\n\r\n\t\t\t\tif (addr)\r\n\t\t\t\t{\r\n\t\t\t\t\tcount = 0;\r\n\t\t\t\t\twhile (*((BYTE*)addr) != 0xE8 && count < 128)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\taddr--;\r\n\t\t\t\t\t\tcount++;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (*((BYTE*)addr) == 0xE8)\r\n\t\t\t\t\t\tNativeGetUOVersion = (GetUOVersionFunc)((addr + 5) + *((DWORD*)(addr + 1)));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n}\r\n\r\nDLLFUNCTION void SetServer( unsigned int addr, unsigned short port )\r\n{\r\n\tif (pShared)\r\n\t{\r\n\t\tpShared->ServerIP = addr;\r\n\t\tpShared->ServerPort = port;\r\n\t}\r\n}\r\n\r\nDLLFUNCTION const char *GetUOVersion()\r\n{\r\n\tif ( pShared )\r\n\t\treturn pShared->UOVersion;\r\n\telse\r\n\t\treturn \"\";\r\n}\r\n\r\nbool CreateSharedMemory()\r\n{\r\n\tif (pShared)\r\n\t\treturn true;\r\n\r\n\tchar name[256];\r\n\r\n\tCommMutex = NULL;\r\n\thFileMap = NULL;\r\n\tpShared = NULL;\r\n\r\n\tLog( \"Creating shared mem, proc: %x\", UOProcId );\r\n\r\n\tsprintf( name, \"UONetSharedCOMM_%x\", UOProcId );\r\n\r\n\tCommMutex = CreateMutex( NULL, FALSE, name );\r\n\tif ( !CommMutex )\r\n\t\treturn false;\r\n\r\n\tfor (int i = 0; i < 30; i++) {\r\n\t\tsprintf(name, \"UONetSharedFM_%x%d\", UOProcId, i);\r\n\t\thFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(SharedMemory), name);\r\n\t\tif (!hFileMap || hFileMap == INVALID_HANDLE_VALUE) {\r\n\t\t\tauto err = GetLastError();\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tpShared = (SharedMemory*)MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(SharedMemory));\r\n\t\tif (!pShared) {\r\n\t\t\tauto err = GetLastError();\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tbreak;\r\n\t}\r\n\r\n\tif (!pShared) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\t//memset( pShared, 0, sizeof(SharedMemory) );\r\n\r\n\treturn true;\r\n}\r\n\r\nvoid CloseSharedMemory()\r\n{\r\n\tLog( \"Close shared memory\" );\r\n\r\n\tif ( hWndProcRetHook )\r\n\t\tUnhookWindowsHookEx( hWndProcRetHook );\r\n\tif ( hGetMsgHook )\r\n\t\tUnhookWindowsHookEx( hGetMsgHook );\r\n\r\n\tif ( CommMutex )\r\n\t\tCloseHandle( CommMutex );\r\n\tCommMutex = NULL;\r\n\tif ( pShared )\r\n\t\tUnmapViewOfFile( pShared );\r\n\tpShared = NULL;\r\n\tif ( hFileMap )\r\n\t\tCloseHandle( hFileMap );\r\n\thFileMap = NULL;\r\n\r\n\t//these are shared vars\r\n\thWndProcRetHook = NULL;\r\n\thGetMsgHook = NULL;\r\n\r\n\tFreeArt();\r\n\r\n\tdelete ClientCrypt;\r\n\tdelete ClientLogin;\r\n\tdelete ServerCrypt;\r\n\tdelete ServerLogin;\r\n\r\n\tClientCrypt = NULL;\r\n\tClientLogin = NULL;\r\n\tServerCrypt = NULL;\r\n\tServerLogin = NULL;\r\n}\r\n\r\nvoid CreateEncryption()\r\n{\r\n\tdelete ClientCrypt;\r\n\tdelete ClientLogin;\r\n\tdelete ServerCrypt;\r\n\tdelete ServerLogin;\r\n\r\n\tif ( ClientEncrypted )\r\n\t{\r\n\t\tClientCrypt = new OSIEncryption();\r\n\t\tClientLogin = new LoginEncryption();\r\n\t}\r\n\r\n\tif ( ServerEncrypted )\r\n\t{\r\n\t\tServerCrypt = new OSIEncryption();\r\n\t\tServerLogin = new LoginEncryption();\r\n\t}\r\n}\r\n\r\ninline void Maintenance( Buffer &buff )\r\n{\r\n\tif ( buff.Length <= 0 )\r\n\t{\r\n\t\tbuff.Start = 0;\r\n\t\tbuff.Length = 0;\r\n\t}\r\n\telse if ( buff.Start > SHARED_BUFF_SIZE / 2 )\r\n\t{\r\n\t\t//shift all the data to the begining of the buffer\r\n\t\tmemmove( buff.Buff, &buff.Buff[buff.Start], buff.Length );\r\n\t\tbuff.Start = 0;\r\n\t}\r\n}\r\n\r\nint RecvData()\r\n{\r\n\tint len = SHARED_BUFF_SIZE;\r\n\tchar buff[SHARED_BUFF_SIZE];\r\n\r\n\tint ackLen = (*(NetIOFunc)OldRecv)(CurrentConnection,buff,len,0);\r\n\r\n\tif ( ackLen == SOCKET_ERROR )\r\n\t{\r\n\t\tif ( WSAGetLastError() != WSAEWOULDBLOCK )\r\n\t\t{\r\n\t\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\t\t\tpShared->ForceDisconn = true;\r\n\t\t\tReleaseMutex( CommMutex );\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tWSASetLastError( WSAEWOULDBLOCK );\r\n\t\t}\r\n\r\n\t\tackLen = -1;\r\n\t}\r\n\telse if ( ackLen > 0 )\r\n\t{\r\n\t\tif ( FirstRecv )\r\n\t\t{\r\n\t\t\tCompression::Reset();\r\n\t\t\tFirstRecv = false;\r\n\t\t}\r\n\r\n\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\r\n\t\tpShared->TotalRecv += ackLen;\r\n\r\n\t\tif ( LoginServer )\r\n\t\t{\r\n\t\t\tmemcpy( &pShared->InRecv.Buff[pShared->InRecv.Start+pShared->InRecv.Length], buff, ackLen );\r\n\t\t\tpShared->InRecv.Length += ackLen;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tif ( ServerEncrypted )\r\n\t\t\t\tServerCrypt->DecryptFromServer( (BYTE*)buff, (BYTE*)buff, ackLen );\r\n\r\n\t\t\tint blen = Compression::Decompress( (char*)&pShared->InRecv.Buff[pShared->InRecv.Start+pShared->InRecv.Length], buff, ackLen );\r\n\t\t\tpShared->InRecv.Length += blen;\r\n\r\n\t\t\tif ( !ServerNegotiated && !InGame && pShared && pShared->AllowNegotiate )\r\n\t\t\t{\r\n\t\t\t\tint pos = pShared->InRecv.Start;\r\n\t\t\t\tunsigned char *p_buff = &pShared->InRecv.Buff[pos];\r\n\r\n\t\t\t\twhile ( pos < pShared->InRecv.Length )\r\n\t\t\t\t{\r\n\t\t\t\t\tint left = pShared->InRecv.Length - pos;\r\n\t\t\t\t\tint p_len = GetPacketLength( p_buff, left );\r\n\r\n\t\t\t\t\tif ( *p_buff == 0xA9 && p_len >= 1+2+1+30+30 && p_len <= left )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t// character list\r\n\r\n\t\t\t\t\t\tunsigned char hash[16], test[16];\r\n\r\n\t\t\t\t\t\tmemcpy( pShared->AuthBits, p_buff + 1+2+1+30+1, 8 );\r\n\r\n\t\t\t\t\t\tif ( p_buff[3] > 1 )\r\n\t\t\t\t\t\t\tmemcpy( hash, p_buff + 1+2+1+30+30+30+1, 16 );\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\tmemcpy( hash, p_buff + 1+2+1+30+1+8, 16 );\r\n\r\n\t\t\t\t\t\tfor ( int i = 0; i < p_buff[3]; i++ )\r\n\t\t\t\t\t\t\tmemset( p_buff + 1+2+1+ 30 + 60*i, 0, 30 );\r\n\r\n\t\t\t\t\t\tif ( memcmp( hash, \"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16 ) != 0 )\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tOSIEncryption::MD5( p_buff, p_len, test );\r\n\r\n\t\t\t\t\t\t\tServerNegotiated = memcmp( hash, test, 16 ) == 0;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif ( !ServerNegotiated )\r\n\t\t\t\t\t\t\tmemset( pShared->AuthBits, 0, 8 );\r\n\r\n\t\t\t\t\t\tForwarding = Forwarded = false;\r\n\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif ( p_len <= 0 )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tpos += p_len;\r\n\t\t\t\t\t\tp_buff += p_len;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tReleaseMutex( CommMutex );\r\n\r\n\t\tSendMessage( hRazorWnd, WM_UONETEVENT, RECV, 0 );\r\n\t}\r\n\r\n\treturn ackLen;\r\n}\r\n\r\nint HookRecv( SOCKET sock, char *buff, int len, int flags )\r\n{\r\n\tint ackLen;\r\n\r\n\tif ( sock == CurrentConnection && CurrentConnection )\r\n\t{\r\n\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\t\tif ( pShared->ForceDisconn && pShared->OutRecv.Length <= 0 )\r\n\t\t{\r\n\t\t\tReleaseMutex( CommMutex );\r\n\t\t\tWSASetLastError( WSAECONNRESET );\r\n\t\t\treturn -1;\r\n\t\t}\r\n\r\n\t\tif ( LoginServer )\r\n\t\t{\r\n\t\t\tif ( pShared->OutRecv.Length > 0 )\r\n\t\t\t{\r\n\t\t\t\tackLen = pShared->OutRecv.Length;\r\n\t\t\t\tmemcpy( buff, &pShared->OutRecv.Buff[pShared->OutRecv.Start], ackLen );\r\n\r\n\t\t\t\tif ( ((BYTE)buff[0]) == 0x8C )\r\n\t\t\t\t\tLoginServer = false;\r\n\r\n\t\t\t\tif ( Forwarding )\r\n\t\t\t\t\tSeeded = Forwarded = true;\r\n\r\n\t\t\t\tpShared->OutRecv.Start += ackLen;\r\n\t\t\t\tpShared->OutRecv.Length -= ackLen;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tackLen = 0;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tackLen = 0;\r\n\t\t\twhile ( pShared->OutRecv.Length > 0 )\r\n\t\t\t{\r\n\t\t\t\tint blen = GetPacketLength( &pShared->OutRecv.Buff[pShared->OutRecv.Start], pShared->OutRecv.Length );\r\n\r\n\t\t\t\tif ( blen <= 0 || blen > pShared->OutRecv.Length || ackLen+blen > len )\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tackLen += Compression::Compress( &buff[ackLen], (char*)&pShared->OutRecv.Buff[pShared->OutRecv.Start], blen );\r\n\r\n\t\t\t\tpShared->OutRecv.Start += blen;\r\n\t\t\t\tpShared->OutRecv.Length -= blen;\r\n\t\t\t}\r\n\r\n\t\t\tif ( ClientEncrypted && ackLen > 0 )\r\n\t\t\t\tClientCrypt->EncryptForClient( (BYTE*)buff, (BYTE*)buff, ackLen );\r\n\t\t}\r\n\r\n\t\tMaintenance( pShared->InRecv );\r\n\t\tMaintenance( pShared->OutRecv );\r\n\r\n\t\tReleaseMutex( CommMutex );\r\n\r\n\t\tif ( ackLen == 0 )\r\n\t\t{\r\n\t\t\tWSASetLastError( WSAEWOULDBLOCK );\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\treturn ackLen;\r\n\t\t}\r\n\t}\r\n\telse\r\n\t{\r\n\t\treturn (*(NetIOFunc)OldRecv)(sock,buff,len,flags);\r\n\t}\r\n}\r\n\r\nint SkipSendData = 0;\r\nint HookSend( SOCKET sock, char *buff, int len, int flags )\r\n{\r\n\tint ackLen;\r\n\r\n\tif ( sock == CurrentConnection && CurrentConnection )\r\n\t{\r\n\t\tif ( !Seeded )\r\n\t\t{\r\n\t\t\tif ( len > 0 && ((BYTE)*buff) == ((BYTE)0xEF) )\r\n\t\t\t\tSkipSendData = 16;\r\n\r\n\t\t\tif ( len >= 4 )\r\n\t\t\t{\r\n\t\t\t\tSeeded = true;\r\n\r\n\t\t\t\tCryptSeed = *((DWORD*)buff);\r\n\r\n\t\t\t\tif ( ServerEncrypted )\r\n\t\t\t\t{\r\n\t\t\t\t\tServerCrypt->Initialize( CryptSeed );\r\n\t\t\t\t\tServerLogin->Initialize( (BYTE*)&CryptSeed );\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( ClientEncrypted )\r\n\t\t\t\t{\r\n\t\t\t\t\tClientCrypt->Initialize( CryptSeed );\r\n\t\t\t\t\tClientLogin->Initialize( (BYTE*)&CryptSeed );\r\n\t\t\t\t}\r\n\r\n\t\t\t\tCompression::Reset();\r\n\t\t\t}\r\n\r\n\t\t\tackLen = (*(NetIOFunc)OldSend)(sock,buff,len,flags);\r\n\t\t\tpShared->TotalSend += len;\r\n\t\t}\r\n\t\telse if ( SkipSendData < len )\r\n\t\t{\r\n\t\t\tSkipSendData = 0;\r\n\r\n\t\t\tif ( FirstSend )\r\n\t\t\t{\r\n\t\t\t\tFirstSend = false;\r\n\r\n\t\t\t\tif ( ClientEncrypted )\r\n\t\t\t\t\tLoginServer = ClientLogin->TestForLogin( (BYTE)buff[0] );\r\n\t\t\t\telse\r\n\t\t\t\t\tLoginServer = LoginEncryption::IsLoginByte( (BYTE)buff[0] );\r\n\r\n\t\t\t\tif ( LoginServer )\r\n\t\t\t\t\tForwarding = Forwarded = false;\r\n\t\t\t}\r\n\r\n\t\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\r\n\t\t\tif (ClientEncrypted)\r\n\t\t\t{\r\n\t\t\t\tif ( Forwarded )\r\n\t\t\t\t{\r\n\t\t\t\t\tCryptSeed = LoginEncryption::GenerateBadSeed( CryptSeed );\r\n\r\n\t\t\t\t\tClientCrypt->Initialize( CryptSeed );\r\n\r\n\t\t\t\t\tClientCrypt->DecryptFromClient( (BYTE*)buff, (BYTE*)(&pShared->InSend.Buff[pShared->InSend.Start+pShared->InSend.Length]), len );\r\n\t\t\t\t\tClientLogin->Decrypt( (BYTE*)(&pShared->InSend.Buff[pShared->InSend.Start+pShared->InSend.Length]), (BYTE*)(&pShared->InSend.Buff[pShared->InSend.Start+pShared->InSend.Length]), len );\r\n\r\n\t\t\t\t\tLoginServer = Forwarding = Forwarded = false;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tif ( LoginServer )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tClientLogin->Decrypt( (BYTE*)(buff), (BYTE*)(&pShared->InSend.Buff[pShared->InSend.Start+pShared->InSend.Length]), len );\r\n\r\n\t\t\t\t\t\tif ( ((BYTE)pShared->InSend.Buff[pShared->InSend.Start+pShared->InSend.Length]) == 0xA0 )\r\n\t\t\t\t\t\t\tForwarding = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tClientCrypt->DecryptFromClient((BYTE*)(buff), (BYTE*)(&pShared->InSend.Buff[pShared->InSend.Start + pShared->InSend.Length]), len);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t\tmemcpy( &pShared->InSend.Buff[pShared->InSend.Start+pShared->InSend.Length], buff, len );\r\n\r\n\t\t\tpShared->InSend.Length += len;\r\n\t\t\tReleaseMutex( CommMutex );\r\n\r\n\t\t\tSendMessage( hRazorWnd, WM_UONETEVENT, SEND, 0 );\r\n\r\n\t\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\t\t\tFlushSendData();\r\n\t\t\tMaintenance( pShared->InSend );\r\n\t\t\tReleaseMutex( CommMutex );\r\n\r\n\t\t\tackLen = len;//lie and say we sent it all -- or should we tell the truth? (probably not since then it could try to send it again..)\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tackLen = (*(NetIOFunc)OldSend)(sock,buff,len,flags);\r\n\t\t\tpShared->TotalSend += len;\r\n\t\t\tSkipSendData -= len;\r\n\t\t}\r\n\t}\r\n\telse\r\n\t{\r\n\t\tackLen = (*(NetIOFunc)OldSend)(sock,buff,len,flags);\r\n\t}\r\n\r\n\treturn ackLen;\r\n}\r\n\r\n#define RAZOR_ID_KEY \"\\x9\\x11\\x83+\\x4\\x17\\x83\\x5\\x24\\x85\\x7\\x17\\x87\\x6\\x19\\x88\"\r\n#define RAZOR_ID_KEY_LEN 16\r\n\r\nvoid FlushSendData()\r\n{\r\n\tWaitForSingleObject( CommMutex, INFINITE );\r\n\tif ( pShared->OutSend.Length > 0 && CurrentConnection )\r\n\t{\r\n\t\tint ackLen = 0;\r\n\t\tint outLen = pShared->OutSend.Length;\r\n\r\n\t\tif ( !InGame && !LoginServer )\r\n\t\t{\r\n\t\t\tint pos = pShared->OutSend.Start;\r\n\t\t\tunsigned char *buff = &pShared->OutSend.Buff[pos];\r\n\r\n\t\t\twhile ( pos < outLen )\r\n\t\t\t{\r\n\t\t\t\tint left = pShared->OutSend.Length - pos;\r\n\t\t\t\tint len = GetPacketLength( buff, left );\r\n\r\n\t\t\t\tif ( *buff == 0x5D && len >= 1+4+30+30 && len <= left )\r\n\t\t\t\t{\r\n\t\t\t\t\t// play character\r\n\t\t\t\t\tif ( pShared->AllowNegotiate && ServerNegotiated )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t// the first 2 bytes are 0\r\n\t\t\t\t\t\t// the next 4 bytes are \"flags\" which say the user's client type (lbr,t2a,aos,etc)\r\n\t\t\t\t\t\t// the rest are ignored, so we can use them for auth\r\n\t\t\t\t\t\tmemcpy( buff + 1 + 4 + 30 + 2 + 4, pShared->AuthBits, 8 );\r\n\t\t\t\t\t\tmemcpy( buff + 1 + 4 + 30 + 2 + 4 + 8, RAZOR_ID_KEY, RAZOR_ID_KEY_LEN );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tInGame = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\telse if ( *buff == 0x00 && (*((DWORD*)&buff[1])) == 0xEDEDEDED && len >= 1+4+4+1+30+30 && len <= left )\r\n\t\t\t\t{\r\n\t\t\t\t\t// char creation\r\n\t\t\t\t\tif ( pShared->AllowNegotiate && ServerNegotiated )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemcpy( buff + 1 + 4 + 4 + 1 + 30 + 15, pShared->AuthBits, 8 );\r\n\t\t\t\t\t\tmemcpy( buff + 1 + 4 + 4 + 1 + 30 + 15 + 8, RAZOR_ID_KEY, min( 7, RAZOR_ID_KEY_LEN ) );\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tInGame = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( len <= 0 )\r\n\t\t\t\t{\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tpos += len;\r\n\t\t\t\t\tbuff += len;\r\n\t\t\t\t}\r\n\t\t\t} // END while\r\n\t\t} // END if ( !InGame && !LoginServer\r\n\r\n\t\tif ( ServerEncrypted )\r\n\t\t{\r\n\t\t\tif ( tempBuff == NULL )\r\n\t\t\t\ttempBuff = new char[SHARED_BUFF_SIZE];\r\n\r\n\t\t\tif ( LoginServer )\r\n\t\t\t\tServerLogin->Encrypt( (BYTE*)&pShared->OutSend.Buff[pShared->OutSend.Start], (BYTE*)tempBuff, outLen );\r\n\t\t\telse\r\n\t\t\t\tServerCrypt->EncryptForServer( (BYTE*)&pShared->OutSend.Buff[pShared->OutSend.Start], (BYTE*)tempBuff, outLen );\r\n\r\n\t\t\tackLen = (*(NetIOFunc)OldSend)(CurrentConnection,tempBuff,outLen,0);\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tackLen = (*(NetIOFunc)OldSend)(CurrentConnection,(char*)&pShared->OutSend.Buff[pShared->OutSend.Start],outLen,0);\r\n\t\t}\r\n\r\n\t\tif ( ackLen == SOCKET_ERROR )\r\n\t\t{\r\n\t\t\tif ( WSAGetLastError() != WSAEWOULDBLOCK )\r\n\t\t\t\tpShared->ForceDisconn = true;\r\n\t\t}\r\n\t\telse //if ( ackLen >= 0 )\r\n\t\t{\r\n\t\t\tpShared->TotalSend += ackLen;\r\n\r\n\t\t\tpShared->OutSend.Start += ackLen;\r\n\t\t\tpShared->OutSend.Length -= ackLen;\r\n\t\t}\r\n\t}\r\n\r\n\tMaintenance( pShared->OutSend );\r\n\tReleaseMutex( CommMutex );\r\n}\r\n\r\nint HookConnect( SOCKET sock, const sockaddr *addr, int addrlen )\r\n{\r\n\tint retVal;\r\n\r\n\tif ( addr && addrlen >= sizeof(sockaddr_in) )\r\n\t{\r\n\t\tconst sockaddr_in *old_addr = (const sockaddr_in *)addr;\r\n\t\tsockaddr_in useAddr;\r\n\r\n\t\tmemcpy( &useAddr, old_addr, sizeof(sockaddr_in) );\r\n\r\n\t\tif ( !Forwarded && pShared->ServerIP != 0 )\r\n\t\t{\r\n\t\t\tuseAddr.sin_addr.S_un.S_addr = pShared->ServerIP;\r\n\t\t\tuseAddr.sin_port = htons( pShared->ServerPort );\r\n\t\t}\r\n\r\n\t\tretVal = (*(ConnFunc)OldConnect)( sock, (sockaddr*)&useAddr, sizeof(sockaddr_in) );\r\n\r\n\t\tif ( retVal != SOCKET_ERROR )\r\n\t\t{\r\n\t\t\tLog( \"Connecting to %i\", sock );\r\n\r\n\t\t\tCreateEncryption();\r\n\r\n\t\t\tSeeded = false;\r\n\t\t\tLoginServer = false;\r\n\t\t\tFirstRecv = true;\r\n\t\t\tFirstSend = true;\r\n\t\t\tForwarding = Forwarded = false;\r\n\r\n\t\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\t\t\tCurrentConnection = sock;\r\n\t\t\tpShared->OutRecv.Length = pShared->InRecv.Length = pShared->OutSend.Length = pShared->InSend.Length = 0;\r\n\t\t\tpShared->ForceDisconn = false;\r\n\t\t\tReleaseMutex( CommMutex );\r\n\r\n\t\t\tPostMessage( hRazorWnd, WM_UONETEVENT, CONNECT, useAddr.sin_addr.S_un.S_addr );\r\n\t\t}\r\n\t}\r\n\telse\r\n\t{\r\n\t\tretVal = (*(ConnFunc)OldConnect)( sock, addr, addrlen );\r\n\t}\r\n\r\n\treturn retVal;\r\n}\r\n\r\nint HookCloseSocket( SOCKET sock )\r\n{\r\n\tint retVal = (*(CLSFunc)OldCloseSocket)( sock );\r\n\r\n\tif ( sock == CurrentConnection && sock != 0 )\r\n\t{\r\n\t\tLog( \"Closing socket %i\", sock );\r\n\t\tCurrentConnection = 0;\r\n\r\n\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\t\tpShared->OutRecv.Length = pShared->InRecv.Length = pShared->OutSend.Length = pShared->InSend.Length = 0;\r\n\t\tpShared->TotalSend = pShared->TotalRecv = 0;\r\n\t\tpShared->ForceDisconn = false;\r\n\t\tReleaseMutex( CommMutex );\r\n\r\n\t\tServerNegotiated = false;\r\n\t\tInGame = false;\r\n\r\n\t\tmemset( pShared->AuthBits, 0, 8 );\r\n\r\n\t\tPostMessage( hRazorWnd, WM_UONETEVENT, DISCONNECT, 0 );\r\n\t}\r\n\r\n\treturn retVal;\r\n}\r\n\r\nint HookSelect( int ndfs, fd_set *readfd, fd_set *writefd, fd_set *exceptfd, const struct timeval *timeout )\r\n{\r\n\tbool checkRecv = false;\r\n\tbool checkErr = false;\r\n\tbool modified = false;\r\n\tint realRet = 0;\r\n\tint myRet = 0;\r\n\r\n\tif ( CurrentConnection )\r\n\t{\r\n\t\tif ( readfd != NULL )\r\n\t\t\tcheckRecv = FD_ISSET( CurrentConnection, readfd );\r\n\r\n\t\tif ( exceptfd != NULL )\r\n\t\t\tcheckErr = FD_ISSET( CurrentConnection, exceptfd );\r\n\t}\r\n\r\n\ttimeval myTimeout;\r\n\r\n\tif ( SmartCPU )\r\n\t{\r\n\t\tint length = 0;\r\n\r\n\t\tif ( Active )\r\n\t\t{\r\n\t\t\tLARGE_INTEGER end;\r\n\t\t\tQueryPerformanceCounter( &end );\r\n\r\n\t\t\tlength = int( 1000000.0 * ((end.QuadPart-Counter.QuadPart)/double(PerfFreq.QuadPart)) );\r\n\t\t}\r\n\r\n\t\tif ( length < 33333 )\r\n\t\t{\r\n\t\t\tmyTimeout.tv_sec = 0;\r\n\t\t\tmyTimeout.tv_usec = 33333 - length;\r\n\t\t\ttimeout = &myTimeout;\r\n\t\t}\r\n\t}\r\n\r\n\trealRet = (*(SelectFunc)OldSelect)( ndfs, readfd, writefd, exceptfd, timeout );\r\n\r\n\tif ( SmartCPU )\r\n\t\tQueryPerformanceCounter( &Counter );\r\n\r\n\tif ( checkRecv )\r\n\t{\r\n\t\tif ( FD_ISSET( CurrentConnection, readfd ) )\r\n\t\t{\r\n\t\t\tFD_CLR( CurrentConnection, readfd );\r\n\t\t\tRecvData();\r\n\t\t\trealRet--;\r\n\t\t}\r\n\r\n\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\t\tif ( pShared->OutRecv.Length > 0 || ( pShared->ForceDisconn ) )\r\n\t\t{\r\n\t\t\tFD_SET( CurrentConnection, readfd );\r\n\t\t\tmyRet++;\r\n\t\t}\r\n\t\tReleaseMutex( CommMutex );\r\n\t}\r\n\r\n\tif ( checkErr && !FD_ISSET( CurrentConnection, exceptfd ) )\r\n\t{\r\n\t\tWaitForSingleObject( CommMutex, INFINITE );\r\n\t\tif ( pShared->ForceDisconn && pShared->OutRecv.Length <= 0 )\r\n\t\t{\r\n\t\t\tFD_SET( CurrentConnection, exceptfd );\r\n\t\t\tmyRet++;\r\n\t\t}\r\n\t\tReleaseMutex( CommMutex );\r\n\t}\r\n\r\n\tif ( realRet < 0 )\r\n\t{\r\n\t\treturn myRet;\r\n\t}\r\n\telse\r\n\t{\r\n\t\treturn realRet + myRet;\r\n\t}\r\n}\r\n\r\nbool HookFunction( const char *Dll, const char *FuncName, int Ordinal, unsigned long NewAddr,\r\n\t\t\t\t  unsigned long *OldAddr, unsigned long *PatchAddr )\r\n{\r\n\tDWORD baseAddr = (DWORD)GetModuleHandle(NULL);\r\n\tif ( !baseAddr )\r\n\t\treturn false;\r\n\r\n\tIMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)baseAddr;\r\n\r\n\tIMAGE_FILE_HEADER *ifh = (IMAGE_FILE_HEADER *)(baseAddr + idh->e_lfanew + sizeof(DWORD));\r\n\r\n\tIMAGE_OPTIONAL_HEADER *ioh = (IMAGE_OPTIONAL_HEADER *)((DWORD)(ifh) + sizeof(IMAGE_FILE_HEADER));\r\n\r\n\tIMAGE_IMPORT_DESCRIPTOR *iid = (IMAGE_IMPORT_DESCRIPTOR *)(baseAddr + ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);\r\n\r\n\twhile( iid->Name )\r\n\t{\r\n\t\tif( _stricmp( Dll, (char *)(baseAddr + iid->Name) ) == 0 )\r\n\t\t{\r\n\t\t\tIMAGE_THUNK_DATA * pThunk = (IMAGE_THUNK_DATA *)((DWORD)iid->OriginalFirstThunk + baseAddr);\r\n\t\t\tIMAGE_THUNK_DATA * pThunk2 = (IMAGE_THUNK_DATA *)((DWORD)iid->FirstThunk + baseAddr);\r\n\r\n\t\t\twhile( pThunk->u1.AddressOfData )\r\n\t\t\t{\r\n\t\t\t\tchar *name = NULL;\r\n\t\t\t\tint ord;\r\n\r\n\t\t\t\tif( pThunk->u1.Ordinal & 0x80000000 )\r\n\t\t\t\t{\r\n\t\t\t\t\t// Imported by ordinal only:\r\n\t\t\t\t\tord = pThunk->u1.Ordinal & 0xFFFF;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\t// Imported by name (with ordinal hint)\r\n\t\t\t\t\tIMAGE_IMPORT_BY_NAME * pName = (IMAGE_IMPORT_BY_NAME *)((DWORD)pThunk->u1.AddressOfData + baseAddr);\r\n\t\t\t\t\tord = pName->Hint;\r\n\t\t\t\t\tname = (char *)pName->Name;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( ord == Ordinal || ( name && FuncName && !strcmp( name, FuncName ) ) )\r\n\t\t\t\t{\r\n\t\t\t\t\t*OldAddr = (unsigned long)pThunk2->u1.Function;\r\n\t\t\t\t\t*PatchAddr = (unsigned long)(&pThunk2->u1.Function);\r\n\t\t\t\t\tMemoryPatch( *PatchAddr, NewAddr );\r\n\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpThunk++;\r\n\t\t\t\tpThunk2++;\r\n\t\t\t}\r\n\t\t}\r\n\t\tiid++;\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n\r\n\r\nbool FindFunction( const char *Dll, const char *FuncName, int Ordinal, unsigned long *ImpAddr, unsigned long *CallAddr )\r\n{\r\n\tDWORD baseAddr = (DWORD)GetModuleHandle(NULL);\r\n\tif ( !baseAddr )\r\n\t\treturn false;\r\n\r\n\tIMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)baseAddr;\r\n\r\n\tIMAGE_FILE_HEADER *ifh = (IMAGE_FILE_HEADER *)(baseAddr + idh->e_lfanew + sizeof(DWORD));\r\n\r\n\tIMAGE_OPTIONAL_HEADER *ioh = (IMAGE_OPTIONAL_HEADER *)((DWORD)(ifh) + sizeof(IMAGE_FILE_HEADER));\r\n\r\n\tIMAGE_IMPORT_DESCRIPTOR *iid = (IMAGE_IMPORT_DESCRIPTOR *)(baseAddr + ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);\r\n\r\n\twhile( iid->Name )\r\n\t{\r\n\t\tif( _stricmp( Dll, (char *)(baseAddr + iid->Name) ) == 0 )\r\n\t\t{\r\n\t\t\tIMAGE_THUNK_DATA * pThunk = (IMAGE_THUNK_DATA *)((DWORD)iid->OriginalFirstThunk + baseAddr);\r\n\t\t\tIMAGE_THUNK_DATA * pThunk2 = (IMAGE_THUNK_DATA *)((DWORD)iid->FirstThunk + baseAddr);\r\n\r\n\t\t\twhile( pThunk->u1.AddressOfData )\r\n\t\t\t{\r\n\t\t\t\tchar *name = NULL;\r\n\t\t\t\tint ord;\r\n\r\n\t\t\t\tif( pThunk->u1.Ordinal & 0x80000000 )\r\n\t\t\t\t{\r\n\t\t\t\t\t// Imported by ordinal only:\r\n\t\t\t\t\tord = pThunk->u1.Ordinal & 0xFFFF;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\t// Imported by name (with ordinal hint)\r\n\t\t\t\t\tIMAGE_IMPORT_BY_NAME * pName = (IMAGE_IMPORT_BY_NAME *)((DWORD)pThunk->u1.AddressOfData + baseAddr);\r\n\t\t\t\t\tord = pName->Hint;\r\n\t\t\t\t\tname = (char *)pName->Name;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif ( ord == Ordinal || ( name && FuncName && !strcmp( name, FuncName ) ) )\r\n\t\t\t\t{\r\n\t\t\t\t\t*ImpAddr = (unsigned long)pThunk2->u1.Function;\r\n\t\t\t\t\t*CallAddr = (unsigned long)(&pThunk2->u1.Function);\r\n\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpThunk++;\r\n\t\t\t\tpThunk2++;\r\n\t\t\t}\r\n\t\t}\r\n\t\tiid++;\r\n\t}\r\n\r\n\treturn false;\r\n}\r\n\r\n#define NOTO_HUE_STR \"\\0\\0\\0\\0\\x59\\0\\0\\0\\x3F\\0\\0\\0\\xb2\\x03\\0\\0\"\r\n#define NOTO_HUE_LEN 16\r\n\r\nDWORD NotoLoc = 0;\r\nvoid SetCustomNotoHue( int hue )\r\n{\r\n\tif ( !NotoLoc )\r\n\t{\r\n\t\tNotoLoc = MemFinder::Find( NOTO_HUE_STR, NOTO_HUE_LEN );\r\n\t\tif ( !NotoLoc )\r\n\t\t\tNotoLoc = 0xFFFFFFFF;\r\n\t}\r\n\r\n\tif ( NotoLoc != 0xFFFFFFFF )\r\n\t\t*((int*)(NotoLoc + 8*4)) = hue;\r\n}\r\n\r\nbool PatchMemory( void )\r\n{\r\n\tLog( \"Patching client functions.\" );\r\n\r\n\treturn\r\n\t\tHookFunction( \"wsock32.dll\", \"closesocket\", 3, (unsigned long)HookCloseSocket, &OldCloseSocket, &CloseSocketAddress ) &&\r\n\t\tHookFunction( \"wsock32.dll\", \"connect\", 4, (unsigned long)HookConnect, &OldConnect, &ConnectAddress ) &&\r\n\t\tHookFunction( \"wsock32.dll\", \"recv\", 16, (unsigned long)HookRecv, &OldRecv, &RecvAddress ) &&\r\n\t\tHookFunction( \"wsock32.dll\", \"select\", 18, (unsigned long)HookSelect, &OldSelect, &SelectAddress ) &&\r\n\t\tHookFunction( \"wsock32.dll\", \"send\", 19, (unsigned long)HookSend, &OldSend, &SendAddress )\r\n\t\t;\r\n}\r\n\r\nvoid MemoryPatch( unsigned long Address, unsigned long value )\r\n{\r\n\tMemoryPatch( Address, &value, 4 ); // sizeof(int)\r\n}\r\n\r\nvoid MemoryPatch( unsigned long Address, int value, int numBytes )\r\n{\r\n\tMemoryPatch( Address, &value, numBytes );\r\n}\r\n\r\nvoid MemoryPatch( unsigned long Address, const void *value, int length )\r\n{\r\n\tDWORD OldProtect;\r\n\tif ( !VirtualProtect( (void *)Address, length, PAGE_READWRITE, &OldProtect ) )\r\n\t\treturn;\r\n\r\n\tmemcpy( (void *)Address, value, length );\r\n\r\n\tVirtualProtect( (void *)Address, length, OldProtect, &OldProtect );\r\n}\r\n\r\nbool CheckParent( HWND hCheck, HWND hComp )\r\n{\r\n\thCheck = GetParent( hCheck );\r\n\twhile ( hCheck != hComp && hCheck != NULL )\r\n\t\thCheck = GetParent( hCheck );\r\n\r\n\treturn ( hCheck == hComp );\r\n}\r\n\r\nvoid MessageProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, MSG *pMsg )\r\n{\r\n\tHWND hFore;\r\n\r\n\tswitch ( nMsg )\r\n\t{\r\n\t\t// Custom messages\r\n\tcase WM_PROCREADY:\r\n\t\thRazorWnd = (HWND)lParam;\r\n\t\tUOProcId = GetCurrentProcessId();\r\n\t\thUOWindow = hWnd;\r\n\r\n\t\tif (!pShared) // If this failed the first time or was not run at all, try it once more before panicing\r\n\t\t\tOnAttach(NULL, 0);\r\n\r\n\t\tClientEncrypted = (wParam & 0x08) != 0;\r\n\t\tServerEncrypted = (wParam & 0x10) != 0;\r\n\r\n\t\tInitThemes();\r\n\r\n\t\tif (pShared)\r\n\t\t{\r\n\t\t\tpShared->AllowNegotiate = (wParam & 0x04) != 0;\r\n\r\n\t\t\tpShared->UOVersion[0] = 0;\r\n\r\n\t\t\tif (NativeGetUOVersion != NULL)\r\n\t\t\t\tstrncpy(pShared->UOVersion, NativeGetUOVersion(), 16);\r\n\t\t}\r\n\r\n\t\tif ( !pShared )\r\n\t\t\tPostMessage( hRazorWnd, WM_UONETEVENT, NOT_READY, NO_SHAREMEM );\r\n\t\telse if ( CopyFailed )\r\n\t\t\tPostMessage( hRazorWnd, WM_UONETEVENT, NOT_READY, NO_COPY );\r\n\t\telse if ( !PatchMemory() )\r\n\t\t\tPostMessage( hRazorWnd, WM_UONETEVENT, NOT_READY, NO_PATCH );\r\n\t\telse\r\n\t\t\tPostMessage( hRazorWnd, WM_UONETEVENT, READY, SUCCESS );\r\n\r\n\t\t/* Start a timer that will call a callback each tick. We use this to implement\r\n\t\t * timers as well as scan client memory for position updates. */\r\n\t\tSetTimer(hUOWindow, (UINT_PTR)0xAA, 25, OnTick);\r\n\r\n\t\tbreak;\r\n\r\n\tcase WM_UONETEVENT:\r\n\t\tswitch ( LOWORD(wParam) )\r\n\t\t{\r\n\t\tcase SEND:\r\n\t\t\tFlushSendData();\r\n\t\t\tbreak;\r\n\t\tcase STAT_BAR:\r\n\t\t\tPatchStatusBar( (BOOL)lParam );\r\n\t\t\tbreak;\r\n\t\tcase NOTO_HUE:\r\n\t\t\tSetCustomNotoHue( (int)lParam );\r\n\t\t\tbreak;\r\n\r\n\t\tcase SETWNDSIZE:\r\n\t\t\tDesiredSize.cx = LOWORD(lParam);\r\n\t\t\tDesiredSize.cy = HIWORD(lParam);\r\n\t\t\tbreak;\r\n\r\n\t\tcase SMART_CPU:\r\n\t\t\tSmartCPU = lParam;\r\n\t\t\tbreak;\r\n\r\n\t\tcase NEGOTIATE:\r\n\t\t\tif ( pShared )\r\n\t\t\t\tpShared->AllowNegotiate = (lParam != 0);\r\n\t\t\tbreak;\r\n\r\n\t\tcase SET_MAP_HWND:\r\n\t\t\thMapWnd = (HWND)lParam;\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tbreak;\r\n\r\n\tcase WM_COPYDATA: {\r\n\t\tCOPYDATASTRUCT *copydata = (COPYDATASTRUCT *)lParam;\r\n\r\n\t\tswitch ((UONET_MESSAGE_COPYDATA)copydata->dwData) {\r\n\t\tcase UONET_MESSAGE_COPYDATA::POSITION:\r\n\t\t\tg_TestPosition = *(Position *)copydata->lpData;\r\n\t\t\tbreak;\r\n\r\n\t\t}\r\n\t\tbreak;\r\n\t}\r\n\r\n\t\t// Macro stuff\r\n\tcase WM_SYSKEYDOWN:\r\n\tcase WM_KEYDOWN:\r\n\t\tif ( pMsg && !SendMessage( hRazorWnd, WM_UONETEVENT, KEYDOWN, wParam ) )\r\n\t\t{\r\n\t\t\t// dont give the key to the client\r\n\t\t\tpMsg->message = WM_NULL;\r\n\t\t\tpMsg->lParam = 0;\r\n\t\t\tpMsg->wParam = 0;\r\n\t\t}\r\n\t\tbreak;\r\n\r\n\tcase WM_SYSKEYUP:\r\n\tcase WM_KEYUP:\r\n\t\tif ( pMsg && wParam == VK_SNAPSHOT ) // VK_SNAPSHOT (Print Screen) Doesn't seem to send a KeyDown message\r\n\t\t\tSendMessage( hRazorWnd, WM_UONETEVENT, KEYDOWN, wParam );\r\n\t\tbreak;\r\n\r\n\tcase WM_MOUSEWHEEL:\r\n\t\tPostMessage( hRazorWnd, WM_UONETEVENT, MOUSE, MAKELONG( 0, (((short)HIWORD(wParam)) < 0 ? -1 : 1) ) );\r\n\t\tbreak;\r\n\tcase WM_MBUTTONDOWN:\r\n\t\tPostMessage( hRazorWnd, WM_UONETEVENT, MOUSE, MAKELONG( 1, 0 ) );\r\n\t\tbreak;\r\n\tcase WM_XBUTTONDOWN:\r\n\t\tPostMessage( hRazorWnd, WM_UONETEVENT, MOUSE, MAKELONG( HIWORD(wParam) + 1, 0 ) );\r\n\t\tbreak;\r\n\r\n\t\t//Activation tracking :\r\n\tcase WM_ACTIVATE:\r\n\t\tActive = wParam;\r\n\t\tPostMessage( hRazorWnd, WM_UONETEVENT, ACTIVATE, wParam );\r\n\t\tbreak;\r\n\tcase WM_KILLFOCUS:\r\n\t\thFore = GetForegroundWindow();\r\n\t\tif ( ((HWND)wParam) != hRazorWnd && hFore != hRazorWnd && ((HWND)wParam) != hMapWnd && hFore != hMapWnd\r\n\t\t\t&& !CheckParent( hFore, hRazorWnd ) )\r\n\t\t{\r\n\t\t\tPostMessage( hRazorWnd, WM_UONETEVENT, FOCUS, FALSE );\r\n\t\t}\r\n\t\tbreak;\r\n\tcase WM_SETFOCUS:\r\n\t\tPostMessage( hRazorWnd, WM_UONETEVENT, FOCUS, TRUE );\r\n\t\tbreak;\r\n\r\n\t\t//Custom title bar:\r\n\tcase WM_NCACTIVATE:\r\n\t\tActive = wParam;\r\n\t\t//fallthrough\r\n\tcase WM_NCPAINT:\r\n\tcase WM_GETICON:\r\n\tcase WM_SETTEXT:\r\n\tcase WM_CUSTOMTITLE:\r\n\t\tCheckTitlebarAttr(hWnd);\r\n\t\tRedrawTitleBar( hWnd, Active );\r\n\t\tbreak;\r\n\t}\r\n}\r\n\r\nLRESULT CALLBACK GetMsgHookFunc( int Code, WPARAM Flag, LPARAM pMsg )\r\n{\r\n\tif ( Code >= 0 && Flag != PM_NOREMOVE ) //dont process messages until they are removed from the queue\r\n\t{\r\n\t\tMSG *Msg = (MSG*)pMsg;\r\n\t\t/*\r\n\t\tMsg->message ^= 0x11;\r\n\t\tMsg->message ^= Disabled * 101;\r\n\t\tMsg->message *= !(Disabled * 020);\r\n\t\tMsg->message ^= 0x11;\r\n\t\t*/\r\n\t\tif ( Msg->hwnd == hUOWindow || ( hUOWindow == NULL && Msg->message == WM_PROCREADY ) )\r\n\t\t\tMessageProc( Msg->hwnd, Msg->message, Msg->wParam, Msg->lParam, Msg );\r\n\t}\r\n\r\n\treturn CallNextHookEx( NULL, Code, Flag, pMsg );\r\n}\r\n\r\nLRESULT CALLBACK WndProcRetHookFunc( int Code, WPARAM Flag, LPARAM pMsg )\r\n{\r\n\tif ( Code >= 0 )\r\n\t{\r\n\t\tCWPRETSTRUCT *Msg = (CWPRETSTRUCT *)(pMsg);\r\n\t\t/*\r\n\t\tMsg->message ^= 0x11;\r\n\t\tMsg->message ^= Disabled * 101;\r\n\t\tMsg->message *= !(Disabled * 020);\r\n\t\tMsg->message ^= 0x11;\r\n\t\t*/\r\n\t\tif ( Msg->hwnd == hUOWindow || ( hUOWindow == NULL && Msg->message == WM_PROCREADY ) )\r\n\t\t\tMessageProc( Msg->hwnd, Msg->message, Msg->wParam, Msg->lParam, NULL );\r\n\t}\r\n\r\n\treturn CallNextHookEx( NULL, Code, Flag, pMsg );\r\n}\r\n\r\nLRESULT CALLBACK UOAWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)\r\n{\r\n\tif (nMsg >= WM_USER + 200 && nMsg < WM_USER + 315)\r\n\t   return SendMessage(hRazorWnd, nMsg, wParam, lParam);\r\n\telse\r\n\t   return DefWindowProc(hWnd, nMsg, wParam, lParam);\r\n}\r\n\r\nvoid Log( const char *format, ... )\r\n{\r\n#ifdef _DEBUG\r\n#ifdef LOGGING\r\n\tFILE *log = fopen( \"Crypt.log\", \"a\" );\r\n\tif ( log )\r\n\t{\r\n\t\tchar timeStr[256];\r\n\t\tstruct tm *newtime;\r\n\t\ttime_t aclock;\r\n\r\n\t\ttime( &aclock );\r\n\t\tnewtime = localtime( &aclock );\r\n\t\tstrncpy( timeStr, asctime( newtime ), 256 );\r\n\t\tint len = (int)strlen( timeStr );\r\n\t\tif ( timeStr[len-1] == '\\n' )\r\n\t\t\ttimeStr[len-1] = 0;\r\n\r\n\t\tchar OutTxt[512];\r\n\t\tva_list argList;\r\n\t\tva_start( argList, format );\r\n\t\t_vsnprintf( OutTxt, 512, format, argList );\r\n\t\tva_end( argList );\r\n\r\n\t\tfprintf( log, \"%s: %s\\n\", timeStr, OutTxt );\r\n\t\tfclose( log );\r\n\t}\r\n#endif\r\n#endif\r\n}\r\n\r\n"
  },
  {
    "path": "Crypt/Crypt.def",
    "content": "LIBRARY\tCrypt\r\n\r\nEXPORTS\r\n\tInstallLibrary\r\n\tShutdown\r\n\tFindUOWindow\r\n\tGetSharedAddress\r\n\tGetPacketLength\r\n\tIsDynLength\r\n\tGetUOProcId\r\n\tGetCommMutex\r\n\tTotalIn\r\n\tTotalOut\r\n\tWaitForWindow\r\n\tSetDataPath\r\n\tCalibratePosition\r\n\tOnAttach\r\n\tSetServer\r\n\tGetUOVersion\r\n"
  },
  {
    "path": "Crypt/Crypt.h",
    "content": "#pragma once\r\n#pragma pack(1)\r\n\r\n#include <stdint.h>\r\n\r\n#define DLL_VERSION \"1.4.1\"\r\n\r\n#define DLLFUNCTION __declspec(dllexport)\r\n#define DLLVAR DLLFUNCTION\r\n\r\n#ifdef _DEBUG\r\n//#define LOGGING\r\n#endif\r\n\r\nenum IError\r\n{\r\n\tSUCCESS,\r\n\tNO_UOWND,\r\n\tNO_TID,\r\n\tNO_HOOK,\r\n\tNO_SHAREMEM,\r\n\tLIB_DISABLED,\r\n\tNO_PATCH,\r\n\tNO_COPY,\r\n\tINVALID_PARAMS,\r\n\r\n\tUNKNOWN,\r\n};\r\n\r\nenum UONET_MESSAGE\r\n{\r\n\tSEND = 1,\r\n\tRECV = 2,\r\n\tREADY = 3,\r\n\tNOT_READY = 4,\r\n\tCONNECT = 5,\r\n\tDISCONNECT = 6,\r\n\tKEYDOWN = 7,\r\n\tMOUSE = 8,\r\n\r\n\tACTIVATE = 9,\r\n\tFOCUS = 10,\r\n\r\n\tCLOSE = 11,\r\n\tSTAT_BAR = 12,\r\n\tNOTO_HUE = 13,\r\n\tDLL_ERROR = 14,\r\n\r\n\tSETWNDSIZE = 19,\r\n\r\n\tSMART_CPU = 21,\r\n\tNEGOTIATE = 22,\r\n\tSET_MAP_HWND = 23,\r\n\r\n\tON_TICK = 24,\r\n};\r\n\r\nenum class UONET_MESSAGE_COPYDATA\r\n{\r\n\tPOSITION = 1,\r\n};\r\n\r\n//#define SHARED_BUFF_SIZE 0x80000 // Client's buffers are 500k\r\n#define SHARED_BUFF_SIZE 524288 // 262144 // 250k\r\nstruct Buffer\r\n{\r\n\tint Length;\r\n\tint Start;\r\n\tBYTE Buff[SHARED_BUFF_SIZE];\r\n};\r\n\r\n#pragma pack(1)\r\nstruct Position {\r\n\tuint16_t x;\r\n\tuint16_t y;\r\n\tuint16_t z;\r\n};\r\nstatic_assert(sizeof(struct Position) == 6, \"Incorrect size\\n\");\r\n\r\nstruct SharedMemory\r\n{\r\n\t// Do *not* mess with this struct.  Really.  I mean it.\r\n\tBuffer InRecv;\r\n\tBuffer OutRecv;\r\n\tBuffer InSend;\r\n\tBuffer OutSend;\r\n\r\n\tchar TitleBar[1024];\r\n\tbool ForceDisconn;\r\n\tunsigned int TotalSend;\r\n\tunsigned int TotalRecv;\r\n\tunsigned short PacketTable[256];\r\n\tchar DataPath[256];\r\n\tbool AllowNegotiate;\r\n\tunsigned char AuthBits[16];\r\n\tbool Reserved0;\r\n\tunsigned int ServerIP;\r\n\tunsigned short ServerPort;\r\n\tchar UOVersion[16];\r\n};\r\n\r\nclass PatchInfo\r\n{\r\npublic:\r\n\tPatchInfo( DWORD addr, int len )\r\n\t{\r\n\t\tAddress = addr;\r\n\t\tLength = len;\r\n\t\tData = new char[Length];\r\n\t\tmemcpy( Data, (const void*)Address, Length );\r\n\t}\r\n\r\n\t~PatchInfo()\r\n\t{\r\n\t\tdelete[] Data;\r\n\t}\r\n\r\n\tDWORD Address;\r\n\tint Length;\r\n\tchar *Data;\r\n};\r\n\r\n#define WM_PROCREADY WM_USER\r\n#define WM_UONETEVENT WM_USER+1\r\n#define WM_CUSTOMTITLE WM_USER+2\r\n\r\n#ifndef WM_XBUTTONDOWN\r\n#define WM_XBUTTONDOWN                  0x020B\r\n#endif\r\n\r\nextern HWND hUOWindow;\r\nextern HINSTANCE hInstance;\r\nextern SharedMemory *pShared;\r\nextern HANDLE CommMutex;\r\n\r\nDLLFUNCTION int InstallLibrary( HWND PostWindow, DWORD pId );\r\nDLLFUNCTION void Shutdown( bool closeClient );\r\nDLLFUNCTION HWND FindUOWindow();\r\nDLLFUNCTION void *GetSharedAddress();\r\nDLLFUNCTION int GetPacketLength( unsigned char *data, int len );\r\nDLLFUNCTION bool IsDynLength( unsigned char packet );\r\nDLLFUNCTION int GetUOProcId();\r\nDLLFUNCTION HANDLE GetCommMutex();\r\nDLLFUNCTION unsigned int TotalIn();\r\nDLLFUNCTION unsigned int TotalOut();\r\nDLLFUNCTION void CalibratePosition(uint16_t x, uint16_t y, uint16_t z);\r\nDLLFUNCTION void OnAttach(void *params, int paramsLen);\r\nDLLFUNCTION void SetServer(unsigned int addr, unsigned short port);\r\nDLLFUNCTION const char *GetUOVersion();\r\n\r\n\r\nLRESULT CALLBACK UOAWndProc( HWND, UINT, WPARAM, LPARAM );\r\nvoid Log( const char *format, ... );\r\nvoid MemoryPatch( unsigned long, unsigned long );\r\nvoid MemoryPatch( unsigned long, int, int );\r\nvoid MemoryPatch( unsigned long, const void *, int );\r\nvoid RedrawTitleBar( HWND, bool );\r\nvoid CheckTitlebarAttr(HWND);\r\nvoid FreeArt();\r\nvoid InitThemes();\r\nbool PatchStatusBar( BOOL preAOS );\r\n\r\n//#define PACKET_TBL_STR \"Got Logout OK packet!\\0\\0\\0\"\r\n//#define PACKET_TS_LEN 24\r\n#define PACKET_TBL_STR \"\\x07\\0\\0\\0\\x03\\0\\0\\0\"\r\n#define PACKET_TS_LEN 8\r\n#define PACKET_TBL_OFFSET (0-(8+12+12))\r\n\r\n//search disassembly for\r\n//static key1 C1 E2 1F D1 E8 D1 E9 0B C6 0B CA 35 static key2 81 F1 dynamic key 4D\r\n#define CRYPT_KEY_STR \"\\xC1\\xE2\\x1F\\xD1\\xE8\\xD1\\xE9\\x0B\\xC6\\x0B\\xCA\\x35\"\r\n#define CRYPT_KEY_LEN 12\r\n\r\n//static key1 D1 E8 0B C6 C1 E2 1F 35 static key2 D1 E9 89 83 F0 00 42 00 8B 45 08 0B CA 81 F1 dynamic key 48\r\n#define CRYPT_KEY_STR_3D \"\\xD1\\xE8\\x0B\\xC6\\xC1\\xE2\\x1F\\x35\"\r\n#define CRYPT_KEY_3D_LEN 8\r\n\r\n/* To calculate login keys:\r\nkey1 = ( Major << 23 ) | ( Minor << 14 ) | ( Revision << 4 );\r\nkey1 ^= ( Revision * Revision ) << 9;\r\nkey1 ^= ( Minor * Minor );\r\nkey1 ^= ( Minor * 11 ) << 24;\r\nkey1 ^= ( Revision * 7 ) << 19;\r\nkey1 ^= 0x2C13A5FD;\r\nkey2 = ( Major << 22 ) | ( Revision << 13 ) | ( Minor << 3 );\r\nkey2 ^= ( Revision * Revision * 3 ) << 10;\r\nkey2 ^= ( Minor * Minor );\r\nkey2 ^= ( Minor * 13 ) << 23;\r\nkey2 ^= ( Revision * 7 ) << 18;\r\nkey2 ^= 0xA31D527F;\r\n*/\r\n/*\r\n.text:0041AA2F C1 E6 1F                          shl     esi, 31\r\n.text:0041AA32 D1 E8                             shr     eax, 1\r\n.text:0041AA34 0B C6                             or      eax, esi\r\n.text:0041AA36 47                                inc     edi\r\n.text:0041AA37 33 05 BC 29 6B 00                 xor     eax, LoginKey_2\r\n.text:0041AA3D C1 E2 1F                          shl     edx, 31\r\n.text:0041AA40 89 83 F8 00 0A 00                 mov     [ebx+0A00F8h], eax\r\n.text:0041AA46 D1 E8                             shr     eax, 1\r\n.text:0041AA48 0B C6                             or      eax, esi\r\n.text:0041AA4A 8B 35 BC 29 6B 00                 mov     esi, LoginKey_2\r\n.text:0041AA50 33 C6                             xor     eax, esi\r\n.text:0041AA52 D1 E9                             shr     ecx, 1\r\n.text:0041AA54 89 83 F8 00 0A 00                 mov     [ebx+0A00F8h], eax\r\n.text:0041AA5A 0B CA                             or      ecx, edx\r\n.text:0041AA5C 8B 15 B8 29 6B 00                 mov     edx, LoginKey_1\r\n*/\r\n// -- -- -- -- -- --\r\n// 1F D1 E8 0B C6 47 33 05 memoryloc_2 C1 E2 1F 89 83 F8 00 0A 00 D1 E8 0B C6 8B 35 memoryloc_2 33 C6 D1 E9 89 83 F8 00 0A 00 0B Ca 8b 15 memoryloc_1 33 CA\r\n#define CRYPT_KEY_STR_NEW \"\\x1F\\xD1\\xE8\\x0B\\xC6\\x47\\x33\\x05\"\r\n#define CRYPT_KEY_NEW_LEN 8\r\n\r\n/*\r\n.text:0041C599 8B F0                             mov     esi, eax\r\n.text:0041C59B 8B FA                             mov     edi, edx\r\n.text:0041C59D D1 E8                             shr     eax, 1\r\n.text:0041C59F C1 E7 1F                          shl     edi, 31\r\n.text:0041C5A2 0B C7                             or      eax, edi\r\n.text:0041C5A4 33 05 FC AB 6C 00                 xor     eax, dword_6CABFC\r\n.text:0041C5AA D1 EA                             shr     edx, 1\r\n.text:0041C5AC D1 E8                             shr     eax, 1\r\n.text:0041C5AE C1 E6 1F                          shl     esi, 31\r\n.text:0041C5B1 0B C7                             or      eax, edi\r\n.text:0041C5B3 33 05 FC AB 6C 00                 xor     eax, dword_6CABFC\r\n.text:0041C5B9 0B D6                             or      edx, esi\r\n.text:0041C5BB 33 15 00 AC 6C 00                 xor     edx, dword_6CAC00\r\n.text:0041C5C1 83 EB 01                          sub     ebx, 1\r\n.text:0041C5C4 83 C5 01                          add     ebp, 1\r\n.text:0041C5C7 85 DB                             test    ebx, ebx\r\n*/\r\n// E8 C1 E7 1F 0B C7 33 05 memoryloc_2\r\n#define CRYPT_KEY_STR_MORE_NEW \"\\xE8\\xC1\\xE7\\x1F\\x0B\\xC7\\x33\\x05\"\r\n#define CRYPT_KEY_MORE_NEW_LEN 8\r\n"
  },
  {
    "path": "Crypt/Crypt.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}</ProjectGuid>\r\n    <RootNamespace>Crypt</RootNamespace>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup>\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <CharacterSet>MultiByte</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup>\r\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <OutDir>$(SolutionDir)bin\\$(Platform)\\$(Configuration)\\</OutDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CRYPT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <Optimization>Disabled</Optimization>\r\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r\n      <CallingConvention>StdCall</CallingConvention>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <ModuleDefinitionFile>Crypt.def</ModuleDefinitionFile>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <TargetMachine>MachineX86</TargetMachine>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;CRYPT_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n      <CallingConvention>StdCall</CallingConvention>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <ModuleDefinitionFile>Crypt.def</ModuleDefinitionFile>\r\n      <GenerateDebugInformation>false</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <TargetMachine>MachineX86</TargetMachine>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"Crypt.cpp\" />\r\n    <ClCompile Include=\"LoginEncryption.cpp\" />\r\n    <ClCompile Include=\"MemFinder.cpp\" />\r\n    <ClCompile Include=\"OldStatusBar.cpp\" />\r\n    <ClCompile Include=\"OSIEncryption.cpp\" />\r\n    <ClCompile Include=\"PacketInfo.cpp\" />\r\n    <ClCompile Include=\"stdafx.cpp\" />\r\n    <ClCompile Include=\"twofish.c\" />\r\n    <ClCompile Include=\"uo_huffman.cpp\" />\r\n    <ClCompile Include=\"UOArt.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"Crypt.h\" />\r\n    <ClInclude Include=\"debug.h\" />\r\n    <ClInclude Include=\"LoginEncryption.h\" />\r\n    <ClInclude Include=\"MemFinder.h\" />\r\n    <ClInclude Include=\"OSIEncryption.h\" />\r\n    <ClInclude Include=\"PacketInfo.h\" />\r\n    <ClInclude Include=\"platform.h\" />\r\n    <ClInclude Include=\"resource.h\" />\r\n    <ClInclude Include=\"stdafx.h\" />\r\n    <ClInclude Include=\"table.h\" />\r\n    <ClInclude Include=\"twofish.h\" />\r\n    <ClInclude Include=\"uo_huffman.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"Crypt.def\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\Razor\\Razor.csproj\">\r\n      <Project>{b24e4fb1-4936-4544-9e88-f3ff9b04fdba}</Project>\r\n      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"App.ico\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"Crypt.rc\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "Crypt/Crypt.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"Crypt.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"LoginEncryption.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"MemFinder.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"OldStatusBar.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"OSIEncryption.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"PacketInfo.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"stdafx.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"twofish.c\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"uo_huffman.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"UOArt.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"Crypt.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"debug.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"LoginEncryption.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"MemFinder.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"OSIEncryption.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"PacketInfo.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"platform.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"resource.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"stdafx.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"table.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"twofish.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"uo_huffman.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"Crypt.def\">\r\n      <Filter>Source Files</Filter>\r\n    </None>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"App.ico\">\r\n      <Filter>Resource Files</Filter>\r\n    </Image>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"Crypt.rc\">\r\n      <Filter>Resource Files</Filter>\r\n    </ResourceCompile>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "Crypt/LoginEncryption.cpp",
    "content": "#include \"stdafx.h\"\r\n\r\n#include \"Crypt.h\"\r\n#include \"LoginEncryption.h\"\r\n\r\n#define N2L(C, LL) \\\r\n    LL  = ((unsigned int)(*((C)++))) << 24, \\\r\n    LL |= ((unsigned int)(*((C)++))) << 16, \\\r\n    LL |= ((unsigned int)(*((C)++))) << 8, \\\r\n    LL |= ((unsigned int)(*((C)++)))\r\n\r\nDWORD zero = 0;\r\n\r\nconst DWORD *LoginEncryption::Key1 = &zero;\r\nconst DWORD *LoginEncryption::Key2 = &zero;\r\n\r\nLoginEncryption::LoginEncryption()\r\n{\r\n\tm_Table[0] = m_Table[1] = 0;\r\n}\r\n\r\nvoid LoginEncryption::SetKeys( const DWORD *k1, const DWORD *k2 )\r\n{\r\n\t//LoginEncryption::StaticKey1  = *((DWORD*)sk1);\r\n\tLoginEncryption::Key1 = k1;\r\n\tLoginEncryption::Key2 = k2;\r\n}\r\n\r\nvoid LoginEncryption::Initialize( const BYTE *pSeed )\r\n{\r\n\tDWORD seed;\r\n    N2L(pSeed, seed);\r\n\r\n\t/*char temp[256];\r\n\tsprintf( temp, \"Key1 = %08x, Key2 = %08x\", *Key1, *Key2 );\r\n\tMessageBox( NULL, temp, \"Keys\", MB_OK );*/\r\n\r\n    m_Table[0] = (((~seed) ^ 0x00001357) << 16) | ((seed ^ 0xffffaaaa) & 0x0000ffff);\r\n    m_Table[1] = ((seed ^ 0x43210000) >> 16) | (((~seed) ^ 0xabcdffff) & 0xffff0000);\r\n}\r\n\r\nvoid LoginEncryption::Encrypt( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tfor (int i=0;i<len;i++)\r\n\t\tout[i] = Crypt( in[i] );\r\n}\r\n\r\nvoid LoginEncryption::Decrypt( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tfor (int i=0;i<len;i++)\r\n\t\tout[i] = Crypt( in[i] );\r\n}\r\n\r\nBYTE LoginEncryption::Crypt( BYTE in )\r\n{\r\n\t//m_Table[1] = (((((pt1 >> 1) | (pt0 << 31)) ^ LOGIN_KEY_1) >> 1) | (pt0<<31)) ^ LOGIN_KEY_1;\r\n\t//m_Table[0] = ((pt0 >> 1) | (pt1 << 31)) ^ LOGIN_KEY_2;\r\n\t\r\n\tBYTE out = in ^ ((unsigned char)m_Table[0]);\r\n\r\n\tDWORD OldT1 = m_Table[1];\r\n\tm_Table[1] = ((((m_Table[1] >> 1) | (m_Table[0] << 31)) ^ ((*Key1)-1)) >> 1 | (m_Table[0] << 31)) ^ (*Key1);\r\n\tm_Table[0] = ((m_Table[0]>>1) | (OldT1<<31)) ^ (*Key2);\r\n\t\r\n\treturn out;\r\n}\r\n\r\nbool LoginEncryption::TestForLogin( BYTE encrypted )\r\n{\r\n\treturn IsLoginByte( (BYTE)( encrypted ^ ((BYTE)m_Table[0]) ) );\r\n}\r\n\r\nbool LoginEncryption::IsLoginByte( BYTE unencrypted )\r\n{\r\n\treturn unencrypted == ((BYTE)0x80) || unencrypted == ((BYTE)0x48);\r\n}\r\n\r\nDWORD LoginEncryption::GenerateBadSeed( DWORD oldSeed )\r\n{\r\n\tDWORD newSeed = (*Key1) ^ (*Key2);\r\n\tnewSeed = ((newSeed >> 24) & 0xFF) | ((newSeed >> 8) & 0xFF00) | ((newSeed << 8) & 0xFF0000) | ((newSeed << 24) & 0xFF000000);\r\n\treturn htonl( newSeed ^ htonl( oldSeed ) );\r\n}\r\n"
  },
  {
    "path": "Crypt/LoginEncryption.h",
    "content": "#pragma once\r\n\r\nclass LoginEncryption\r\n{\r\npublic:\r\n\tLoginEncryption();\r\n\r\n\tvoid Initialize( const BYTE *pSeed );\r\n\r\n\tstatic void SetKeys( const DWORD *k1, const DWORD *k2 );\r\n\r\n\tvoid Encrypt( const BYTE *in, BYTE *out, int len );\r\n\tvoid Decrypt( const BYTE *in, BYTE *out, int len );\r\n\r\n\tbool TestForLogin( BYTE encrypted );\r\n\r\n\tstatic DWORD GenerateBadSeed( DWORD oldSeed );\r\n\r\n\tstatic bool IsLoginByte( BYTE unencrypted );\r\n\r\nprivate:\r\n\tstatic const DWORD *Key1, *Key2;\r\n\r\n\tBYTE Crypt( BYTE );\r\n\r\n\tDWORD m_Table[2];\r\n};\r\n\r\n"
  },
  {
    "path": "Crypt/MemFinder.cpp",
    "content": "#include \"stdafx.h\"\r\n#include \"MemFinder.h\"\r\n\r\nDWORD MemFinder::Find(const void *data, int length, DWORD addressHint, DWORD addressMax)\r\n{\r\n\tfor (DWORD addr = addressHint; addr < addressMax; addr++)\r\n\t{\r\n\t\tif (IsBadReadPtr((void*)addr, length)) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\t__try\r\n\t\t{\r\n\t\t\tif (memcmp((const void*)addr, data, length) == 0)\r\n\t\t\t\treturn addr;\r\n\t\t}\r\n\t\t__except (EXCEPTION_ACCESS_VIOLATION)\r\n\t\t{\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t}\r\n\r\n\treturn 0;\r\n}\r\n\r\nMemFinder::MemFinder()\r\n{\r\n\tClear();\r\n}\r\n\r\nMemFinder::~MemFinder()\r\n{\r\n\tClear();\r\n}\r\n\r\nvoid MemFinder::Clear()\r\n{\r\n\t_Executed = false;\r\n\t_StartPos = 0xFFFFFFFF;\r\n\r\n\tfor (unsigned int i = 0; i<_Entries.size(); i++)\r\n\t\tdelete[] _Entries[i].Data;\r\n\r\n\t_Entries.clear();\r\n}\r\n\r\n\r\nvoid MemFinder::AddEntry(const void *data, int length, unsigned int maxResults, DWORD hint)\r\n{\r\n\tEntry ent;\r\n\r\n\tent.Data = new char[length];\r\n\tmemcpy(ent.Data, data, length);\r\n\r\n\tent.Length = length;\r\n\tent.MaxResults = maxResults;\r\n\tent.PositionHint = hint;\r\n\r\n\tif (hint < _StartPos)\r\n\t\t_StartPos = hint;\r\n\r\n\t_Entries.push_back(ent);\r\n}\r\n\r\nDWORD MemFinder::GetAddress(const void *data, int length, unsigned int idx)\r\n{\r\n\tif (!_Executed)\r\n\t\treturn 0;\r\n\r\n\tfor (unsigned int i = 0; i < _Entries.size(); i++)\r\n\t{\r\n\t\tif (_Entries[i].Length != length)\r\n\t\t\tcontinue;\r\n\r\n\t\tif (!memcmp(data, _Entries[i].Data, length))\r\n\t\t{\r\n\t\t\tif (idx < _Entries[i].Results.size())\r\n\t\t\t\treturn _Entries[i].Results[idx];\r\n\t\t\telse\r\n\t\t\t\treturn 0;\r\n\t\t}\r\n\t}\r\n\r\n\treturn 0;\r\n}\r\n\r\nvoid MemFinder::Execute()\r\n{\r\n\tbool allDone = false;\r\n\tfor (DWORD pos = _StartPos; pos < 0x02000000 && !allDone; pos++)\r\n\t{\r\n\t\t__try\r\n\t\t{\r\n\t\t\tallDone = true;\r\n\t\t\tfor (unsigned int i = 0; i < _Entries.size(); i++)\r\n\t\t\t{\r\n\t\t\t\tEntry &e = _Entries[i];\r\n\r\n\t\t\t\tif (e.Results.size() >= e.MaxResults) {\r\n\t\t\t\t\t/* Already found this entry */\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (IsBadReadPtr((void*)pos, e.Length)) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tallDone = false;\r\n\r\n\t\t\t\tif (e.PositionHint > pos) {\r\n\t\t\t\t\t/* This entry always appears in memory after this position */\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!memcmp((void*)pos, e.Data, e.Length)) {\r\n\t\t\t\t\te.Results.push_back(pos);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\t__except (EXCEPTION_ACCESS_VIOLATION)\r\n\t\t{\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\t_Executed = true;\r\n}\r\n\r\n"
  },
  {
    "path": "Crypt/MemFinder.h",
    "content": "#pragma pack(1)\r\n#pragma once\r\n\r\n#include <vector>\r\nusing std::vector;\r\n\r\nclass MemFinder\r\n{\r\npublic:\r\n\tstatic DWORD Find( const void *data, int length, DWORD hint = 0x00400000, DWORD addressMax = 0x01000000 );\r\n\r\n\tMemFinder();\r\n\t~MemFinder();\r\n\r\n\tvoid AddEntry( const void *data, int length, unsigned int maxResults, DWORD hint );\r\n\tvoid AddEntry( const void *data, int length, DWORD hint = 0x00400000 ) { AddEntry( data, length, 1, hint ); }\r\n\r\n\tDWORD GetAddress( const void *data, int length, unsigned int idx = 0 );\r\n\r\n\tvoid Execute();\r\n\r\n\tvoid Clear();\r\n\r\nprivate:\r\n\tstruct Entry\r\n\t{\r\n\t\tchar *Data;\r\n\t\tint Length;\r\n\t\tDWORD PositionHint;\r\n\t\tunsigned int MaxResults;\r\n\t\tvector<DWORD> Results;\r\n\t};\r\n\r\n\tvector<Entry> _Entries;\r\n\tbool _Executed;\r\n\tDWORD _StartPos;\r\n};\r\n"
  },
  {
    "path": "Crypt/OSIEncryption.cpp",
    "content": "#include \"stdafx.h\"\r\n\r\n#include \"Crypt.h\"\r\n#include \"OSIEncryption.h\"\r\n#include \"TwoFish.h\"\r\n\r\nOSIEncryption::OSIEncryption()\r\n{\r\n\tmemset( &m_Key, 0, sizeof(m_Key) );\r\n\tmemset( &m_Cipher, 0, sizeof(m_Cipher) );\r\n\tmemset( m_TFTable, 0, 256 );\r\n\tmemset( m_XORTable, 0, 16 );\r\n\r\n\tLog( \"XT: %X\", m_XORTable );\r\n\r\n\tm_XORPos = m_TFPos = 0;\r\n}\r\n\r\nvoid OSIEncryption::Initialize( DWORD Seed )\r\n{\r\n\tmemset( &m_Key, 0, sizeof(m_Key) );\r\n\tmemset( &m_Cipher, 0, sizeof(m_Cipher) );\r\n\tmemset( m_TFTable, 0, 256 );\r\n\r\n\tmakeKey( &m_Key, DIR_DECRYPT, 0x80, NULL );\r\n\tm_Key.key32[0] = m_Key.key32[1] = m_Key.key32[2] = m_Key.key32[3] = Seed;\r\n\treKey( &m_Key );\r\n\tcipherInit( &m_Cipher, MODE_ECB, NULL );\r\n\tfor(int i=0;i<256;i++)\r\n\t\tm_TFTable[i] = i;\r\n\tReinitTFTable();\r\n\r\n\tMD5( m_TFTable, 256, m_XORTable );\r\n\tm_XORPos = 0;\r\n}\r\n\r\nvoid OSIEncryption::ReinitTFTable()\r\n{\r\n\tunsigned char tmpBuff[256];\r\n\tblockEncrypt( &m_Cipher, &m_Key, m_TFTable, 256*8, tmpBuff );\r\n\tmemcpy( m_TFTable, tmpBuff, 256 );\r\n\tm_TFPos = 0;\r\n}\r\n\r\nvoid OSIEncryption::Hash( BYTE *field, const BYTE *param )\r\n{\r\n\tunsigned int a = *((unsigned int *)(field +  0));\r\n\tunsigned int b = *((unsigned int *)(field +  4));\r\n\tunsigned int c = *((unsigned int *)(field +  8));\r\n\tunsigned int d = *((unsigned int *)(field + 12));\r\n\r\n\ta = ((b & c) | (~b & d)) + *((unsigned int *)(param + 0x00)) + a - 0x28955B88;\r\n\ta = ((a << 0x07) | (a >> 0x19)) + b;\r\n\td = ((a & b) | (~a & c)) + *((unsigned int *)(param + 0x04)) + d - 0x173848AA;\r\n\td = ((d << 0x0c) | (d >> 0x14)) + a;\r\n\tc = ((d & a) | (~d & b)) + *((unsigned int *)(param + 0x08)) + c + 0x242070DB;\r\n\tc = ((c << 0x11) | (c >> 0x0f)) + d;\r\n\tb = ((c & d) | (~c & a)) + *((unsigned int *)(param + 0x0c)) + b - 0x3E423112;\r\n\tb = ((b << 0x16) | (b >> 0x0a)) + c;\r\n\ta = ((b & c) | (~b & d)) + *((unsigned int *)(param + 0x10)) + a - 0x0A83F051;\r\n\ta = ((a << 0x07) | (a >> 0x19)) + b;\r\n\td = ((a & b) | (~a & c)) + *((unsigned int *)(param + 0x14)) + d + 0x4787C62A;\r\n\td = ((d << 0x0c) | (d >> 0x14)) + a;\r\n\tc = ((d & a) | (~d & b)) + *((unsigned int *)(param + 0x18)) + c - 0x57CFB9ED;\r\n\tc = ((c << 0x11) | (c >> 0x0f)) + d;\r\n\tb = ((c & d) | (~c & a)) + *((unsigned int *)(param + 0x1c)) + b - 0x02B96AFF;\r\n\tb = ((b << 0x16) | (b >> 0x0a)) + c;\r\n\ta = ((b & c) | (~b & d)) + *((unsigned int *)(param + 0x20)) + a + 0x698098D8;\r\n\ta = ((a << 0x07) | (a >> 0x19)) + b;\r\n\td = ((a & b) | (~a & c)) + *((unsigned int *)(param + 0x24)) + d - 0x74BB0851;\r\n\td = ((d << 0x0c) | (d >> 0x14)) + a;\r\n\tc = ((d & a) | (~d & b)) + *((unsigned int *)(param + 0x28)) + c - 0x0000A44F;\r\n\tc = ((c << 0x11) | (c >> 0x0f)) + d;\r\n\tb = ((c & d) | (~c & a)) + *((unsigned int *)(param + 0x2C)) + b - 0x76A32842;\r\n\tb = ((b << 0x16) | (b >> 0x0a)) + c;\r\n\ta = ((b & c) | (~b & d)) + *((unsigned int *)(param + 0x30)) + a + 0x6B901122;\r\n\ta = ((a << 0x07) | (a >> 0x19)) + b;\r\n\td = ((a & b) | (~a & c)) + *((unsigned int *)(param + 0x34)) + d - 0x02678E6D;\r\n\td = ((d << 0x0c) | (d >> 0x14)) + a;\r\n\tc = ((d & a) | (~d & b)) + *((unsigned int *)(param + 0x38)) + c - 0x5986BC72;\r\n\tc = ((c << 0x11) | (c >> 0x0f)) + d;\r\n\tb = ((c & d) | (~c & a)) + *((unsigned int *)(param + 0x3c)) + b + 0x49B40821;\r\n\tb = ((b << 0x16) | (b >> 0x0a)) + c;\r\n\r\n\ta = ((b & d) | (~d & c)) + *((unsigned int *)(param + 0x04)) + a - 0x09E1DA9E;\r\n\ta = ((a << 0x05) | (a >> 0x1b)) + b;\r\n\td = ((a & c) | (~c & b)) + *((unsigned int *)(param + 0x18)) + d - 0x3FBF4CC0;\r\n\td = ((d << 0x09) | (d >> 0x17)) + a;\r\n\tc = ((d & b) | (~b & a)) + *((unsigned int *)(param + 0x2c)) + c + 0x265E5A51;\r\n\tc = ((c << 0x0e) | (c >> 0x12)) + d;\r\n\tb = ((c & a) | (~a & d)) + *((unsigned int *)(param + 0x00)) + b - 0x16493856;\r\n\tb = ((b << 0x14) | (b >> 0x0c)) + c;\r\n\ta = ((b & d) | (~d & c)) + *((unsigned int *)(param + 0x14)) + a - 0x29D0EFA3;\r\n\ta = ((a << 0x05) | (a >> 0x1b)) + b;\r\n\td = ((a & c) | (~c & b)) + *((unsigned int *)(param + 0x28)) + d + 0x02441453;\r\n\td = ((d << 0x09) | (d >> 0x17)) + a;\r\n\tc = ((d & b) | (~b & a)) + *((unsigned int *)(param + 0x3c)) + c - 0x275E197F;\r\n\tc = ((c << 0x0e) | (c >> 0x12)) + d;\r\n\tb = ((c & a) | (~a & d)) + *((unsigned int *)(param + 0x10)) + b - 0x182C0438;\r\n\tb = ((b << 0x14) | (b >> 0x0c)) + c;\r\n\ta = ((b & d) | (~d & c)) + *((unsigned int *)(param + 0x24)) + a + 0x21E1CDE6;\r\n\ta = ((a << 0x05) | (a >> 0x1b)) + b;\r\n\td = ((a & c) | (~c & b)) + *((unsigned int *)(param + 0x38)) + d - 0x3CC8F82A;\r\n\td = ((d << 0x09) | (d >> 0x17)) + a;\r\n\tc = ((d & b) | (~b & a)) + *((unsigned int *)(param + 0x0c)) + c - 0x0B2AF279;\r\n\tc = ((c << 0x0e) | (c >> 0x12)) + d;\r\n\tb = ((c & a) | (~a & d)) + *((unsigned int *)(param + 0x20)) + b + 0x455A14ED;\r\n\tb = ((b << 0x14) | (b >> 0x0c)) + c;\r\n\ta = ((b & d) | (~d & c)) + *((unsigned int *)(param + 0x34)) + a - 0x561C16FB;\r\n\ta = ((a << 0x05) | (a >> 0x1b)) + b;\r\n\td = ((a & c) | (~c & b)) + *((unsigned int *)(param + 0x08)) + d - 0x03105C08;\r\n\td = ((d << 0x09) | (d >> 0x17)) + a;\r\n\tc = ((d & b) | (~b & a)) + *((unsigned int *)(param + 0x1c)) + c + 0x676F02D9;\r\n\tc = ((c << 0x0e) | (c >> 0x12)) + d;\r\n\tb = ((c & a) | (~a & d)) + *((unsigned int *)(param + 0x30)) + b - 0x72D5B376;\r\n\tb = ((b << 0x14) | (b >> 0x0c)) + c;\r\n\r\n\ta = (b ^ c ^ d) + *((unsigned int *)(param + 0x14)) + a - 0x0005C6BE;\r\n\ta = ((a << 0x04) | (a >> 0x1c)) + b;\r\n\td = (a ^ b ^ c) + *((unsigned int *)(param + 0x20)) + d - 0x788E097F;\r\n\td = ((d << 0x0b) | (d >> 0x15)) + a;\r\n\tc = (d ^ a ^ b) + *((unsigned int *)(param + 0x2c)) + c + 0x6D9D6122;\r\n\tc = ((c << 0x10) | (c >> 0x10)) + d;\r\n\tb = (c ^ d ^ a) + *((unsigned int *)(param + 0x38)) + b - 0x021AC7F4;\r\n\tb = ((b << 0x17) | (b >> 0x09)) + c;\r\n\ta = (b ^ c ^ d) + *((unsigned int *)(param + 0x04)) + a - 0x5B4115BC;\r\n\ta = ((a << 0x04) | (a >> 0x1c)) + b;\r\n\td = (a ^ b ^ c) + *((unsigned int *)(param + 0x10)) + d + 0x4BDECFA9;\r\n\td = ((d << 0x0b) | (d >> 0x15)) + a;\r\n\tc = (d ^ a ^ b) + *((unsigned int *)(param + 0x1c)) + c - 0x0944B4A0;\r\n\tc = ((c << 0x10) | (c >> 0x10)) + d;\r\n\tb = (c ^ d ^ a) + *((unsigned int *)(param + 0x28)) + b - 0x41404390;\r\n\tb = ((b << 0x17) | (b >> 0x09)) + c;\r\n\ta = (b ^ c ^ d) + *((unsigned int *)(param + 0x34)) + a + 0x289B7EC6;\r\n\ta = ((a << 0x04) | (a >> 0x1c)) + b;\r\n\td = (a ^ b ^ c) + *((unsigned int *)(param + 0x00)) + d - 0x155ED806;\r\n\td = ((d << 0x0b) | (d >> 0x15)) + a;\r\n\tc = (d ^ a ^ b) + *((unsigned int *)(param + 0x0c)) + c - 0x2B10CF7B;\r\n\tc = ((c << 0x10) | (c >> 0x10)) + d;\r\n\tb = (c ^ d ^ a) + *((unsigned int *)(param + 0x18)) + b + 0x04881D05;\r\n\tb = ((b << 0x17) | (b >> 0x09)) + c;\r\n\ta = (b ^ c ^ d) + *((unsigned int *)(param + 0x24)) + a - 0x262B2FC7;\r\n\ta = ((a << 0x04) | (a >> 0x1c)) + b;\r\n\td = (a ^ b ^ c) + *((unsigned int *)(param + 0x30)) + d - 0x1924661B;\r\n\td = ((d << 0x0b) | (d >> 0x15)) + a;\r\n\tc = (d ^ a ^ b) + *((unsigned int *)(param + 0x3c)) + c + 0x1fa27cf8;\r\n\tc = ((c << 0x10) | (c >> 0x10)) + d;\r\n\tb = (c ^ d ^ a) + *((unsigned int *)(param + 0x08)) + b - 0x3B53A99B;\r\n\tb = ((b << 0x17) | (b >> 0x09)) + c;\r\n\r\n\ta = ((~d | b) ^ c)  + *((unsigned int *)(param + 0x00)) + a - 0x0BD6DDBC;\r\n\ta = ((a << 0x06) | (a >> 0x1a)) + b; \r\n\td = ((~c | a) ^ b)  + *((unsigned int *)(param + 0x1c)) + d + 0x432AFF97;\r\n\td = ((d << 0x0a) | (d >> 0x16)) + a; \r\n\tc = ((~b | d) ^ a)  + *((unsigned int *)(param + 0x38)) + c - 0x546BDC59;\r\n\tc = ((c << 0x0f) | (c >> 0x11)) + d; \r\n\tb = ((~a | c) ^ d)  + *((unsigned int *)(param + 0x14)) + b - 0x036C5FC7;\r\n\tb = ((b << 0x15) | (b >> 0x0b)) + c; \r\n\ta = ((~d | b) ^ c)  + *((unsigned int *)(param + 0x30)) + a + 0x655B59C3;\r\n\ta = ((a << 0x06) | (a >> 0x1a)) + b; \r\n\td = ((~c | a) ^ b)  + *((unsigned int *)(param + 0x0C)) + d - 0x70F3336E;\r\n\td = ((d << 0x0a) | (d >> 0x16)) + a; \r\n\tc = ((~b | d) ^ a)  + *((unsigned int *)(param + 0x28)) + c - 0x00100B83;\r\n\tc = ((c << 0x0f) | (c >> 0x11)) + d; \r\n\tb = ((~a | c) ^ d)  + *((unsigned int *)(param + 0x04)) + b - 0x7A7BA22F;\r\n\tb = ((b << 0x15) | (b >> 0x0b)) + c; \r\n\ta = ((~d | b) ^ c)  + *((unsigned int *)(param + 0x20)) + a + 0x6FA87E4F;\r\n\ta = ((a << 0x06) | (a >> 0x1a)) + b; \r\n\td = ((~c | a) ^ b)  + *((unsigned int *)(param + 0x3c)) + d - 0x01D31920;\r\n\td = ((d << 0x0a) | (d >> 0x16)) + a; \r\n\tc = ((~b | d) ^ a)  + *((unsigned int *)(param + 0x18)) + c - 0x5CFEBCEC;\r\n\tc = ((c << 0x0f) | (c >> 0x11)) + d; \r\n\tb = ((~a | c) ^ d)  + *((unsigned int *)(param + 0x34)) + b + 0x4E0811A1;\r\n\tb = ((b << 0x15) | (b >> 0x0b)) + c; \r\n\ta = ((~d | b) ^ c)  + *((unsigned int *)(param + 0x10)) + a - 0x08AC817E;\r\n\ta = ((a << 0x06) | (a >> 0x1a)) + b; \r\n\td = ((~c | a) ^ b)  + *((unsigned int *)(param + 0x2c)) + d - 0x42C50DCB;\r\n\td = ((d << 0x0a) | (d >> 0x16)) + a; \r\n\tc = ((~b | d) ^ a)  + *((unsigned int *)(param + 0x08)) + c + 0x2AD7D2BB;\r\n\tc = ((c << 0x0f) | (c >> 0x11)) + d; \r\n\tb = ((~a | c) ^ d)  + *((unsigned int *)(param + 0x24)) + b - 0x14792C6F;\r\n\tb = ((b << 0x15) | (b >> 0x0b)) + c;\r\n\r\n\t*((unsigned int *)(field +  0)) += a;\r\n\t*((unsigned int *)(field +  4)) += b;\r\n\t*((unsigned int *)(field +  8)) += c;\r\n\t*((unsigned int *)(field + 12)) += d;\r\n}\r\n\r\nvoid OSIEncryption::CallHash( BYTE *key, const BYTE *challenge, unsigned int len )\r\n{\r\n\tunsigned int *ptr1, *ptr2;\r\n\tunsigned int a, b, c;\r\n\r\n\tptr1 = (unsigned int *)(key + 16);\r\n\tptr2 = (unsigned int *)(key + 20);\r\n\r\n\ta = *ptr1;\r\n\tb = (a >> 3) & 0x3f;\r\n\ta += len * 8;\r\n\t*ptr1 = a;\r\n\r\n\tif ( a < (len << 3) )\r\n\t\tptr2 += 4;\r\n\r\n\t*ptr2 = *ptr2 + (len >> 0x1d);\r\n\r\n\ta = 64 - b;\r\n\tc = 0;\r\n\r\n\tif ( a <= len )\r\n\t{\r\n\t\tmemcpy( key + b + 24, challenge, a );\r\n\t\tHash( key, key + 24 );\r\n\r\n\t\tc = a;\r\n\t\ta += 0x3F;\r\n\r\n\t\twhile ( a < len )\r\n\t\t{\r\n\t\t\tHash( key, challenge + a - 0x3f );\r\n\t\t\ta += 64;\r\n\t\t\tc += 64;\r\n\t\t}\r\n\r\n\t\tb = 0;\r\n\t}\r\n\r\n\tmemcpy( key + b + 24, challenge + c, len - c );\r\n}\r\n\r\nvoid OSIEncryption::CalcResponse( BYTE *result, BYTE *field )\r\n{\r\n\tBYTE buf1[0x80];\r\n\tBYTE buf2[0x80];\r\n\tint i;\r\n\r\n\tmemset( buf1, 0, 0x80 );\r\n\r\n\t*buf1 = 0x80;\r\n\r\n\tmemcpy( buf2, field + 16, 8 );\r\n\r\n\ti = ( int(*((unsigned int *)(buf2))) >> 3 ) & 0x3f;\r\n\r\n\tif ( i < 56 )\r\n\t\ti = 56 - i;\r\n\telse\r\n\t\ti = 120 - i;\r\n\r\n\tCallHash( field, buf1, i );\r\n\tCallHash( field, buf2, 8 );\r\n\r\n\tmemcpy( result, field, 16 );\r\n}\r\n\r\nvoid OSIEncryption::MD5( const BYTE *input, int inLen, BYTE *output )\r\n{\r\n\tBYTE field[0x80];\r\n\r\n\tmemset( field, 0, 0x80 );\r\n\r\n\tfield[0x0] = 0x01;\r\n\tfield[0x1] = 0x23;\r\n\tfield[0x2] = 0x45;\r\n\tfield[0x3] = 0x67;\r\n\tfield[0x4] = 0x89;\r\n\tfield[0x5] = 0xAB;\r\n\tfield[0x6] = 0xCD;\r\n\tfield[0x7] = 0xEF;\r\n\tfield[0x8] = 0xFE;\r\n\tfield[0x9] = 0xDC;\r\n\tfield[0xA] = 0xBA;\r\n\tfield[0xB] = 0x98;\r\n\tfield[0xC] = 0x76;\r\n\tfield[0xD] = 0x54;\r\n\tfield[0xE] = 0x32;\r\n\tfield[0xF] = 0x10;\r\n\r\n\tCallHash( field, input, inLen );\r\n\tCalcResponse( output, field );\r\n}\r\n\r\n//going TO the client uses rotating XOR, going FROM the client uses TwoFish\r\n\r\nvoid OSIEncryption::XORCrypt( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tfor (int i=0;i<len;i++)\r\n\t{\r\n\t\tout[i] = in[i] ^ m_XORTable[m_XORPos%16];\r\n\t\tm_XORPos++;\r\n\t}\r\n}\r\n\r\nvoid OSIEncryption::TwoFishCrypt( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tfor(int i=0;i<len;i++)\r\n\t{\r\n\t\tif( m_TFPos >= 256 )\r\n\t\t\tReinitTFTable();\r\n\t\tout[i] = in[i] ^ m_TFTable[m_TFPos++];\r\n\t}\r\n}\r\n\r\n//server -> us\r\nvoid OSIEncryption::DecryptFromServer( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tXORCrypt( in, out, len );\r\n}\r\n\r\n//us -> client\r\nvoid OSIEncryption::EncryptForClient( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tXORCrypt( in, out, len );\r\n}\r\n\r\n//us -> server\r\nvoid OSIEncryption::EncryptForServer( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tTwoFishCrypt( in, out, len );\r\n}\r\n\r\n//client -> us\r\nvoid OSIEncryption::DecryptFromClient( const BYTE *in, BYTE *out, int len )\r\n{\r\n\tTwoFishCrypt( in, out, len );\r\n}\r\n\r\n\r\n"
  },
  {
    "path": "Crypt/OSIEncryption.h",
    "content": "#pragma once\r\n\r\n#include \"TwoFish.h\"\r\n\r\nclass OSIEncryption\r\n{\r\npublic:\r\n\tOSIEncryption();\r\n\r\n\tvoid Initialize( DWORD dwSeed );\r\n\r\n\tvoid DecryptFromServer( const BYTE *in, BYTE *out, int len );\r\n\tvoid DecryptFromClient( const BYTE *in, BYTE *out, int len );\r\n\r\n\tvoid EncryptForServer( const BYTE *in, BYTE *out, int len );\r\n\tvoid EncryptForClient( const BYTE *in, BYTE *out, int len );\r\n\r\n\tstatic void MD5( const BYTE *input, int inLen, BYTE *output );\r\n\r\nprivate:\r\n\tvoid TwoFishCrypt( const BYTE *in, BYTE *out, int len );\r\n\tvoid ReinitTFTable();\r\n\r\n\tvoid XORCrypt( const BYTE *in, BYTE *out, int len );\r\n\tvoid InitializeXORTable( const BYTE* data, int dataLen );\r\n\tstatic void Hash( BYTE *field, const BYTE *param );\r\n\tstatic void CallHash( BYTE *key, const BYTE *challenge, unsigned int len );\r\n\tstatic void CalcResponse( BYTE *result, BYTE *field );\r\n\r\n\tkeyInstance m_Key; \r\n\tcipherInstance m_Cipher; \r\n\tunsigned int m_TFPos;\r\n\tunsigned char m_XORPos;\r\n\tBYTE m_TFTable[256];\r\n\tBYTE m_XORTable[16];\r\n};\r\n\r\n"
  },
  {
    "path": "Crypt/OldStatusBar.cpp",
    "content": "#include \"StdAfx.h\"\r\n#include \"Crypt.h\"\r\n#include \"MemFinder.h\"\r\n\r\nDWORD GumpOutV28( DWORD OutFuncAddr, int esiOff, char TwoFourOff, DWORD CurAddr, int x, int y )\r\n{\r\n\tint count = 0;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8D\\x44\\x24\\x20\", 4 ); // lea    eax, [esp+70h+var_50]\r\n\tcount += 4;\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x50\", 1 ); // push    eax\r\n\tcount ++;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8B\\x46\", 2 ); // mov    eax, [esi+24h]\r\n\tcount += 2;\r\n\t*((unsigned char*)(CurAddr+count)) = 0x24+TwoFourOff;//+esiOff;\r\n\tcount ++;\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x50\", 1 ); // push    eax\r\n\tcount ++;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8B\\x56\", 2 ); // mov     edx, [esi+44h]\r\n\tcount += 2;\r\n\t*((unsigned char*)(CurAddr+count)) = 0x44+esiOff;\r\n\tcount ++;\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8B\\x42\\x14\", 3 ); // mov     eax, [edx+14h]\r\n\tcount += 3;\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x83\\xC0\\x04\", 3 ); // add     eax, 4\r\n\tcount += 3;\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x50\", 1 ); // push    eax\r\n\tcount ++;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8D\\x44\\x24\\x54\", 4 ); // lea    eax, [esp+7Ch+var_28]\r\n\tcount += 4;\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x50\", 1 ); // push    eax\r\n\tcount ++;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x68\\x86\\x03\\x00\\x00\", 5 ); // push    386h\r\n\tcount += 5;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x6A\\x01\", 2 ); // push    1\r\n\tcount += 2;\r\n\r\n\t// push    y\r\n\tif ( y < 0x80 )\r\n\t{\r\n\t\t*((unsigned char*)(CurAddr+count)) = 0x6A;\r\n\t\tcount ++;\r\n\t\t*((unsigned char*)(CurAddr+count)) = (unsigned char)y;\r\n\t\tcount ++;\r\n\t}\r\n\telse\r\n\t{\r\n\t\t*((unsigned char*)(CurAddr+count)) = 0x68;\r\n\t\tcount ++;\r\n\t\t*((int*)(CurAddr+count)) = y;\r\n\t\tcount += 4;\r\n\t}\r\n\r\n\t// push    x\r\n\tif ( x < 0x80 )\r\n\t{\r\n\t\t*((unsigned char*)(CurAddr+count)) = 0x6A;\r\n\t\tcount ++;\r\n\t\t*((unsigned char*)(CurAddr+count)) = (unsigned char)x;\r\n\t\tcount ++;\r\n\t}\r\n\telse\r\n\t{\r\n\t\t*((unsigned char*)(CurAddr+count)) = 0x68;\r\n\t\tcount ++;\r\n\t\t*((int*)(CurAddr+count)) = x;\r\n\t\tcount += 4;\r\n\t}\r\n\r\n\t// call theFunction\r\n\t*((unsigned char*)(CurAddr+count)) = 0xE8;\r\n\tcount ++;\r\n\t*((int*)(CurAddr+count)) = OutFuncAddr - (CurAddr+count+4);\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x83\\xC4\\x20\", 3 ); // add    esp, 20h\r\n\tcount += 3;\r\n\r\n\treturn count;\r\n}\r\n\r\nDWORD Sprintf1UV28( DWORD sprintfAddr, DWORD fmtAddr, DWORD CurAddr, int esiOffset )\r\n{\r\n\tint count = 0;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x33\\xC9\", 2 ); // xor     ecx, ecx\r\n\tcount += 2;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8D\\x54\\x24\\x48\", 4 ); // lea     edx, [esp+70h+var_28]\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x66\\x8B\\x8E\", 3 ); // mov     cx, [esi+___]\r\n\tcount += 3;\r\n\t*((int*)(CurAddr+count)) = esiOffset;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x51\", 1 ); // push    ecx\r\n\tcount ++;\r\n\r\n\t// push offset fmtAddr\r\n\t*((unsigned char*)(CurAddr+count)) = 0x68;\r\n\tcount ++;\r\n\t*((int*)(CurAddr+count)) = fmtAddr;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x52\", 1 ); // push    edx\r\n\tcount ++;\r\n\r\n\t// call    _sprintf\r\n\t*((unsigned char*)(CurAddr+count)) = 0xE8;\r\n\tcount ++;\r\n\t*((int*)(CurAddr+count)) = sprintfAddr - (CurAddr+count+4);\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x83\\xC4\\x0C\", 3 ); // add    esp, 0Ch\r\n\tcount += 3;\r\n\r\n\treturn count;\r\n}\r\n\r\nDWORD Sprintf2UV28_Byte( DWORD sprintfAddr, DWORD fmtAddr, DWORD CurAddr, int offset1, int offset2 )\r\n{\r\n\tint count = 0;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x33\\xC0\", 2 ); // xor     eax, eax\r\n\tcount += 2;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8A\\x86\", 2 ); // mov     al, [esi+___]\r\n\tcount += 2;\r\n\t*((int*)(CurAddr+count)) = offset2;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x50\", 1 ); // push    eax\r\n\tcount ++;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x33\\xC9\", 2 ); // xor     ecx, ecx\r\n\tcount += 2;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8D\\x54\\x24\\x4C\", 4 ); // lea     edx, [esp+70h+var_28]\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8A\\x8E\", 2 ); // mov     cl, [esi+___]\r\n\tcount += 2;\r\n\t*((int*)(CurAddr+count)) = offset1;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x51\", 1 ); // push    ecx\r\n\tcount ++;\r\n\r\n\t// push offset fmtAddr\r\n\t*((unsigned char*)(CurAddr+count)) = 0x68;\r\n\tcount ++;\r\n\t*((int*)(CurAddr+count)) = fmtAddr;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x52\", 1 ); // push    edx\r\n\tcount ++;\r\n\r\n\t// call    _sprintf\r\n\t*((unsigned char*)(CurAddr+count)) = 0xE8;\r\n\tcount ++;\r\n\t*((int*)(CurAddr+count)) = sprintfAddr - (CurAddr+count+4);\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x83\\xC4\\x10\", 3 ); // add    esp, 10h\r\n\tcount += 3;\r\n\r\n\treturn count;\r\n}\r\n\r\nDWORD Sprintf2UV28( DWORD sprintfAddr, DWORD fmtAddr, DWORD CurAddr, int offset1, int offset2 )\r\n{\r\n\tint count = 0;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x33\\xC0\", 2 ); // xor     eax, eax\r\n\tcount += 2;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x66\\x8B\\x86\", 3 ); // mov     ax, [esi+___]\r\n\tcount += 3;\r\n\t*((int*)(CurAddr+count)) = offset2;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x50\", 1 ); // push    eax\r\n\tcount ++;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x33\\xC9\", 2 ); // xor     ecx, ecx\r\n\tcount += 2;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x8D\\x54\\x24\\x4C\", 4 ); // lea     edx, [esp+70h+var_28]\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x66\\x8B\\x8E\", 3 ); // mov     cx, [esi+___]\r\n\tcount += 3;\r\n\t*((int*)(CurAddr+count)) = offset1;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x51\", 1 ); // push    ecx\r\n\tcount ++;\r\n\r\n\t// push offset fmtAddr\r\n\t*((unsigned char*)(CurAddr+count)) = 0x68;\r\n\tcount ++;\r\n\t*((int*)(CurAddr+count)) = fmtAddr;\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x52\", 1 ); // push    edx\r\n\tcount ++;\r\n\r\n\t// call    _sprintf\r\n\t*((unsigned char*)(CurAddr+count)) = 0xE8;\r\n\tcount ++;\r\n\t*((int*)(CurAddr+count)) = sprintfAddr - (CurAddr+count+4);\r\n\tcount += 4;\r\n\r\n\tmemcpy( (void*)(CurAddr+count), \"\\x83\\xC4\\x10\", 3 ); // add    esp, 10h\r\n\tcount += 3;\r\n\r\n\treturn count;\r\n}\r\n\r\n/*#define STATCODE_BEG \"\\x8D\\x54\\x24\\x48\\x8B\\xC3\\x2B\\xD3\\x8A\\x08\\x88\\x0C\\x02\\x40\\x84\\xC9\\x75\\xF6\"\r\n#define STATCODE_B_LEN 18\r\n#define STATCODE_START_OFF (STATCODE_B_LEN+0x15)\r\n#define STACK_OFFSET -3\r\n#define STACK_BASE 0x28\r\n*/\r\n#define STATCODE_BEG \"\\x68\\x86\\x03\\x00\\x00\\x6A\\x01\\x6A\\x32\\x6A\\x28\\xE8\"\r\n#define STATCODE_B_LEN 12\r\n#define STATCODE_START_OFF (-0x1E)\r\n#define STACK_OFFSET 6\r\n#define STACK_BASE 0x28\r\n\r\n#define STATCODE_END \"\\x51\\x52\\x68\\x86\\x03\\x00\\x00\\x6A\\x01\\x68\\x8F\\x00\\x00\\x00\\x00\"\r\n#define STATCODE_E_LEN 14\r\n#define STATCODE_END_OFFSET 9\r\n\r\n#define GUMP_STRING1 \"\\x53\\x55\\x8B\\x6C\\x24\\x1C\\x56\\x57\\x8B\\xFD\\x83\\xC9\\xFF\\x33\\xC0\\xF2\"\r\n#define GS1_LEN 16\r\n#define GS1_OFFSET 0x29\r\n\r\n#define GID_REPL \"\\x6C\\x2A\\x00\\x00\"\r\n#define GID_R_LEN 4\r\n\r\n#define SPRINTF_STR \"\\x55\\x8B\\xEC\\x83\\xEC\\x20\\x8B\\x45\\x08\\x56\\x89\\x45\\xE8\\x89\\x45\\xE0\\x8D\\x45\\x10\\xC7\\x45\\xEC\\x42\\x00\\x00\\x00\\x50\\x8D\\x45\\xE0\\xFF\\x75\\x0C\\xC7\\x45\\xE4\\xFF\\xFF\\xFF\\x7F\\x50\\xE8\"\r\n#define SPRINTF_LEN 42\r\n\r\n#define LOCK_STR_1 \"\\x6A\\x4E\\x6A\\x28\"\r\n#define LOCK_STR_2 \"\\x6A\\x69\\x6A\\x28\"\r\n#define LOCK_STR_3 \"\\x68\\x85\\x00\\x00\\x00\\x6A\\x28\"\r\n#define LOCK_LEN_1 4\r\n#define LOCK_LEN_2 4\r\n#define LOCK_LEN_3 7\r\n\r\n#define MIN_STR \"\\x68\\xA8\\x00\\x00\\x00\\x68\\x98\\x01\\x00\\x00\\x68\\x92\\x00\\x00\\x00\\x68\\x81\\x01\\x00\\x00\"\r\n#define MIN_STR_LEN 20\r\n\r\nvector<PatchInfo *> *PatchVec = NULL;\r\nbool PatchStatusBar( BOOL preAOS )\r\n{\r\n\tif ( !preAOS )\r\n\t{\r\n\t\tif ( PatchVec == NULL )\r\n\t\t\treturn true;\r\n\r\n\t\tfor(unsigned int i=0;i<PatchVec->size();i++)\r\n\t\t{\r\n\t\t\tPatchInfo *patch = (*PatchVec)[i];\r\n\t\t\tMemoryPatch( patch->Address, patch->Data, patch->Length );\r\n\t\t\tdelete patch;\r\n\t\t}\r\n\t\tdelete PatchVec;\r\n\t\tPatchVec = NULL;\r\n\t\treturn true;\r\n\t}\r\n\r\n\tif ( PatchVec != NULL )\r\n\t\treturn true;\r\n\r\n\tconst unsigned int NewGumpID = 0x00000802;\r\n\r\n\tMemFinder mf;\r\n\r\n\tmf.AddEntry( GUMP_STRING1, GS1_LEN );\r\n\tmf.AddEntry( \"%u/%u\", 6 );\r\n\tmf.AddEntry( MIN_STR, MIN_STR_LEN );\r\n\tmf.AddEntry( STATCODE_BEG, STATCODE_B_LEN );\r\n\tmf.AddEntry( SPRINTF_STR, SPRINTF_LEN );\r\n\tmf.AddEntry( LOCK_STR_1, LOCK_LEN_1 );\r\n\tmf.AddEntry( GID_REPL, GID_R_LEN );\r\n\r\n\tmf.Execute();\r\n\r\n\tDWORD GumpString1 = mf.GetAddress( GUMP_STRING1, GS1_LEN );\r\n\tif ( !GumpString1 ) \r\n\t\treturn false;\r\n\tGumpString1 -= GS1_OFFSET;\r\n\r\n\tDWORD uuFmt = mf.GetAddress( \"%u/%u\", 6 );\r\n\tif ( !uuFmt ) \r\n\t\treturn false;\r\n\tDWORD uFmt = uuFmt + 3;\r\n\r\n\tDWORD MinLoc = mf.GetAddress( MIN_STR, MIN_STR_LEN );\r\n\tif ( !MinLoc ) \r\n\t\treturn false;\r\n\tMinLoc += 1;\r\n\r\n\tDWORD Start = mf.GetAddress( STATCODE_BEG, STATCODE_B_LEN );\r\n\tif ( !Start ) \r\n\t\treturn false;\r\n\tStart += STATCODE_START_OFF;\r\n\r\n\tDWORD End = Start;\r\n\r\n\tdo {\r\n\t\tEnd = MemFinder::Find( STATCODE_END, STATCODE_E_LEN, End + 1 );\r\n\t} while ( End && *((unsigned char*)(End+STATCODE_E_LEN+1)) != 0xE8 );\r\n\r\n\tif ( !End )\r\n\t\treturn false;\r\n\r\n\tEnd += STATCODE_E_LEN + STATCODE_END_OFFSET;\r\n\r\n\tDWORD sprintfAddr = mf.GetAddress( SPRINTF_STR, SPRINTF_LEN );\r\n\tDWORD LockLoc = mf.GetAddress( LOCK_STR_1, LOCK_LEN_1 );\r\n\tDWORD CurPos = mf.GetAddress( GID_REPL, GID_R_LEN );\r\n\r\n\tif ( !( sprintfAddr && LockLoc && CurPos ) )\r\n\t\treturn false;\r\n\r\n\tPatchVec = new vector<PatchInfo*>();\r\n\r\n\tPatchVec->push_back( new PatchInfo( CurPos, 4 ) );\r\n\tMemoryPatch( CurPos, NewGumpID );\r\n\tCurPos = MemFinder::Find( GID_REPL, GID_R_LEN, CurPos+4 );\r\n\tif ( CurPos )\r\n\t{\r\n\t\tPatchVec->push_back( new PatchInfo( CurPos, 4 ) );\r\n\t\tMemoryPatch( CurPos, NewGumpID );\r\n\t}\r\n\r\n\tPatchVec->push_back( new PatchInfo( LockLoc+0x01, 1 ) );\r\n\tPatchVec->push_back( new PatchInfo( LockLoc+0x03, 1 ) );\r\n\tMemoryPatch( LockLoc+0x01, 0x3E, 1 );\r\n\tMemoryPatch( LockLoc+0x03, 0x26, 1 );\r\n\r\n\tLockLoc = MemFinder::Find( LOCK_STR_2, LOCK_LEN_2, LockLoc );\r\n\tif ( LockLoc )\r\n\t{\r\n\t\tPatchVec->push_back( new PatchInfo( LockLoc+0x01, 1 ) );\r\n\t\tPatchVec->push_back( new PatchInfo( LockLoc+0x03, 1 ) );\r\n\t\tMemoryPatch( LockLoc+0x01, 0x4A, 1 );\r\n\t\tMemoryPatch( LockLoc+0x03, 0x26, 1 );\r\n\r\n\t\tLockLoc = MemFinder::Find( LOCK_STR_3, LOCK_LEN_3, LockLoc );\r\n\t\tif ( LockLoc )\r\n\t\t{\r\n\t\t\tPatchVec->push_back( new PatchInfo( LockLoc+0x01, 4 ) );\r\n\t\t\tPatchVec->push_back( new PatchInfo( LockLoc+0x06, 1 ) );\r\n\t\t\tMemoryPatch( LockLoc+0x01, 0x56, 4 );\r\n\t\t\tMemoryPatch( LockLoc+0x06, 0x26, 1 );\r\n\t\t}\r\n\t}\r\n\r\n\tPatchVec->push_back( new PatchInfo( MinLoc+ 0, 4 ) );\r\n\tPatchVec->push_back( new PatchInfo( MinLoc+ 5, 4 ) );\r\n\tPatchVec->push_back( new PatchInfo( MinLoc+10, 4 ) );\r\n\tPatchVec->push_back( new PatchInfo( MinLoc+15, 4 ) );\r\n\tMemoryPatch( MinLoc+ 0, 137 );\r\n\tMemoryPatch( MinLoc+ 5, 263 );\r\n\tMemoryPatch( MinLoc+10, 111 );\r\n\tMemoryPatch( MinLoc+15, 239 );\r\n\r\n\tint len = End - Start;\r\n\r\n\tPatchVec->push_back( new PatchInfo( Start, len ) );\r\n\r\n\tDWORD OldProtect;\r\n\tif ( !VirtualProtect( (void *)(Start), len, PAGE_EXECUTE_READWRITE, &OldProtect ) )\r\n\t\treturn false;\r\n\r\n\tCurPos = Start;\r\n\r\n\tint statOffset = *((unsigned char*)(Start + 0x31 + 0x18 + 3));\r\n\tint esiOffset = statOffset - 0xD4;\r\n\tint stackChange = STACK_BASE - *((unsigned char*)(Start + STACK_OFFSET));\r\n\tint twoFourOff = *((unsigned char*)(Start + 0x31 + 2)) - 0x24;\r\n\r\n\tbool client5 = false;\r\n\tchar uuPush[5];\r\n\tuuPush[0] = 0x68;\r\n\t*((DWORD*)&uuPush[1]) = uuFmt;\r\n\r\n\tDWORD uuSP = MemFinder::Find( uuPush, 5, Start );\r\n\tif ( uuSP )\r\n\t\tclient5 = ( *((int*)(uuSP - 10)) != (statOffset + 0x1F) );\r\n\r\n\tif ( stackChange != 0  )\r\n\t{\r\n\t\tmemcpy( (void*)CurPos, \"\\x83\\xC4\", 2 ); // add    esp, __h\r\n\t\tCurPos += 2;\r\n\t\t*((char*)CurPos) = (char)stackChange;\r\n\t\tCurPos++;\r\n\t}\r\n\r\n\tif ( *((unsigned char*)(Start + 11)) != 0x46 ) // was reg is it in?\r\n\t{\r\n\t\tmemcpy( (void*)CurPos, \"\\x8B\\xF5\", 2 ); // mov     esi, ebp\r\n\t\tCurPos += 2;\r\n\t}\r\n\r\n\t// name\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 53 );\r\n\r\n\tif ( stackChange != 0  )\r\n\t{\r\n\t\tmemcpy( (void*)CurPos, \"\\x83\\xC4\", 2 ); // add    esp, __h\r\n\t\tCurPos += 2;\r\n\t\t*((char*)CurPos) = -stackChange;\r\n\t\tCurPos++;\r\n\t}\r\n\r\n\tmemset( (void*)CurPos, 0x90, (Start+0x31) - CurPos );\r\n\r\n\tCurPos = Start + 0x31 + 0x12;\r\n\r\n\tif ( stackChange != 0  )\r\n\t{\r\n\t\tmemcpy( (void*)CurPos, \"\\x83\\xC4\", 2 ); // add    esp, __h\r\n\t\tCurPos += 2;\r\n\t\t*((char*)CurPos) = (char)stackChange;\r\n\t\tCurPos++;\r\n\t}\r\n\r\n\tif ( *((unsigned char*)(Start + 11)) != 0x46 ) // was reg is it in?\r\n\t{\r\n\t\tmemcpy( (void*)CurPos, \"\\x8B\\xF5\", 2 ); // mov     esi, ebp\r\n\t\tCurPos += 2;\r\n\t}\r\n\r\n\t// str\r\n\tCurPos += Sprintf1UV28( sprintfAddr, uFmt, CurPos, statOffset+0x00 );\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 72 );\r\n\r\n\t// dex\r\n\tCurPos += Sprintf1UV28( sprintfAddr, uFmt, CurPos, statOffset+0x02 );\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 84 );\r\n\r\n\t// int\r\n\tCurPos += Sprintf1UV28( sprintfAddr, uFmt, CurPos, statOffset+0x04 );\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 96 );\r\n\r\n\t// sex?\r\n\t//memcpy( (void*)(CurPos), \"\\xC7\\x44\\x24\\x48Yes\", 8 ); // mov     [esp+70h+var_28], __\r\n\t//CurPos += 8;\r\n\t//CurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 108 );\r\n\r\n\t// followers:\r\n\tif ( client5 )\r\n\t{\r\n\t\tCurPos += Sprintf2UV28_Byte( sprintfAddr, uuFmt, CurPos, statOffset+2+0x1E, statOffset+2+0x1F );\r\n\t\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 108 );\r\n\t}\r\n\telse\r\n\t{\r\n\t\tCurPos += Sprintf2UV28_Byte( sprintfAddr, uuFmt, CurPos, statOffset+0x1E, statOffset+0x1F );\r\n\t\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 108 );\r\n\t}\r\n\r\n\t// AR\r\n\tif ( client5 )\r\n\t\tCurPos += Sprintf1UV28( sprintfAddr, uFmt, CurPos, statOffset+0x1C );\r\n\telse\r\n\t\tCurPos += Sprintf1UV28( sprintfAddr, uFmt, CurPos, statOffset+0x1A );\r\n\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 86, 120 );\r\n\r\n\t// hits\r\n\tCurPos += Sprintf2UV28( sprintfAddr, uuFmt, CurPos, statOffset+0x06, statOffset+0x08 );\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 174, 72 );\r\n\r\n\t// stam\r\n\tCurPos += Sprintf2UV28( sprintfAddr, uuFmt, CurPos, statOffset+0x0A, statOffset+0x0C );\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 174, 96 );\r\n\r\n\t// mana\r\n\tCurPos += Sprintf2UV28( sprintfAddr, uuFmt, CurPos, statOffset+0x0E, statOffset+0x10 );\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 174, 84 );\r\n\r\n\t// gold\r\n\tCurPos += Sprintf1UV28( sprintfAddr, uFmt, CurPos, statOffset+0x14 );\r\n\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 174, 108 );\r\n\r\n\tif ( client5 )\r\n\t{\r\n\t\tCurPos += Sprintf2UV28( sprintfAddr, uuFmt, CurPos, statOffset+0x18, statOffset+0x1A );\r\n\t\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 174, 120 );\r\n\t}\r\n\telse\r\n\t{\r\n\t\t// Weight:\r\n\t\tmemcpy( (void*)CurPos, \"\\x33\\xC9\", 2 ); // xor     ecx, ecx\r\n\t\tCurPos += 2;\r\n\t\tmemcpy( (void*)CurPos, \"\\x66\\x8B\\x8E\", 3 ); // mov     cx, [esi+___]\r\n\t\tCurPos += 3;\r\n\t\t*((int*)CurPos) = statOffset+0x00; // str\r\n\t\tCurPos += 4;\r\n\t\tmemcpy( (void*)CurPos, \"\\x8D\\x04\\xCD\\x00\\x00\\x00\\x00\\x2B\\xC1\\x99\\x2B\\xC2\\xD1\\xF8\\x83\\xC0\\x28\", 17 ); // eax = ecx*3.5 + 40\r\n\t\tCurPos += 17;\r\n\t\tmemcpy( (void*)CurPos, \"\\x50\", 1 ); // push    eax\r\n\t\tCurPos ++;\r\n\r\n\t\tmemcpy( (void*)CurPos, \"\\x33\\xC9\", 2 ); // xor     ecx, ecx\r\n\t\tCurPos += 2;\r\n\t\tmemcpy( (void*)CurPos, \"\\x8D\\x54\\x24\\x4C\", 4 ); // lea     edx, [esp+74h+var_28]\r\n\t\tCurPos += 4;\r\n\t\tmemcpy( (void*)CurPos, \"\\x66\\x8B\\x8E\", 3 ); // mov     cx, [esi+___]\r\n\t\tCurPos += 3;\r\n\t\t*((int*)CurPos) = statOffset+0x18; // weight\r\n\t\tCurPos += 4;\r\n\t\tmemcpy( (void*)CurPos, \"\\x51\", 1 ); // push    ecx\r\n\t\tCurPos ++;\r\n\r\n\t\t// push offset fmtAddr\r\n\t\t*((unsigned char*)CurPos) = 0x68;\r\n\t\tCurPos ++;\r\n\t\t*((int*)CurPos) = uuFmt;\r\n\t\tCurPos += 4;\r\n\r\n\t\tmemcpy( (void*)CurPos, \"\\x52\", 1 ); // push    edx\r\n\t\tCurPos ++;\r\n\r\n\t\t// call    _sprintf\r\n\t\t*((unsigned char*)CurPos) = 0xE8;\r\n\t\tCurPos ++;\r\n\t\t*((int*)CurPos) = sprintfAddr - (CurPos+4);\r\n\t\tCurPos += 4;\r\n\r\n\t\tmemcpy( (void*)CurPos, \"\\x83\\xC4\\x10\", 3 ); // add    esp, 10h\r\n\t\tCurPos += 3;\r\n\r\n\t\tCurPos += GumpOutV28( GumpString1, esiOffset, twoFourOff, CurPos, 174, 120 );\r\n\t}\r\n\r\n\tif ( stackChange != 0  )\r\n\t{\r\n\t\tmemcpy( (void*)CurPos, \"\\x83\\xC4\", 2 ); // add    esp, __h\r\n\t\tCurPos += 2;\r\n\t\t*((char*)CurPos) = -stackChange;\r\n\t\tCurPos++;\r\n\t}\r\n\r\n\tmemset( (void*)CurPos, 0x90, End-CurPos );\r\n\r\n\tVirtualProtect( (void *)(Start), len, OldProtect, &OldProtect );\r\n\r\n\treturn true;\r\n}\r\n\r\n"
  },
  {
    "path": "Crypt/PacketInfo.cpp",
    "content": "#include \"stdafx.h\"\r\n#include \"Crypt.h\"\r\n\r\n#include \"PacketInfo.h\"\r\n\r\nDLLFUNCTION int GetPacketLength( unsigned char *packet, int len )\r\n{\r\n\tif ( pShared != NULL )\r\n\t{\r\n\t\tint packetLen = pShared->PacketTable[(unsigned char)packet[0]];\r\n\r\n\t\tif ( packetLen >= 0x4000 )\r\n\t\t{\r\n\t\t\tif ( len < 3 )\r\n\t\t\t\treturn 0;\r\n\t\t\telse\r\n\t\t\t\treturn packet[1]<<8 | packet[2];\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\treturn packetLen;\r\n\t\t}\r\n\t}\r\n\telse if ( len >= 3 )\r\n\t{\r\n\t\t//attempt to auto detect an undefined packet\r\n\t\treturn packet[1]<<8 | packet[2];\r\n\t}\r\n\telse\r\n\t{\r\n\t\treturn -1;\r\n\t}\r\n}\r\n\r\nDLLFUNCTION bool IsDynLength( BYTE packet )\r\n{\r\n\tif ( pShared != NULL )\r\n\t\treturn pShared->PacketTable[packet] >= 0x8000;\r\n\telse\r\n\t\treturn true;\r\n}\r\n"
  },
  {
    "path": "Crypt/PacketInfo.h",
    "content": "#pragma once\r\n#pragma pack(1)\r\n\r\nstruct ClientPacketInfo // 12 bytes\r\n{\r\n\tint Id;\r\n\tint Unk;\r\n\tunsigned short Length;\r\n\tshort Unk0000;\r\n};\r\n\r\nconst unsigned short StaticPacketTable[] =\r\n{\r\n\t0x0068, // 0x00\r\n\t0x0005, // 0x01\r\n\t0x0007, // 0x02\r\n\t0x8000, // 0x03\r\n\t0x0002, // 0x04\r\n\t0x0005, // 0x05\r\n\t0x0005, // 0x06\r\n\t0x0007, // 0x07\r\n\t0x000F, // 0x08\r\n\t0x0005, // 0x09\r\n\t0x000B, // 0x0A\r\n\t0x0007, // 0x0B\r\n\t0x8000, // 0x0C\r\n\t0x0003, // 0x0D\r\n\t0x8000, // 0x0E\r\n\t0x003D, // 0x0F\r\n\t0x00D7, // 0x10\r\n\t0x8000, // 0x11\r\n\t0x8000, // 0x12\r\n\t0x000A, // 0x13\r\n\t0x0006, // 0x14\r\n\t0x0009, // 0x15\r\n\t0x8000, // 0x16\r\n\t0x8000, // 0x17\r\n\t0x8000, // 0x18\r\n\t0x8000, // 0x19\r\n\t0x8000, // 0x1A\r\n\t0x0025, // 0x1B\r\n\t0x8000, // 0x1C\r\n\t0x0005, // 0x1D\r\n\t0x0004, // 0x1E\r\n\t0x0008, // 0x1F\r\n\t0x0013, // 0x20\r\n\t0x0008, // 0x21\r\n\t0x0003, // 0x22\r\n\t0x001A, // 0x23\r\n\t0x0007, // 0x24\r\n\t0x0015, // 0x25\r\n\t0x0005, // 0x26\r\n\t0x0002, // 0x27\r\n\t0x0005, // 0x28\r\n\t0x0001, // 0x29\r\n\t0x0005, // 0x2A\r\n\t0x0002, // 0x2B\r\n\t0x0002, // 0x2C\r\n\t0x0011, // 0x2D\r\n\t0x000F, // 0x2E\r\n\t0x000A, // 0x2F\r\n\t0x0005, // 0x30\r\n\t0x8000, // 0x31\r\n\t0x0002, // 0x32\r\n\t0x0002, // 0x33\r\n\t0x000A, // 0x34\r\n\t0x028D, // 0x35\r\n\t0x8000, // 0x36\r\n\t0x0008, // 0x37\r\n\t0x0007, // 0x38\r\n\t0x0009, // 0x39\r\n\t0x8000, // 0x3A\r\n\t0x8000, // 0x3B\r\n\t0x8000, // 0x3C\r\n\t0x0002, // 0x3D\r\n\t0x0025, // 0x3E\r\n\t0x8000, // 0x3F\r\n\t0x00C9, // 0x40\r\n\t0x8000, // 0x41\r\n\t0x8000, // 0x42\r\n\t0x0229, // 0x43\r\n\t0x02C9, // 0x44\r\n\t0x0005, // 0x45\r\n\t0x8000, // 0x46\r\n\t0x000B, // 0x47\r\n\t0x0049, // 0x48\r\n\t0x005D, // 0x49\r\n\t0x0005, // 0x4A\r\n\t0x0009, // 0x4B\r\n\t0x8000, // 0x4C\r\n\t0x8000, // 0x4D\r\n\t0x0006, // 0x4E\r\n\t0x0002, // 0x4F\r\n\t0x8000, // 0x50\r\n\t0x8000, // 0x51\r\n\t0x8000, // 0x52\r\n\t0x0002, // 0x53\r\n\t0x000C, // 0x54\r\n\t0x0001, // 0x55\r\n\t0x000B, // 0x56\r\n\t0x006E, // 0x57\r\n\t0x006A, // 0x58\r\n\t0x8000, // 0x59\r\n\t0x8000, // 0x5A\r\n\t0x0004, // 0x5B\r\n\t0x0002, // 0x5C\r\n\t0x0049, // 0x5D\r\n\t0x8000, // 0x5E\r\n\t0x0031, // 0x5F\r\n\t0x0005, // 0x60\r\n\t0x0009, // 0x61\r\n\t0x000F, // 0x62\r\n\t0x000D, // 0x63\r\n\t0x0001, // 0x64\r\n\t0x0004, // 0x65\r\n\t0x8000, // 0x66\r\n\t0x0015, // 0x67\r\n\t0x8000, // 0x68\r\n\t0x8000, // 0x69\r\n\t0x0003, // 0x6A\r\n\t0x0009, // 0x6B\r\n\t0x0013, // 0x6C\r\n\t0x0003, // 0x6D\r\n\t0x000E, // 0x6E\r\n\t0x8000, // 0x6F\r\n\t0x001C, // 0x70\r\n\t0x8000, // 0x71\r\n\t0x0005, // 0x72\r\n\t0x0002, // 0x73\r\n\t0x8000, // 0x74\r\n\t0x0023, // 0x75\r\n\t0x0010, // 0x76\r\n\t0x0011, // 0x77\r\n\t0x8000, // 0x78\r\n\t0x0009, // 0x79\r\n\t0x8000, // 0x7A\r\n\t0x0002, // 0x7B\r\n\t0x8000, // 0x7C\r\n\t0x000D, // 0x7D\r\n\t0x0002, // 0x7E\r\n\t0x8000, // 0x7F\r\n\t0x003E, // 0x80\r\n\t0x8000, // 0x81\r\n\t0x0002, // 0x82\r\n\t0x0027, // 0x83\r\n\t0x0045, // 0x84\r\n\t0x0002, // 0x85\r\n\t0x8000, // 0x86\r\n\t0x8000, // 0x87\r\n\t0x0042, // 0x88\r\n\t0x8000, // 0x89\r\n\t0x8000, // 0x8A\r\n\t0x8000, // 0x8B\r\n\t0x000B, // 0x8C\r\n\t0x8000, // 0x8D\r\n\t0x8000, // 0x8E\r\n\t0x8000, // 0x8F\r\n\t0x0013, // 0x90\r\n\t0x0041, // 0x91\r\n\t0x8000, // 0x92\r\n\t0x0063, // 0x93\r\n\t0x8000, // 0x94\r\n\t0x0009, // 0x95\r\n\t0x8000, // 0x96\r\n\t0x0002, // 0x97\r\n\t0x8000, // 0x98\r\n\t0x001A, // 0x99\r\n\t0x8000, // 0x9A\r\n\t0x0102, // 0x9B\r\n\t0x0135, // 0x9C\r\n\t0x0033, // 0x9D\r\n\t0x8000, // 0x9E\r\n\t0x8000, // 0x9F\r\n\t0x0003, // 0xA0\r\n\t0x0009, // 0xA1\r\n\t0x0009, // 0xA2\r\n\t0x0009, // 0xA3\r\n\t0x0095, // 0xA4\r\n\t0x8000, // 0xA5\r\n\t0x8000, // 0xA6\r\n\t0x0004, // 0xA7\r\n\t0x8000, // 0xA8\r\n\t0x8000, // 0xA9\r\n\t0x0005, // 0xAA\r\n\t0x8000, // 0xAB\r\n\t0x8000, // 0xAC\r\n\t0x8000, // 0xAD\r\n\t0x8000, // 0xAE\r\n\t0x000D, // 0xAF\r\n\t0x8000, // 0xB0\r\n\t0x8000, // 0xB1\r\n\t0x8000, // 0xB2\r\n\t0x8000, // 0xB3\r\n\t0x8000, // 0xB4\r\n\t0x0040, // 0xB5\r\n\t0x0009, // 0xB6\r\n\t0x8000, // 0xB7\r\n\t0x8000, // 0xB8\r\n\t0x0005, // 0xB9\r\n\t0x0006, // 0xBA\r\n\t0x0009, // 0xBB\r\n\t0x0003, // 0xBC\r\n\t0x8000, // 0xBD\r\n\t0x8000, // 0xBE\r\n\t0x8000, // 0xBF\r\n\t0x0024, // 0xC0\r\n\t0x8000, // 0xC1\r\n\t0x8000, // 0xC2\r\n\t0x8000, // 0xC3\r\n\t0x0006, // 0xC4\r\n\t0x00CB, // 0xC5\r\n\t0x0001, // 0xC6\r\n\t0x0031, // 0xC7\r\n\t0x0002, // 0xC8\r\n\t0x0006, // 0xC9\r\n\t0x0006, // 0xCA\r\n\t0x0007, // 0xCB\r\n\t0x8000, // 0xCC\r\n\t0x0001, // 0xCD\r\n\t0x8000, // 0xCE\r\n\t0x004E, // 0xCF\r\n\t0x8000, // 0xD0\r\n\t0x0002, // 0xD1\r\n\t0x0019, // 0xD2\r\n\t0x8000, // 0xD3\r\n\t0x8000, // 0xD4\r\n\t0x8000, // 0xD5\r\n\t0x8000, // 0xD6\r\n\t0x8000, // 0xD7\r\n\t0x8000, // 0xD8\r\n\t0x010C, // 0xD9\r\n\t0x8000, // 0xDA\r\n\t0x8000, // 0xDB\r\n\t0x0009, // 0xDC\r\n\t0x8000, // 0xDD\r\n\t0x8000, // 0xDE\r\n\t0x8000, // 0xDF\r\n\t0x8000, // 0xE0 \r\n\t0x8000, // 0xE1\r\n\t0x000A, // 0xE2\r\n\t0x8000, // 0xE3\r\n\t0x8000, // 0xE4\r\n\t0x8000, // 0xE5\r\n\t0x0005, // 0xE6\r\n\t0x000C, // 0xE7\r\n\t0x000D, // 0xE8\r\n\t0x004B, // 0xE9\r\n\t0x0003, // 0xEA\r\n\t0x8000, // 0xEB\r\n\t0x8000, // 0xEC\r\n\t0x8000, // 0xED\r\n\t0x8000, // 0xEE\r\n\t0x0015, // 0xEF\r\n\t0x8000, // 0xF0\r\n\t0x8000, // 0xF1\r\n\t0x8000, // 0xF2\r\n\t0x0018, // 0xF3\r\n\t0x8000, // 0xF4\r\n\t0x0015, // 0xF5\r\n\t0x8000, // 0xF6\r\n\t0x8000, // 0xF7\r\n\t0x006A, // 0xF8\r\n\t0x8000, // 0xF9\r\n\t0x8000, // 0xFA\r\n\t0x8000, // 0xFB\r\n\t0x8000, // 0xFC\r\n\t0x8000, // 0xFD\r\n\t0x0008, // 0xFE\r\n\t0x8000, // 0xFF\r\n};"
  },
  {
    "path": "Crypt/UOArt.cpp",
    "content": "#include \"stdafx.h\"\r\n#include \"Crypt.h\"\r\n#include \"Resource.h\"\r\n#include <uxtheme.h>\r\n#include <vssym32.h>\r\n#include <dwmapi.h>\r\n\r\n#define Color16to32(c16) (((c16) & 0x7C00) >> 7) | (((c16) & 0x3E0) << 6) | (((c16) & 0x1F) << 19)\r\n\r\nstruct UOItem\r\n{\r\n    int RealWidth;\r\n    int RealHeight;\r\n\r\n    int Left;\r\n    int Top;\r\n    int Bottom;\r\n    int Right;\r\n\r\n    int GetWidth() const { return Right - Left; }\r\n    int GetHeight() const { return Bottom - Top; }\r\n\r\n    unsigned short **Data; // [ReadlWidth][RealHeight] 32bit color data\r\n\r\n    int ItemID;\r\n    UOItem *pNext;\r\n};\r\n\r\nstruct ArtIdx\r\n{\r\n    long FilePos;\r\n    long Length;\r\n    long Unused;\r\n};\r\n\r\nstruct ArtHeader\r\n{\r\n    long Unknown;\r\n    short Width;\r\n    short Height;\r\n    //followed by short LookupTable\r\n};\r\n\r\nUOItem *ArtCache = NULL;\r\nunsigned short **Hues = NULL;\r\nint NumHues = 0;\r\n\r\ninline int Round(float n)\r\n{\r\n\tint i = (int)n;\r\n\treturn i + (n - i >= 0.5 ? 1 : 0);\r\n}\r\n\r\nunsigned short *GetHue(int index)\r\n{\r\n\tif (Hues == NULL)\r\n\t{\r\n\t\tif (!pShared)\r\n\t\t\treturn NULL;\r\n\r\n\t\tchar str[512];\r\n\t\tint length, blockCount, index;\r\n\t\tFILE *huesMul = NULL;\r\n\r\n\t\tWaitForSingleObject(CommMutex, INFINITE);\r\n\t\tsprintf(str, \"%s/hues.mul\", pShared->DataPath);\r\n\t\tReleaseMutex(CommMutex);\r\n\r\n\t\thuesMul = fopen(str, \"rb\");\r\n\t\tif (!huesMul)\r\n\t\t{\r\n\t\t\tHues = new unsigned short *[1];\r\n\t\t\tHues[0] = new unsigned short[34];\r\n\t\t\tmemset(Hues[0], 0, 34 * 2);\r\n\t\t\tNumHues = 1;\r\n\t\t\treturn NULL;\r\n\t\t}\r\n\r\n\t\tfseek(huesMul, 0, SEEK_END);\r\n\t\tlength = (int)ftell(huesMul);\r\n\t\tfseek(huesMul, 0, SEEK_SET);\r\n\t\tblockCount = length / 708;\r\n\t\tif (blockCount > 375)\r\n\t\t\tblockCount = 375;\r\n\t\tNumHues = blockCount * 8;\r\n\r\n\t\tHues = new unsigned short *[NumHues];\r\n\r\n\t\tindex = 0;\r\n\t\tfor (int b = 0; b < blockCount; b++)\r\n\t\t{\r\n\t\t\tfseek(huesMul, 4, SEEK_CUR);\r\n\r\n\t\t\tfor (int i = 0; i < 8; i++, index++)\r\n\t\t\t{\r\n\t\t\t\tHues[index] = new unsigned short[34];\r\n\t\t\t\tfor (int c = 0; c < 34; c++)\r\n\t\t\t\t{\r\n\t\t\t\t\tunsigned short color;\r\n\t\t\t\t\tfread(&color, 2, 1, huesMul);\r\n\t\t\t\t\tHues[index][c] = color | 0x8000;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfseek(huesMul, 20, SEEK_CUR); // ignore name\r\n\t\t\t}\r\n\t\t}\r\n\t\tfclose(huesMul);\r\n\t}\r\n\r\n\tif (index > 0 && index <= NumHues)\r\n\t\treturn Hues[index - 1];\r\n\telse\r\n\t\treturn NULL;\r\n}\r\n\r\nunsigned short ApplyHueToPixel(unsigned short *hue, unsigned short pix)\r\n{\r\n\tif (hue)\r\n\t\treturn hue[(pix >> 10) & 31];\r\n\telse\r\n\t\treturn pix;\r\n}\r\n\r\nUOItem *ReadUOItem(int item, int bh)\r\n{\r\n\tif (item == 0 || item >= 0xFFFF || !pShared)\r\n\t\treturn NULL;\r\n\r\n\tchar str[512];\r\n\tshort *Lookup;\r\n\tunsigned short *Run;\r\n\r\n\tFILE *idxMul, *artMul;\r\n\tArtIdx idx;\r\n\tArtHeader header;\r\n\tmemset(&header, 0, sizeof(ArtHeader));\r\n\r\n\tWaitForSingleObject(CommMutex, INFINITE);\r\n\tsprintf(str, \"%s/artidx.mul\", pShared->DataPath);\r\n\tReleaseMutex(CommMutex);\r\n\r\n\tidxMul = fopen(str, \"rb\");\r\n\tif (!idxMul)\r\n\t\treturn NULL;\r\n\tfseek(idxMul, item * sizeof(ArtIdx), SEEK_SET);\r\n\tfread(&idx, sizeof(ArtIdx), 1, idxMul);\r\n\tfclose(idxMul);\r\n\tif (idx.FilePos == -1 || idx.Length == -1)\r\n\t\treturn NULL;\r\n\r\n\tWaitForSingleObject(CommMutex, INFINITE);\r\n\tsprintf(str, \"%s/art.mul\", pShared->DataPath);\r\n\tReleaseMutex(CommMutex);\r\n\r\n\tartMul = fopen(str, \"rb\");\r\n\tif (!artMul)\r\n\t{\r\n\t\tfclose(idxMul);\r\n\t\treturn NULL;\r\n\t}\r\n\tfseek(artMul, idx.FilePos, SEEK_SET);\r\n\tfread(&header, sizeof(ArtHeader), 1, artMul);\r\n\tif (header.Height <= 0 || header.Width <= 0 || header.Height >= 1024 || header.Width >= 1024 || header.Unknown > 0xFFFF || header.Unknown == 0)\r\n\t{\r\n\t\tfclose(artMul);\r\n\t\treturn NULL;\r\n\t}\r\n\r\n\tRun = new unsigned short[header.Width]; // it should never be wider than the whole image!\r\n\tLookup = new short[header.Height];\r\n\tfread(Lookup, header.Height * 2, 1, artMul);\r\n\tlong dataStart = ftell(artMul);\r\n\r\n\tUOItem *pNew = new UOItem;\r\n\tpNew->ItemID = item;\r\n\tpNew->pNext = ArtCache;\r\n\tArtCache = pNew;\r\n\r\n\tunsigned short **Image = new unsigned short *[header.Width];\r\n\tfor (int i = 0; i < header.Width; i++)\r\n\t{\r\n\t\tImage[i] = new unsigned short[header.Height];\r\n\t\tmemset(Image[i], 0, header.Height * 2);\r\n\t}\r\n\r\n\tpNew->Left = pNew->Top = 0x7FFFFFFF;\r\n\tpNew->Right = pNew->Bottom = 0;\r\n\tfor (int y = 0; y < header.Height; y++)\r\n\t{\r\n\t\tint x = 0;\r\n\r\n\t\tfseek(artMul, dataStart + Lookup[y] * 2, SEEK_SET);\r\n\t\tdo\r\n\t\t{\r\n\t\t\tshort RunOffset = 0, RunLength = 0;\r\n\r\n\t\t\tfread(&RunOffset, 2, 1, artMul);\r\n\t\t\tfread(&RunLength, 2, 1, artMul);\r\n\r\n\t\t\tif (RunLength <= 0 || RunOffset < 0 || RunOffset + RunLength >= 2048 || RunLength > header.Width)\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tif (y > pNew->Bottom)\r\n\t\t\t\tpNew->Bottom = y;\r\n\t\t\tif (y < pNew->Top)\r\n\t\t\t\tpNew->Top = y;\r\n\r\n\t\t\tx += RunOffset;\r\n\t\t\tif (x < pNew->Left)\r\n\t\t\t\tpNew->Left = x;\r\n\r\n\t\t\tfread(Run, RunLength * 2, 1, artMul);\r\n\t\t\tfor (int o = 0; o < RunLength; o++, x++)\r\n\t\t\t\tImage[x][y] = Run[o];\r\n\r\n\t\t\tif (x > pNew->Right)\r\n\t\t\t\tpNew->Right = x;\r\n\t\t} while (true);\r\n\t}\r\n\tfclose(artMul);\r\n\r\n\tdelete[] Run;\r\n\tdelete[] Lookup;\r\n\r\n\tfloat scale = float(bh) / float(pNew->GetHeight());\r\n\tif (scale > 1 || scale <= 0)\r\n\t\tscale = 1;\r\n\r\n\tpNew->RealHeight = (int)(header.Height * scale + 1);\r\n\tpNew->RealWidth = (int)(header.Width * scale + 1);\r\n\tpNew->Data = new unsigned short *[pNew->RealWidth];\r\n\tfor (int x = 0; x < pNew->RealWidth; x++)\r\n\t{\r\n\t\tpNew->Data[x] = new unsigned short[pNew->RealHeight];\r\n\t\tmemset(pNew->Data[x], 0, 2 * pNew->RealHeight);\r\n\t}\r\n\r\n\tfor (int x = 0; x < header.Width; x++)\r\n\t{\r\n\t\tfor (int y = 0; y < header.Height; y++)\r\n\t\t\tpNew->Data[(int)(x * scale)][(int)(y * scale)] |= Image[x][y];\r\n\t}\r\n\r\n\tpNew->Top = (int)(pNew->Top * scale);\r\n\tpNew->Left = (int)(pNew->Left * scale);\r\n\tpNew->Bottom = (int)(pNew->Bottom * scale);\r\n\tpNew->Right = (int)(pNew->Right * scale);\r\n\r\n\tfor (int x = 0; x < header.Width; x++)\r\n\t\tdelete[] Image[x];\r\n\tdelete[] Image;\r\n\r\n\treturn pNew;\r\n}\r\n\r\nUOItem *FindItem(int item)\r\n{\r\n\tUOItem *node = ArtCache;\r\n\twhile (node != NULL)\r\n\t{\r\n\t\tif (node->ItemID == item)\r\n\t\t\treturn node;\r\n\t\telse\r\n\t\t\tnode = node->pNext;\r\n\t}\r\n\r\n\treturn NULL;\r\n}\r\n\r\ninline COLORREF Brightness(int shift, COLORREF c)\r\n{\r\n\treturn RGB(min(255, GetRValue(c) + shift), min(255, GetGValue(c) + shift), min(255, GetBValue(c) + shift));\r\n}\r\n\r\nint DrawUOItem(HDC hDC, RECT rect, int item, int hueIdx)\r\n{\r\n\titem |= 0x4000;\r\n\r\n\trect.top++;\r\n\trect.bottom--;\r\n\tint maxHeight = rect.bottom - rect.top;\r\n\r\n\tUOItem *i = FindItem(item);\r\n\tif (i == NULL)\r\n\t\ti = ReadUOItem(item, maxHeight);\r\n\r\n\tif (i == NULL)\r\n\t\treturn 0;\r\n\r\n\tif (i->GetHeight() < maxHeight)\r\n\t\trect.top += (maxHeight - i->GetHeight()) / 2;\r\n\r\n\tunsigned short *hue = GetHue(hueIdx);\r\n\tfor (int x = i->Left; x <= i->Right; x++)\r\n\t{\r\n\t\tfor (int y = i->Top; y <= i->Bottom; y++)\r\n\t\t{\r\n\t\t\tif (i->Data[x][y] != 0)\r\n\t\t\t\tSetPixel(hDC, rect.left + x - i->Left, rect.top + y - i->Top, Brightness(0x30, Color16to32(ApplyHueToPixel(hue, i->Data[x][y]))));\r\n\t\t}\r\n\t}\r\n\r\n\treturn i->GetWidth() + 3;\r\n}\r\n\r\nvoid FreeItem(UOItem *node)\r\n{\r\n\tif (node != NULL)\r\n\t{\r\n\t\tFreeItem(node->pNext);\r\n\t\tfor (int i = 0; i < node->RealWidth; i++)\r\n\t\t\tdelete[] node->Data[i];\r\n\t\tdelete[] node->Data;\r\n\t\tdelete node;\r\n\t}\r\n}\r\n\r\nvoid FreeArt()\r\n{\r\n\tFreeItem(ArtCache);\r\n\tif (Hues && NumHues > 0)\r\n\t{\r\n\t\tfor (int i = 0; i < NumHues; i++)\r\n\t\t\tdelete[] Hues[i];\r\n\t\tdelete[] Hues;\r\n\t}\r\n}\r\n\r\nint DrawUOItem(HDC, RECT, int, int);\r\n\r\ntypedef HTHEME(__stdcall *OPENTHEMEDATA)(HWND, LPCWSTR);\r\nOPENTHEMEDATA zOpenThemeData = NULL;\r\ntypedef HRESULT(__stdcall *DRAWTHEMEBACKGROUND)(HTHEME, HDC, int, int, const RECT *, OPTIONAL const RECT *);\r\nDRAWTHEMEBACKGROUND zDrawThemeBackground = NULL;\r\ntypedef HRESULT(__stdcall *CLOSETHEMEDATA)(HTHEME);\r\nCLOSETHEMEDATA zCloseThemeData = NULL;\r\ntypedef HRESULT(__stdcall *GETTHEMESYSFONT)(HTHEME, int, OUT LOGFONTW *);\r\nGETTHEMESYSFONT zGetThemeSysFont = NULL;\r\ntypedef COLORREF(__stdcall *GETTHEMESYSCOLOR)(HTHEME, int);\r\nGETTHEMESYSCOLOR zGetThemeSysColor = NULL;\r\ntypedef HRESULT(__stdcall *GETTHEMEMETRIC)(HTHEME, HDC, int, int, int, int *);\r\nGETTHEMEMETRIC zGetThemeMetric = NULL;\r\ntypedef HRESULT(__stdcall *DWMSETWINDOWATTRIBUTE)(HWND, DWORD, LPCVOID, DWORD);\r\nDWMSETWINDOWATTRIBUTE zDwmSetWindowAttribute = NULL;\r\nHMODULE hThemes = NULL;\r\nHMODULE hDwmApi = NULL;\r\n\r\nvoid InitThemes()\r\n{\r\n\thThemes = LoadLibrary(\"UXTHEME.DLL\");\r\n\tif (hThemes)\r\n\t{\r\n\t\tzOpenThemeData = (OPENTHEMEDATA)GetProcAddress(hThemes, \"OpenThemeData\");\r\n\t\tzDrawThemeBackground = (DRAWTHEMEBACKGROUND)GetProcAddress(hThemes, \"DrawThemeBackground\");\r\n\t\tzCloseThemeData = (CLOSETHEMEDATA)GetProcAddress(hThemes, \"CloseThemeData\");\r\n\t\tzGetThemeSysColor = (GETTHEMESYSCOLOR)GetProcAddress(hThemes, \"GetThemeSysColor\");\r\n\t\tzGetThemeSysFont = (GETTHEMESYSFONT)GetProcAddress(hThemes, \"GetThemeSysFont\");\r\n\t\tzGetThemeMetric = (GETTHEMEMETRIC)GetProcAddress(hThemes, \"GetThemeMetric\");\r\n\t}\r\n\r\n\thDwmApi = LoadLibrary(\"DWMAPI.DLL\");\r\n\tif (hDwmApi)\r\n\t{\r\n\t\tzDwmSetWindowAttribute = (DWMSETWINDOWATTRIBUTE)GetProcAddress(hDwmApi, \"DwmSetWindowAttribute\");\r\n\t}\r\n}\r\n\r\ninline int GetHex2(LPCSTR hex)\r\n{\r\n\tint num = 0;\r\n\tif (!isxdigit(hex[0]) || !isxdigit(hex[1]))\r\n\t\treturn -1;\r\n\r\n\tnum = isdigit(hex[1]) ? (hex[1] - '0') : (tolower(hex[1]) - 'a' + 10);\r\n\tnum += (isdigit(hex[0]) ? (hex[0] - '0') : (tolower(hex[0]) - 'a' + 10)) * 16;\r\n\r\n\treturn num;\r\n}\r\n\r\ninline int GetHex4(LPCSTR hex)\r\n{\r\n\treturn (GetHex2(hex) << 8) | GetHex2(&hex[2]);\r\n}\r\n\r\nvoid DoStat(HDC hDC, int v, int t, int l, int h, int w)\r\n{\r\n\tif (w <= 0)\r\n\t\treturn;\r\n\tRECT fill;\r\n\tfill.top = t;\r\n\tfill.left = l;\r\n\tfill.bottom = t + h;\r\n\tfill.right = l + w;\r\n\tHBRUSH hBr = NULL;\r\n\r\n\tif (v == 0xFF)                                //poisoned\r\n\t\thBr = CreateSolidBrush(RGB(255, 128, 0)); // orange\r\n\telse if (v <= 25)\r\n\t\thBr = CreateSolidBrush(RGB(255, 0, 0)); // red\r\n\telse if (v <= 75)\r\n\t\thBr = CreateSolidBrush(RGB(255, 255, 0)); // yellow\r\n\telse\r\n\t\thBr = CreateSolidBrush(RGB(0, 255, 0)); // green\r\n\r\n\tFillRect(hDC, &fill, hBr);\r\n\tDeleteObject(hBr);\r\n}\r\n\r\nint DrawStatBar(HDC hDC, RECT rect, int width, int status, int hp, int mn, int st)\r\n{\r\n\tHGDIOBJ hOld = NULL;\r\n\tPOINT pt[2];\r\n\trect.right = rect.left + width + 2;\r\n\r\n\tint o = (rect.bottom - rect.top - 20) / 2;\r\n\tif (o > 0)\r\n\t\trect.top += o;\r\n\trect.bottom = rect.top + 6 + 6 + 6 + 1;\r\n\r\n\thOld = SelectObject(hDC, GetStockObject(BLACK_PEN));\r\n\tFrameRect(hDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));\r\n\r\n\tpt[0].x = rect.left;\r\n\tpt[1].x = rect.right;\r\n\r\n\tpt[0].y = rect.top + 6;\r\n\tpt[1].y = rect.top + 6;\r\n\tPolyline(hDC, pt, 2);\r\n\r\n\tpt[0].y = rect.top + 6 + 6;\r\n\tpt[1].y = rect.top + 6 + 6;\r\n\tPolyline(hDC, pt, 2);\r\n\r\n\tif (status == 1) // poisoned\r\n\t\tDoStat(hDC, 0xFF, rect.top + 1, rect.left + 1, 5, (int)((double(hp + 1) / 100.0) * width));\r\n\telse\r\n\t\tDoStat(hDC, hp, rect.top + 1, rect.left + 1, 5, (int)((double(hp + 1) / 100.0) * width));\r\n\r\n\tDoStat(hDC, mn, rect.top + 1 + 6, rect.left + 1, 5, (int)((double(mn + 1) / 100) * width));\r\n\tDoStat(hDC, st, rect.top + 2 + 6 + 5, rect.left + 1, 5, (int)((double(st + 1) / 100) * width));\r\n\r\n\tSelectObject(hDC, hOld);\r\n\treturn width + 2;\r\n}\r\n\r\nvoid CheckTitlebarAttr(HWND hWnd)\r\n{\r\n\tstatic bool curNCRP = true;\r\n\tbool newNCRP = !pShared || pShared->TitleBar[0] == '\\0';\r\n\r\n\tif (curNCRP != newNCRP && zDwmSetWindowAttribute)\r\n\t{\r\n\t\tDWMNCRENDERINGPOLICY policy = newNCRP ? DWMNCRP_ENABLED : DWMNCRP_DISABLED;\r\n\t\tzDwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof(policy));\r\n\t\tcurNCRP = newNCRP;\r\n\t}\r\n}\r\n\r\nvoid DrawColorTitleBar(HTHEME hTheme, HWND hWnd, HDC hOutDC, bool active, bool maximized, LPCSTR str, int len, RECT orig)\r\n{\r\n\tconst COLORREF def = GetSysColor(active ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);\r\n\tCOLORREF color = def;\r\n\r\n\tRECT rect;\r\n\tRECT window;\r\n\tGetWindowRect(hWnd, &window);\r\n\trect.left = rect.top = 0;\r\n\trect.right = window.right - window.left;\r\n\trect.bottom = (orig.bottom - orig.top);\r\n\r\n\tHDC hDC = CreateCompatibleDC(hOutDC);\r\n\tHBITMAP hBmp = CreateCompatibleBitmap(hOutDC, rect.right, rect.bottom);\r\n\tSelectObject(hDC, hBmp);\r\n\r\n\tbool needRegFill = true;\r\n\tHFONT hFont = NULL;\r\n\r\n\tif (hThemes)\r\n\t{\r\n\t\tLOGFONTW lf;\r\n\r\n\t\tif (maximized)\r\n\t\t{\r\n\t\t\tneedRegFill = zDrawThemeBackground(hTheme, hDC, WP_MAXCAPTION, active ? MXCS_ACTIVE : MXCS_INACTIVE, &rect, NULL) != S_OK;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tint modTop = GetSystemMetrics(SM_CYFRAME);\r\n\t\t\trect.top -= modTop;\r\n\t\t\tneedRegFill = zDrawThemeBackground(hTheme, hDC, WP_CAPTION, active ? CS_ACTIVE : CS_INACTIVE, &rect, NULL) != S_OK;\r\n\t\t\trect.top += modTop;\r\n\t\t}\r\n\r\n\t\tif (zGetThemeSysFont(hTheme, TMT_CAPTIONFONT, &lf) == S_OK)\r\n\t\t{\r\n\t\t\thFont = CreateFontIndirectW(&lf);\r\n\t\t\tSelectObject(hDC, hFont);\r\n\t\t}\r\n\t}\r\n\r\n\tif (needRegFill)\r\n\t\tFillRect(hDC, &rect, GetSysColorBrush(active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));\r\n\r\n\tif (hFont == NULL)\r\n\t\tSelectObject(hDC, GetStockObject(ANSI_VAR_FONT));\r\n\r\n\trect.left = orig.left;\r\n\r\n\tint start = 0;\r\n\tint dlen = 0;\r\n\tint t;\r\n\tSetBkMode(hDC, TRANSPARENT);\r\n\tfor (int i = 0; i < len; i++)\r\n\t{\r\n\t\tif (rect.left >= rect.right)\r\n\t\t\tbreak;\r\n\r\n\t\tif (str[i] == '~')\r\n\t\t{\r\n\t\t\tswitch (str[i + 1])\r\n\t\t\t{\r\n\t\t\tcase '#':\r\n\t\t\t\tif (dlen > 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tSetTextColor(hDC, color);\r\n\t\t\t\t\tDrawText(hDC, &str[start], dlen, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);\r\n\t\t\t\t\tSIZE ext;\r\n\t\t\t\t\tGetTextExtentPoint32(hDC, &str[start], dlen, &ext);\r\n\t\t\t\t\trect.left += ext.cx;\r\n\t\t\t\t}\r\n\t\t\t\tdlen = 0;\r\n\r\n\t\t\t\tif (str[i + 2] == '~')\r\n\t\t\t\t{\r\n\t\t\t\t\tcolor = def;\r\n\t\t\t\t\tSetBkMode(hDC, TRANSPARENT);\r\n\t\t\t\t\tstart = i + 3;\r\n\t\t\t\t\ti += 2;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tcolor = RGB(GetHex2(&str[i + 2]), GetHex2(&str[i + 4]), GetHex2(&str[i + 6]));\r\n\t\t\t\t\tstart = i + 8;\r\n\t\t\t\t\ti += 7;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'S':\r\n\t\t\tcase 's':\r\n\t\t\t\t// ~SSFRRGGBB\r\n\t\t\t\tif (dlen > 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tSetTextColor(hDC, color);\r\n\t\t\t\t\tDrawText(hDC, &str[start], dlen, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);\r\n\t\t\t\t\tSIZE ext;\r\n\t\t\t\t\tGetTextExtentPoint32(hDC, &str[start], dlen, &ext);\r\n\t\t\t\t\trect.left += ext.cx;\r\n\t\t\t\t}\r\n\t\t\t\tdlen = 0;\r\n\r\n\t\t\t\tt = 30;\r\n\t\t\t\tswitch (toupper(str[i + 2]))\r\n\t\t\t\t{\r\n\t\t\t\tcase 'S':\r\n\t\t\t\t\tt = 15;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t\t//case 'R': w = 30; break;\r\n\t\t\t\tcase 'M':\r\n\t\t\t\t\tt = 45;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'L':\r\n\t\t\t\t\tt = 60;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase 'X':\r\n\t\t\t\t\tt = 75;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\trect.left += 1;\r\n\t\t\t\trect.left += DrawStatBar(hDC, rect, t, str[i + 3] - '0', GetHex2(&str[i + 4]), GetHex2(&str[i + 6]), GetHex2(&str[i + 8]));\r\n\t\t\t\trect.left += 1;\r\n\r\n\t\t\t\tstart = i + 10;\r\n\t\t\t\ti += 9;\r\n\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'I':\r\n\t\t\tcase 'i':\r\n\t\t\t\tif (dlen > 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tSetTextColor(hDC, color);\r\n\t\t\t\t\tDrawText(hDC, &str[start], dlen, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);\r\n\t\t\t\t\tSIZE ext;\r\n\t\t\t\t\tGetTextExtentPoint32(hDC, &str[start], dlen, &ext);\r\n\t\t\t\t\trect.left += ext.cx;\r\n\t\t\t\t}\r\n\t\t\t\tdlen = 0;\r\n\t\t\t\tif (str[i + 6] == '~')\r\n\t\t\t\t{\r\n\t\t\t\t\trect.left += DrawUOItem(hDC, rect, GetHex4(&str[i + 2]), 0);\r\n\t\t\t\t\tstart = i + 7;\r\n\t\t\t\t\ti += 6;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\trect.left += DrawUOItem(hDC, rect, GetHex4(&str[i + 2]), GetHex4(&str[i + 6]));\r\n\t\t\t\t\tstart = i + 10;\r\n\t\t\t\t\ti += 9;\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tcase '^':\r\n\t\t\t\tif (dlen > 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tSetTextColor(hDC, color);\r\n\t\t\t\t\tDrawText(hDC, &str[start], dlen, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);\r\n\t\t\t\t\tSIZE ext;\r\n\t\t\t\t\tGetTextExtentPoint32(hDC, &str[start], dlen, &ext);\r\n\t\t\t\t\trect.left += ext.cx;\r\n\t\t\t\t}\r\n\t\t\t\tdlen = 0;\r\n\r\n\t\t\t\tcolor = RGB(0, 0, 0);\r\n\t\t\t\tSetBkMode(hDC, OPAQUE);\r\n\t\t\t\tSetBkColor(hDC, RGB(GetHex2(&str[i + 2]), GetHex2(&str[i + 4]), GetHex2(&str[i + 6])));\r\n\r\n\t\t\t\tstart = i + 8;\r\n\t\t\t\ti += 7;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'B':\r\n\t\t\tcase 'b': // skip bold identifier\r\n\t\t\t\ti++;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tdlen++;\r\n\t\t}\r\n\t}\r\n\r\n\tif (dlen > 0)\r\n\t{\r\n\t\tSetTextColor(hDC, color);\r\n\t\tDrawText(hDC, &str[start], dlen, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);\r\n\t}\r\n\r\n\tBitBlt(hOutDC, orig.left, orig.top, (orig.right - orig.left), (orig.bottom - orig.top) - 1, hDC, orig.left, 0, SRCCOPY);\r\n\tDeleteDC(hDC);\r\n\tDeleteObject(hBmp);\r\n\tif (hFont)\r\n\t\tDeleteObject(hFont);\r\n}\r\n\r\nvoid RedrawTitleBar(HWND hWnd, bool active)\r\n{\r\n\tif (!pShared)\r\n\t\treturn;\r\n\r\n\tWaitForSingleObject(CommMutex, INFINITE);\r\n\tif (pShared->TitleBar[0] == 0)\r\n\t{\r\n\t\tReleaseMutex(CommMutex);\r\n\t\treturn;\r\n\t}\r\n\r\n\tint len = (int)strlen(pShared->TitleBar);\r\n\tif (len >= 1024)\r\n\t\tlen = 1023;\r\n\r\n\tWINDOWPLACEMENT place;\r\n\tRECT rect;\r\n\tHDC hDC = GetWindowDC(hWnd); //WINDOW dc allows us to draw on the non client area\r\n\r\n\tGetWindowPlacement(hWnd, &place);\r\n\tGetWindowRect(hWnd, &rect);\r\n\r\n\t// Change the coords (believe me, okay?)\r\n\trect.top = GetSystemMetrics(SM_CYFRAME);\r\n\trect.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);\r\n\r\n\trect.right = (rect.right - rect.left) - (4 * GetSystemMetrics(SM_CXSIZE) + GetSystemMetrics(SM_CXFRAME));\r\n\trect.left = GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXSMICON) + 5;\r\n\r\n\tif (hThemes)\r\n\t{\r\n\t\tHTHEME hTheme = zOpenThemeData(hWnd, L\"WINDOW\");\r\n\t\tDrawColorTitleBar(hTheme, hWnd, hDC, active, place.showCmd == SW_MAXIMIZE, pShared->TitleBar, len, rect);\r\n\t\tzCloseThemeData(hTheme);\r\n\t}\r\n\telse\r\n\t{\r\n\t\trect.left += GetSystemMetrics(SM_CXFRAME);\r\n\t\tDrawColorTitleBar(NULL, hWnd, hDC, active, place.showCmd == SW_MAXIMIZE, pShared->TitleBar, len, rect);\r\n\t}\r\n\r\n\tReleaseDC(hWnd, hDC);\r\n\tReleaseMutex(CommMutex);\r\n}\r\n"
  },
  {
    "path": "Crypt/debug.h",
    "content": "#ifdef DEBUG    /* keep these macros common so they are same for both versions */\r\nCONST int debugCompile  =   1;\r\nextern  int debug;\r\nextern  void DebugIO(CONST char *s);    /* display the debug output */\r\n\r\n#define DebugDump(x,s,R,XOR,doRot,showT,needBswap)  \\\r\n    { if (debug) _Dump(x,s,R,XOR,doRot,showT,needBswap,t0,t1); }\r\n#define DebugDumpKey(key) { if (debug) _DumpKey(key); }\r\n#define IV_ROUND    -100\r\n    \r\nvoid _Dump(CONST void *p,CONST char *s,int R,int XOR,int doRot,int showT,int needBswap,\r\n           DWORD t0,DWORD t1)\r\n    {\r\n    char line[512]; /* build output here */\r\n    int  i,n;\r\n    DWORD q[4];\r\n\r\n    if (R == IV_ROUND)\r\n        sprintf(line,\"%sIV:    \",s);\r\n    else\r\n        sprintf(line,\"%sR[%2d]: \",s,R);\r\n    for (n=0;line[n];n++) ;\r\n    \r\n    for (i=0;i<4;i++)\r\n        {\r\n        q[i]=((CONST DWORD *)p)[i^(XOR)];\r\n        if (needBswap) q[i]=Bswap(q[i]);\r\n        }\r\n\r\n    sprintf(line+n,\"x= %08lX  %08lX  %08lX  %08lX.\",\r\n            ROR(q[0],doRot*(R  )/2),\r\n            ROL(q[1],doRot*(R  )/2),\r\n            ROR(q[2],doRot*(R+1)/2),\r\n            ROL(q[3],doRot*(R+1)/2));\r\n    for (;line[n];n++) ;\r\n\r\n    if (showT)\r\n        sprintf(line+n,\"    t0=%08lX. t1=%08lX.\",t0,t1);\r\n    for (;line[n];n++) ;\r\n\r\n    sprintf(line+n,\"\\n\");\r\n    DebugIO(line);\r\n    }\r\n\r\nvoid _DumpKey(CONST keyInstance *key)\r\n    {\r\n    char    line[512];\r\n    int     i;\r\n    int     k64Cnt=(key->keyLen+63)/64; /* round up to next multiple of 64 bits */\r\n    int     subkeyCnt = ROUND_SUBKEYS + 2*key->numRounds;\r\n\r\n    sprintf(line,\";\\n;makeKey:   Input key            -->  S-box key     [%s]\\n\",\r\n           (key->direction == DIR_ENCRYPT) ? \"Encrypt\" : \"Decrypt\");\r\n    DebugIO(line);\r\n    for (i=0;i<k64Cnt;i++)  /* display in RS format */\r\n        {\r\n        sprintf(line,\";%12s %08lX %08lX  -->  %08lX\\n\",\"\",\r\n               key->key32[2*i+1],key->key32[2*i],key->sboxKeys[k64Cnt-1-i]);\r\n        DebugIO(line);\r\n        }\r\n    sprintf(line,\";%11sSubkeys\\n\",\"\");\r\n    DebugIO(line);\r\n    for (i=0;i<subkeyCnt/2;i++)\r\n        {\r\n        sprintf(line,\";%12s %08lX %08lX%s\\n\",\"\",key->subKeys[2*i],key->subKeys[2*i+1],\r\n              (2*i ==  INPUT_WHITEN) ? \"   Input whiten\" :\r\n              (2*i == OUTPUT_WHITEN) ? \"  Output whiten\" :\r\n              (2*i == ROUND_SUBKEYS) ? \"  Round subkeys\" : \"\");\r\n        DebugIO(line);\r\n        }\r\n    DebugIO(\";\\n\");\r\n    }\r\n#else\r\nCONST int debugCompile  =   0;\r\n#define DebugDump(x,s,R,XOR,doRot,showT,needBswap)\r\n#define DebugDumpKey(key)\r\n#endif\r\n"
  },
  {
    "path": "Crypt/platform.h",
    "content": "/***************************************************************************\r\n    PLATFORM.H  -- Platform-specific defines for TWOFISH code\r\n\r\n    Submitters:\r\n        Bruce Schneier, Counterpane Systems\r\n        Doug Whiting,   Hi/fn\r\n        John Kelsey,    Counterpane Systems\r\n        Chris Hall,     Counterpane Systems\r\n        David Wagner,   UC Berkeley\r\n            \r\n    Code Author:        Doug Whiting,   Hi/fn\r\n        \r\n    Version  1.00       April 1998\r\n        \r\n    Copyright 1998, Hi/fn and Counterpane Systems.  All rights reserved.\r\n        \r\n    Notes:\r\n        *   Tab size is set to 4 characters in this file\r\n\r\n***************************************************************************/\r\n\r\n/* use intrinsic rotate if possible */\r\n#ifndef ROL\r\n#define ROL(x,n) (((x) << ((n) & 0x1F)) | ((x) >> (32-((n) & 0x1F))))\r\n#define ROR(x,n) (((x) >> ((n) & 0x1F)) | ((x) << (32-((n) & 0x1F))))\r\n#endif\r\n\r\n#if (0) && defined(__BORLANDC__) && (__BORLANDC__ >= 0x462)\r\n#error \"!!!This does not work for some reason!!!\"\r\n#include    <stdlib.h>                  /* get prototype for _lrotl() , _lrotr() */\r\n#pragma inline __lrotl__\r\n#pragma inline __lrotr__\r\n#undef  ROL                             /* get rid of inefficient definitions */\r\n#undef  ROR\r\n#define ROL(x,n)    __lrotl__(x,n)      /* use compiler intrinsic rotations */\r\n#define ROR(x,n)    __lrotr__(x,n)\r\n#endif\r\n\r\n#ifdef _MSC_VER\r\n#include    <stdlib.h>                  /* get prototypes for rotation functions */\r\n#undef  ROL\r\n#undef  ROR\r\n#pragma intrinsic(_lrotl,_lrotr)        /* use intrinsic compiler rotations */\r\n#define ROL(x,n)    _lrotl(x,n)         \r\n#define ROR(x,n)    _lrotr(x,n)\r\n#endif\r\n\r\n#ifndef _M_IX86\r\n#ifdef  __BORLANDC__\r\n#define _M_IX86                 300     /* make sure this is defined for Intel CPUs */\r\n#endif\r\n#endif\r\n\r\n#ifdef _M_IX86\r\n#define     LittleEndian        1       /* e.g., 1 for Pentium, 0 for 68K */\r\n#define     ALIGN32             0       /* need dword alignment? (no for Pentium) */\r\n#else   /* non-Intel platforms */\r\n#define     LittleEndian        0       /* (assume big endian */\r\n#define     ALIGN32             1       /* (assume need alignment for non-Intel) */\r\n#endif\r\n\r\n#if LittleEndian\r\n#define     Bswap(x)            (x)     /* NOP for little-endian machines */\r\n#define     ADDR_XOR            0       /* NOP for little-endian machines */\r\n#else\r\n#define     Bswap(x)            ((ROR(x,8) & 0xFF00FF00) | (ROL(x,8) & 0x00FF00FF))\r\n#define     ADDR_XOR            3       /* convert byte address in dword */\r\n#endif\r\n\r\n/*  Macros for extracting bytes from dwords (correct for endianness) */\r\n#define _b(x,N) (((BYTE *)&x)[((N) & 3) ^ ADDR_XOR]) /* pick bytes out of a dword */\r\n\r\n#define     b0(x)           _b(x,0)     /* extract LSB of DWORD */\r\n#define     b1(x)           _b(x,1)\r\n#define     b2(x)           _b(x,2)\r\n#define     b3(x)           _b(x,3)     /* extract MSB of DWORD */\r\n\r\n"
  },
  {
    "path": "Crypt/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\r\n// Microsoft Visual C++ generated include file.\r\n// Used by Crypt.rc\r\n//\r\n#define IDI_ICON1                       101\r\n#define IDI_RAZOR                       101\r\n\r\n// Next default values for new objects\r\n// \r\n#ifdef APSTUDIO_INVOKED\r\n#ifndef APSTUDIO_READONLY_SYMBOLS\r\n#define _APS_NEXT_RESOURCE_VALUE        102\r\n#define _APS_NEXT_COMMAND_VALUE         40001\r\n#define _APS_NEXT_CONTROL_VALUE         1001\r\n#define _APS_NEXT_SYMED_VALUE           101\r\n#endif\r\n#endif\r\n"
  },
  {
    "path": "Crypt/stdafx.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\r\n// Crypt.pch will be the pre-compiled header\r\n// stdafx.obj will contain the pre-compiled type information\r\n\r\n#include \"stdafx.h\"\r\n\r\n// TODO: reference any additional headers you need in STDAFX.H\r\n// and not in this file\r\n"
  },
  {
    "path": "Crypt/stdafx.h",
    "content": "// stdafx.h : include file for standard system include files,\r\n// or project specific include files that are used frequently, but\r\n// are changed infrequently\r\n//\r\n\r\n#pragma once\r\n#pragma warning(disable: 4309)\r\n#pragma warning(disable: 4311)\r\n#pragma warning(disable: 4312)\r\n#pragma warning(disable: 4800)\r\n#pragma warning(disable: 4530)\r\n#pragma warning(disable: 4996)\r\n#pragma comment(lib, \"ws2_32.lib\")\r\n\r\n#define WIN32_LEAN_AND_MEAN\t\t// Exclude rarely-used stuff from Windows headers\r\n// Windows Header Files:\r\n#include <windows.h>\r\n\r\n#pragma pack(1)\r\n\r\n#include <stdio.h>\r\n#include <stdlib.h>\r\n#include <assert.h>\r\n#include <winsock2.h>\r\n#include <time.h>\r\n#include <zmouse.h>\r\n\r\n//#include <vector>\r\n//#include <string>\r\n//using std::vector;\r\n//using std::string;\r\n"
  },
  {
    "path": "Crypt/table.h",
    "content": "/***************************************************************************\r\n    TABLE.H -- Tables, macros, constants for Twofish S-boxes and MDS matrix\r\n\r\n    Submitters:\r\n        Bruce Schneier, Counterpane Systems\r\n        Doug Whiting,   Hi/fn\r\n        John Kelsey,    Counterpane Systems\r\n        Chris Hall,     Counterpane Systems\r\n        David Wagner,   UC Berkeley\r\n            \r\n    Code Author:        Doug Whiting,   Hi/fn\r\n        \r\n    Version  1.00       April 1998\r\n        \r\n    Copyright 1998, Hi/fn and Counterpane Systems.  All rights reserved.\r\n        \r\n    Notes:\r\n        *   Tab size is set to 4 characters in this file\r\n        *   These definitions should be used in optimized and unoptimized\r\n            versions to insure consistency.\r\n\r\n***************************************************************************/\r\n\r\n/* for computing subkeys */\r\n#define SK_STEP         0x02020202u\r\n#define SK_BUMP         0x01010101u\r\n#define SK_ROTL         9\r\n\r\n/* Reed-Solomon code parameters: (12,8) reversible code\r\n    g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1\r\n   where a = primitive root of field generator 0x14D */\r\n#define RS_GF_FDBK      0x14D       /* field generator */\r\n#define RS_rem(x)       \\\r\n    { BYTE  b  = (BYTE) (x >> 24);                                           \\\r\n      DWORD g2 = ((b << 1) ^ ((b & 0x80) ? RS_GF_FDBK : 0 )) & 0xFF;         \\\r\n      DWORD g3 = ((b >> 1) & 0x7F) ^ ((b & 1) ? RS_GF_FDBK >> 1 : 0 ) ^ g2 ; \\\r\n      x = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b;                \\\r\n    }\r\n\r\n/*  Macros for the MDS matrix\r\n*   The MDS matrix is (using primitive polynomial 169):\r\n*      01  EF  5B  5B\r\n*      5B  EF  EF  01\r\n*      EF  5B  01  EF\r\n*      EF  01  EF  5B\r\n*----------------------------------------------------------------\r\n* More statistical properties of this matrix (from MDS.EXE output):\r\n*\r\n* Min Hamming weight (one byte difference) =  8. Max=26.  Total =  1020.\r\n* Prob[8]:      7    23    42    20    52    95    88    94   121   128    91\r\n*             102    76    41    24     8     4     1     3     0     0     0\r\n* Runs[8]:      2     4     5     6     7     8     9    11\r\n* MSBs[8]:      1     4    15     8    18    38    40    43\r\n* HW= 8: 05040705 0A080E0A 14101C14 28203828 50407050 01499101 A080E0A0 \r\n* HW= 9: 04050707 080A0E0E 10141C1C 20283838 40507070 80A0E0E0 C6432020 07070504 \r\n*        0E0E0A08 1C1C1410 38382820 70705040 E0E0A080 202043C6 05070407 0A0E080E \r\n*        141C101C 28382038 50704070 A0E080E0 4320C620 02924B02 089A4508 \r\n* Min Hamming weight (two byte difference) =  3. Max=28.  Total = 390150.\r\n* Prob[3]:      7    18    55   149   270   914  2185  5761 11363 20719 32079\r\n*           43492 51612 53851 52098 42015 31117 20854 11538  6223  2492  1033\r\n* MDS OK, ROR:   6+  7+  8+  9+ 10+ 11+ 12+ 13+ 14+ 15+ 16+\r\n*               17+ 18+ 19+ 20+ 21+ 22+ 23+ 24+ 25+ 26+\r\n*/\r\n#define MDS_GF_FDBK     0x169   /* primitive polynomial for GF(256)*/\r\n#define LFSR1(x) ( ((x) >> 1)  ^ (((x) & 0x01) ?   MDS_GF_FDBK/2 : 0))\r\n#define LFSR2(x) ( ((x) >> 2)  ^ (((x) & 0x02) ?   MDS_GF_FDBK/2 : 0)  \\\r\n                               ^ (((x) & 0x01) ?   MDS_GF_FDBK/4 : 0))\r\n\r\n#define Mx_1(x) ((DWORD)  (x))      /* force result to dword so << will work */\r\n#define Mx_X(x) ((DWORD) ((x) ^            LFSR2(x)))   /* 5B */\r\n#define Mx_Y(x) ((DWORD) ((x) ^ LFSR1(x) ^ LFSR2(x)))   /* EF */\r\n\r\n#define M00     Mul_1\r\n#define M01     Mul_Y\r\n#define M02     Mul_X\r\n#define M03     Mul_X\r\n\r\n#define M10     Mul_X\r\n#define M11     Mul_Y\r\n#define M12     Mul_Y\r\n#define M13     Mul_1\r\n\r\n#define M20     Mul_Y\r\n#define M21     Mul_X\r\n#define M22     Mul_1\r\n#define M23     Mul_Y\r\n\r\n#define M30     Mul_Y\r\n#define M31     Mul_1\r\n#define M32     Mul_Y\r\n#define M33     Mul_X\r\n\r\n#define Mul_1   Mx_1\r\n#define Mul_X   Mx_X\r\n#define Mul_Y   Mx_Y\r\n\r\n/*  Define the fixed p0/p1 permutations used in keyed S-box lookup.  \r\n    By changing the following constant definitions for P_ij, the S-boxes will\r\n    automatically get changed in all the Twofish source code. Note that P_i0 is\r\n    the \"outermost\" 8x8 permutation applied.  See the f32() function to see\r\n    how these constants are to be  used.\r\n*/\r\n#define P_00    1                   /* \"outermost\" permutation */\r\n#define P_01    0\r\n#define P_02    0\r\n#define P_03    (P_01^1)            /* \"extend\" to larger key sizes */\r\n#define P_04    1\r\n\r\n#define P_10    0\r\n#define P_11    0\r\n#define P_12    1\r\n#define P_13    (P_11^1)\r\n#define P_14    0\r\n\r\n#define P_20    1\r\n#define P_21    1\r\n#define P_22    0\r\n#define P_23    (P_21^1)\r\n#define P_24    0\r\n\r\n#define P_30    0\r\n#define P_31    1\r\n#define P_32    1\r\n#define P_33    (P_31^1)\r\n#define P_34    1\r\n\r\n#define p8(N)   P8x8[P_##N]         /* some syntax shorthand */\r\n\r\n/* fixed 8x8 permutation S-boxes */\r\n\r\n/***********************************************************************\r\n*  07:07:14  05/30/98  [4x4]  TestCnt=256. keySize=128. CRC=4BD14D9E.\r\n* maxKeyed:  dpMax = 18. lpMax =100. fixPt =  8. skXor =  0. skDup =  6. \r\n* log2(dpMax[ 6..18])=   --- 15.42  1.33  0.89  4.05  7.98 12.05\r\n* log2(lpMax[ 7..12])=  9.32  1.01  1.16  4.23  8.02 12.45\r\n* log2(fixPt[ 0.. 8])=  1.44  1.44  2.44  4.06  6.01  8.21 11.07 14.09 17.00\r\n* log2(skXor[ 0.. 0])\r\n* log2(skDup[ 0.. 6])=   ---  2.37  0.44  3.94  8.36 13.04 17.99\r\n***********************************************************************/\r\nCONST BYTE P8x8[2][256]=\r\n    {\r\n/*  p0:   */\r\n/*  dpMax      = 10.  lpMax      = 64.  cycleCnt=   1  1  1  0.         */\r\n/* 817D6F320B59ECA4.ECB81235F4A6709D.BA5E6D90C8F32471.D7F4126E9B3085CA. */\r\n/* Karnaugh maps:\r\n*  0111 0001 0011 1010. 0001 1001 1100 1111. 1001 1110 0011 1110. 1101 0101 1111 1001. \r\n*  0101 1111 1100 0100. 1011 0101 0010 0000. 0101 1000 1100 0101. 1000 0111 0011 0010. \r\n*  0000 1001 1110 1101. 1011 1000 1010 0011. 0011 1001 0101 0000. 0100 0010 0101 1011. \r\n*  0111 0100 0001 0110. 1000 1011 1110 1001. 0011 0011 1001 1101. 1101 0101 0000 1100. \r\n*/\r\n    {\r\n    0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, \r\n    0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, \r\n    0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, \r\n    0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, \r\n    0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, \r\n    0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, \r\n    0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, \r\n    0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, \r\n    0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, \r\n    0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, \r\n    0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, \r\n    0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, \r\n    0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, \r\n    0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, \r\n    0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, \r\n    0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, \r\n    0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, \r\n    0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, \r\n    0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, \r\n    0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, \r\n    0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, \r\n    0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, \r\n    0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, \r\n    0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, \r\n    0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, \r\n    0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, \r\n    0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, \r\n    0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, \r\n    0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, \r\n    0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, \r\n    0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, \r\n    0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0\r\n    },\r\n/*  p1:   */\r\n/*  dpMax      = 10.  lpMax      = 64.  cycleCnt=   2  0  0  1.         */\r\n/* 28BDF76E31940AC5.1E2B4C376DA5F908.4C75169A0ED82B3F.B951C3DE647F208A. */\r\n/* Karnaugh maps:\r\n*  0011 1001 0010 0111. 1010 0111 0100 0110. 0011 0001 1111 0100. 1111 1000 0001 1100. \r\n*  1100 1111 1111 1010. 0011 0011 1110 0100. 1001 0110 0100 0011. 0101 0110 1011 1011. \r\n*  0010 0100 0011 0101. 1100 1000 1000 1110. 0111 1111 0010 0110. 0000 1010 0000 0011. \r\n*  1101 1000 0010 0001. 0110 1001 1110 0101. 0001 0100 0101 0111. 0011 1011 1111 0010. \r\n*/\r\n    {\r\n    0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, \r\n    0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, \r\n    0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, \r\n    0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, \r\n    0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, \r\n    0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, \r\n    0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, \r\n    0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, \r\n    0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, \r\n    0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, \r\n    0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, \r\n    0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, \r\n    0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, \r\n    0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, \r\n    0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, \r\n    0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, \r\n    0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, \r\n    0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, \r\n    0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, \r\n    0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, \r\n    0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, \r\n    0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, \r\n    0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, \r\n    0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, \r\n    0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, \r\n    0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, \r\n    0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, \r\n    0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, \r\n    0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, \r\n    0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, \r\n    0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, \r\n    0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91\r\n    }\r\n    };\r\n"
  },
  {
    "path": "Crypt/trees.cpp",
    "content": "\r\nint Trees[] = {\r\n\t0x4CCA, 0x4CCB, 0x4CCC, 0x4CCD, 0x4CD0, 0x4CD3, 0x4CD6, 0x4CD8,\r\n\t0x4CDA, 0x4CDD, 0x4CE0, 0x4CE3, 0x4CE6, 0x4CF8, 0x4CFB, 0x4CFE,\r\n\t0x4D01, 0x4D41, 0x4D42, 0x4D43, 0x4D44, 0x4D57, 0x4D58, 0x4D59,\r\n\t0x4D5A, 0x4D5B, 0x4D6E, 0x4D6F, 0x4D70, 0x4D71, 0x4D72, 0x4D84,\r\n\t0x4D85, 0x4D86, 0x52B5, 0x52B6, 0x52B7, 0x52B8, 0x52B9, 0x52BA,\r\n\t0x52BB, 0x52BC, 0x52BD,\r\n};\r\n\r\nint Leaves[] = {\r\n\t0x4CCE, 0x4CCF, 0x4CD1, 0x4CD2, 0x4CD4, 0x4CD5, 0x4CD7, 0x4CD9,\r\n\t0x4CDB, 0x4CDC, 0x4CDE, 0x4CDF, 0x4CE1, 0x4CE2, 0x4CE4, 0x4CE5,\r\n\t0x4CE7, 0x4CE8, 0x4CF9, 0x4CFA, 0x4CFC, 0x4CFD, 0x4CFF, 0x4D00,\r\n\t0x4D02, 0x4D03, 0x4D45, 0x4D46, 0x4D47, 0x4D48, 0x4D49, 0x4D4A,\r\n\t0x4D4B, 0x4D4C, 0x4D4D, 0x4D4E, 0x4D4F, 0x4D50, 0x4D51, 0x4D52,\r\n\t0x4D53, 0x4D5C, 0x4D5D, 0x4D5E, 0x4D5F, 0x4D60, 0x4D61, 0x4D62,\r\n\t0x4D63, 0x4D64, 0x4D65, 0x4D66, 0x4D67, 0x4D68, 0x4D69, 0x4D73,\r\n\t0x4D74, 0x4D75, 0x4D76, 0x4D77, 0x4D78, 0x4D79, 0x4D7A, 0x4D7B,\r\n\t0x4D7C, 0x4D7D, 0x4D7E, 0x4D7F, 0x4D87, 0x4D88, 0x4D89, 0x4D8A,\r\n\t0x4D8B, 0x4D8C, 0x4D8D, 0x4D8E, 0x4D8F, 0x4D90, 0x4D95, 0x4D96,\r\n\t0x4D97, 0x4D99, 0x4D9A, 0x4D9B, 0x4D9D, 0x4D9E, 0x4D9F, 0x4DA1,\r\n\t0x4DA2, 0x4DA3, 0x4DA5, 0x4DA6, 0x4DA7, 0x4DA9, 0x4DAA, 0x4DAB,\r\n\t0x52BE, 0x52BF, 0x52C0, 0x52C1, 0x52C2, 0x52C3, 0x52C4, 0x52C5,\r\n\t0x52C6, 0x52C7\r\n};\r\n\r\nHANDLE WINAPI NewCreateFile( LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,\r\n\t\t\t\t\t\t\t LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,\r\n                             DWORD dwFlagsAndAttributes, HANDLE hTemplateFile )\r\n{\r\n\tstrlwr( (char*)lpFileName );\r\n\tif ( strstr( lpFileName, \"artidx.mul\" ) && (dwDesiredAccess & GENERIC_READ) != 0 )\r\n\t{\r\n\t\tchar path[MAX_PATH];\r\n\t\tGetTempPath( MAX_PATH, path );\r\n\t\tstrcat( path, \"/razor_art.tmp\" );\r\n\t\tCopyFile( lpFileName, path, FALSE );\r\n\r\n\t\tint stump[3], none[3];\r\n\t\tFILE *f = fopen( path, \"rb\" );\r\n\t\tfseek( f, 12*0xE57, SEEK_SET );\r\n\t\tfread( stump, 12, 1, f );\r\n\t\tfseek( f, 12*0x115E, SEEK_SET );\r\n\t\tfread( none, 12, 1, f );\r\n\t\tfclose( f );\r\n\r\n\t\tf = fopen( path, \"wb\" );\r\n\t\tfor(int i=0;Trees[i] != 0;i++)\r\n\t\t{\r\n\t\t\tfseek( f, 12*Trees[i], SEEK_SET );\r\n\t\t\tfwrite( stump, 12, 1, f );\r\n\t\t}\r\n\t\tfor(int i=0;Leaves[i] != 0;i++)\r\n\t\t{\r\n\t\t\tfseek( f, 12*Leaves[i], SEEK_SET );\r\n\t\t\tfwrite( none, 12, 1, f );\r\n\t\t}\r\n\t\tfclose( f );\r\n\r\n\t\treturn CreateFile( path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile );\r\n\t}\r\n\telse\r\n\t{\r\n\t\treturn CreateFile( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile );\r\n\t}\r\n}\r\n\r\n#define CREATE_FILE_LOC \"\\x68\\x00\\x00\\x00\\xC0\\x50\\xFF\\x15\\xF8\\x71\\x56\\x00\\x83\\xF8\\xFF\"\r\n#define CFL_LEN 15\r\n\r\nvoid PatchCreateFile()\r\n{\r\n\tDWORD CurPos = FindInMemory( 0x00400000, CREATE_FILE_LOC, CFL_LEN );\r\n\tif ( !CurPos ) \r\n\t\treturn;\r\n\tCurPos += 6;\r\n\t*((unsigned char*)(CurPos)) = 0xE8; // call\r\n\t*((unsigned int*)(CurPos+1)) = int(NewCreateFile) - (CurPos+4);\r\n\t*((unsigned char*)(CurPos+5)) = 0x90; // nop\r\n}\r\n\r\nvoid PatchStartup( DWORD ProcID )\r\n{\r\n\tHANDLE hProc = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ProcID );\r\n\tif ( !hProc )\r\n\t\treturn;\r\n\r\n\tDWORD image_base = ???; \r\n    IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)image_base;\r\n    IMAGE_FILE_HEADER *ifh = (IMAGE_FILE_HEADER *)(image_base + idh->e_lfanew + sizeof(DWORD));\r\n    IMAGE_OPTIONAL_HEADER *ioh = (IMAGE_OPTIONAL_HEADER *)((DWORD)(ifh) + sizeof(IMAGE_FILE_HEADER));\r\n\r\n\tDWORD acc = 0;\r\n\tvoid *addr = VirtualAllocEx( hProc, NULL, 512, MEM_COMMIT, PAGE_EXECUTE_READWRITE );\r\n\tDWORD Pos = (DWORD)addr;\r\n\r\n\tchar file[256];\r\n\tacc = GetModuleFileName( GetModuleHandle(NULL), file, 256 );\r\n\tWriteProcessMemory( hProc, (void*)Pos, file, acc, &acc );\r\n\tDWORD FileLoc = Pos;\r\n\tPos += acc;\r\n\tstrcpy( file, \"AttachedStart\" );\r\n\tWriteProcessMemory( hProc, (void*)Pos, file, strlen(file)+1, &acc );\r\n\tDWORD ProcLoc = Pos;\r\n\tPos += acc;\r\n\r\n\tunsigned char LoadFunc[] = {\r\n\t\t0x55,\t\t\t\t\t// push ebp\r\n\t\t0x8B, 0xEC,\t\t\t\t// mov ebp, esp\r\n\t\t0x53,\t\t\t\t\t// push ebx\r\n\t\t0x56,\t\t\t\t\t// push esi\r\n\t\t0x57,\t\t\t\t\t// push edi\r\n\t\t0x68, 0, 0, 0, 0,\t\t// push _address_\r\n\t\t0xFF,0x15,0xB8,0x71,0x56,0x00, // call ds:LoadLibraryA\r\n\t\t0x68, 0, 0, 0, 0,\t\t// push _address_\r\n\t\t0x50,\t\t\t\t\t// push eax\r\n\t\t0x8B, 0xF0,\t\t\t\t// mov esi, eax\r\n\t\t0xFF,0x15,0xBC,0x71,0x56,0x00, // call ds:GetProcAddress\r\n\t\t0xFF, 0xD0,\t\t\t\t// call eax\r\n\t\t//0x56,\t\t\t\t\t// push esi             ; hLibModule\r\n\t\t//0xFF,0x15,0xC0,0x71,0x56,0x00, // call ds:FreeLibrary\r\n\t\t0x5F,\t\t\t\t\t// pop edi\r\n\t\t0x5E,\t\t\t\t\t// pop esi\r\n\t\t0x5B,\t\t\t\t\t// pop ebx\r\n\t\t0x5D,\t\t\t\t\t// pop ebp\r\n\t\t0xE9, 0, 0, 0, 0,\t\t// jmp _addressoffset_\r\n\t\t0x90,\t\t\t\t\t// nop\r\n\t\t0x90,\t\t\t\t\t// nop\r\n\t};\r\n\tconst int len = 44;\r\n\r\n\t*((int*)(LoadFunc+7)) = FileLoc - (Pos+7+4);\r\n\t*((int*)(LoadFunc+18)) = ProcLoc - (Pos+18+4);\r\n\t*((int*)(LoadFunc+38)) = (ioh->ImageBase + ioh->AddressOfEntryPoint) - (Pos+38+4);\r\n\r\n\tWriteProcessMemory( hProc, (void*)Pos, LoadFunc, len, &acc );\r\n\tioh->AddressOfEntryPoint = Pos;\r\n\tCloseHandle( hProc );\r\n}\r\n"
  },
  {
    "path": "Crypt/twofish.c",
    "content": "/***************************************************************************\r\n    TWOFISH2.C  -- Optimized C API calls for TWOFISH AES submission\r\n\r\n    Submitters:\r\n        Bruce Schneier, Counterpane Systems\r\n        Doug Whiting,   Hi/fn\r\n        John Kelsey,    Counterpane Systems\r\n        Chris Hall,     Counterpane Systems\r\n        David Wagner,   UC Berkeley\r\n            \r\n    Code Author:        Doug Whiting,   Hi/fn\r\n        \r\n    Version  1.00       April 1998\r\n        \r\n    Copyright 1998, Hi/fn and Counterpane Systems.  All rights reserved.\r\n        \r\n    Notes:\r\n        *   Optimized version\r\n        *   Tab size is set to 4 characters in this file\r\n\r\n***************************************************************************/\r\n\r\n#pragma pack(1)\r\n\r\n#include <memory.h>\r\n#include    \"twofish.h\"\r\n#include    \"table.h\"\r\n\r\n#pragma warning(disable: 4005)//ignore macro re-definitions\r\n\r\n#if   defined(min_key)  && !defined(MIN_KEY)\r\n#define MIN_KEY     1           /* toupper() */\r\n#elif defined(part_key) && !defined(PART_KEY)\r\n#define PART_KEY    1\r\n#elif defined(zero_key) && !defined(ZERO_KEY)\r\n#define ZERO_KEY    1\r\n#endif\r\n\r\n\r\n#ifdef USE_ASM\r\nextern  int useAsm;             /* ok to use ASM code? */\r\n\r\ntypedef int cdecl CipherProc\r\n   (cipherInstance *cipher, keyInstance *key,BYTE *input,int inputLen,BYTE *outBuffer);\r\ntypedef int cdecl KeySetupProc(keyInstance *key);\r\n\r\nextern CipherProc   *blockEncrypt_86;   /* ptr to ASM functions */\r\nextern CipherProc   *blockDecrypt_86;\r\nextern KeySetupProc *reKey_86;\r\nextern DWORD        cdecl TwofishAsmCodeSize(void);\r\n#endif\r\n\r\n/*\r\n+*****************************************************************************\r\n*           Constants/Macros/Tables\r\n-****************************************************************************/\r\n\r\n#define     CONST                   /* help syntax from C++, NOP here */\r\n\r\nCONST       fullSbox MDStab;        /* not actually const.  Initialized ONE time */\r\nint         needToBuildMDS=1;       /* is MDStab initialized yet? */\r\n\r\n#define     BIG_TAB     0\r\n\r\n#if BIG_TAB\r\nBYTE        bigTab[4][256][256];    /* pre-computed S-box */\r\n#endif\r\n\r\n/* number of rounds for various key sizes:  128, 192, 256 */\r\n/* (ignored for now in optimized code!) */\r\nCONST int   numRounds[4]= {0,ROUNDS_128,ROUNDS_192,ROUNDS_256};\r\n\r\n#if REENTRANT\r\n#define     _sBox_   key->sBox8x32\r\n#else\r\nstatic      fullSbox _sBox_;        /* permuted MDStab based on keys */\r\n#endif\r\n#define _sBox8_(N) (((BYTE *) _sBox_) + (N)*256)\r\n\r\n/*------- see what level of S-box precomputation we need to do -----*/\r\n#if   defined(ZERO_KEY)\r\n#define MOD_STRING  \"(Zero S-box keying)\"\r\n#define Fe32_128(x,R)   \\\r\n    (   MDStab[0][p8(01)[p8(02)[_b(x,R  )]^b0(SKEY[1])]^b0(SKEY[0])] ^  \\\r\n        MDStab[1][p8(11)[p8(12)[_b(x,R+1)]^b1(SKEY[1])]^b1(SKEY[0])] ^  \\\r\n        MDStab[2][p8(21)[p8(22)[_b(x,R+2)]^b2(SKEY[1])]^b2(SKEY[0])] ^  \\\r\n        MDStab[3][p8(31)[p8(32)[_b(x,R+3)]^b3(SKEY[1])]^b3(SKEY[0])] )\r\n#define Fe32_192(x,R)   \\\r\n    (   MDStab[0][p8(01)[p8(02)[p8(03)[_b(x,R  )]^b0(SKEY[2])]^b0(SKEY[1])]^b0(SKEY[0])] ^ \\\r\n        MDStab[1][p8(11)[p8(12)[p8(13)[_b(x,R+1)]^b1(SKEY[2])]^b1(SKEY[1])]^b1(SKEY[0])] ^ \\\r\n        MDStab[2][p8(21)[p8(22)[p8(23)[_b(x,R+2)]^b2(SKEY[2])]^b2(SKEY[1])]^b2(SKEY[0])] ^ \\\r\n        MDStab[3][p8(31)[p8(32)[p8(33)[_b(x,R+3)]^b3(SKEY[2])]^b3(SKEY[1])]^b3(SKEY[0])] )\r\n#define Fe32_256(x,R)   \\\r\n    (   MDStab[0][p8(01)[p8(02)[p8(03)[p8(04)[_b(x,R  )]^b0(SKEY[3])]^b0(SKEY[2])]^b0(SKEY[1])]^b0(SKEY[0])] ^ \\\r\n        MDStab[1][p8(11)[p8(12)[p8(13)[p8(14)[_b(x,R+1)]^b1(SKEY[3])]^b1(SKEY[2])]^b1(SKEY[1])]^b1(SKEY[0])] ^ \\\r\n        MDStab[2][p8(21)[p8(22)[p8(23)[p8(24)[_b(x,R+2)]^b2(SKEY[3])]^b2(SKEY[2])]^b2(SKEY[1])]^b2(SKEY[0])] ^ \\\r\n        MDStab[3][p8(31)[p8(32)[p8(33)[p8(34)[_b(x,R+3)]^b3(SKEY[3])]^b3(SKEY[2])]^b3(SKEY[1])]^b3(SKEY[0])] )\r\n\r\n#define GetSboxKey  DWORD SKEY[4];  /* local copy */ \\\r\n                    memcpy(SKEY,key->sboxKeys,sizeof(SKEY));\r\n/*----------------------------------------------------------------*/\r\n#elif defined(MIN_KEY)\r\n#define MOD_STRING  \"(Minimal keying)\"\r\n#define Fe32_(x,R)(MDStab[0][p8(01)[_sBox8_(0)[_b(x,R  )]] ^ b0(SKEY0)] ^ \\\r\n                   MDStab[1][p8(11)[_sBox8_(1)[_b(x,R+1)]] ^ b1(SKEY0)] ^ \\\r\n                   MDStab[2][p8(21)[_sBox8_(2)[_b(x,R+2)]] ^ b2(SKEY0)] ^ \\\r\n                   MDStab[3][p8(31)[_sBox8_(3)[_b(x,R+3)]] ^ b3(SKEY0)])\r\n#define sbSet(N,i,J,v) { _sBox8_(N)[i+J] = v; }\r\n#define GetSboxKey  DWORD SKEY0 = key->sboxKeys[0]      /* local copy */\r\n/*----------------------------------------------------------------*/\r\n#elif defined(PART_KEY) \r\n#define MOD_STRING  \"(Partial keying)\"\r\n#define Fe32_(x,R)(MDStab[0][_sBox8_(0)[_b(x,R  )]] ^ \\\r\n                   MDStab[1][_sBox8_(1)[_b(x,R+1)]] ^ \\\r\n                   MDStab[2][_sBox8_(2)[_b(x,R+2)]] ^ \\\r\n                   MDStab[3][_sBox8_(3)[_b(x,R+3)]])\r\n#define sbSet(N,i,J,v) { _sBox8_(N)[i+J] = v; }\r\n#define GetSboxKey  \r\n/*----------------------------------------------------------------*/\r\n#else   /* default is FULL_KEY */\r\n#ifndef FULL_KEY\r\n#define FULL_KEY    1\r\n#endif\r\n#if BIG_TAB\r\n#define TAB_STR     \" (Big table)\"\r\n#else\r\n#define TAB_STR\r\n#endif\r\n#ifdef COMPILE_KEY\r\n#define MOD_STRING  \"(Compiled subkeys)\" TAB_STR\r\n#else\r\n#define MOD_STRING  \"(Full keying)\" TAB_STR\r\n#endif\r\n/* Fe32_ does a full S-box + MDS lookup.  Need to #define _sBox_ before use.\r\n   Note that we \"interleave\" 0,1, and 2,3 to avoid cache bank collisions\r\n   in optimized assembly language.\r\n*/\r\n#define Fe32_(x,R) (_sBox_[0][2*_b(x,R  )] ^ _sBox_[0][2*_b(x,R+1)+1] ^ \\\r\n                    _sBox_[2][2*_b(x,R+2)] ^ _sBox_[2][2*_b(x,R+3)+1])\r\n        /* set a single S-box value, given the input byte */\r\n#define sbSet(N,i,J,v) { _sBox_[N&2][2*i+(N&1)+2*J]=MDStab[N][v]; }\r\n#define GetSboxKey  \r\n#endif\r\n\r\nCONST       char *moduleDescription =\"Optimized C \";\r\nCONST       char *modeString        =MOD_STRING;\r\n\r\n\r\n/* macro(s) for debugging help */\r\n#define     CHECK_TABLE     0       /* nonzero --> compare against \"slow\" table */\r\n#define     VALIDATE_PARMS  0       /* disable for full speed */\r\n\r\n#include    \"debug.h\"               /* debug display macros */\r\n\r\n/* end of debug macros */\r\n\r\n#ifdef GetCodeSize\r\nextern DWORD Here(DWORD x);         /* return caller's address! */\r\nDWORD TwofishCodeStart(void) { return Here(0); }\r\n#endif\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    TableOp\r\n*\r\n* Function:         Handle table use checking\r\n*\r\n* Arguments:        op  =   what to do  (see TAB_* defns in AES.H)\r\n*\r\n* Return:           TRUE --> done (for TAB_QUERY)       \r\n*\r\n* Notes: This routine is for use in generating the tables KAT file.\r\n*        For this optimized version, we don't actually track table usage,\r\n*        since it would make the macros incredibly ugly.  Instead we just\r\n*        run for a fixed number of queries and then say we're done.\r\n*\r\n-****************************************************************************/\r\nint TableOp(int op)\r\n    {\r\n    static int queryCnt=0;\r\n\r\n    switch (op)\r\n        {\r\n        case TAB_DISABLE:\r\n            break;\r\n        case TAB_ENABLE:\r\n            break;\r\n        case TAB_RESET:\r\n            queryCnt=0;\r\n            break;\r\n        case TAB_QUERY:\r\n            queryCnt++;\r\n            if (queryCnt < TAB_MIN_QUERY)\r\n                return FALSE;\r\n        }\r\n    return TRUE;\r\n    }\r\n\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    ParseHexDword\r\n*\r\n* Function:         Parse ASCII hex nibbles and fill in key/iv dwords\r\n*\r\n* Arguments:        bit         =   # bits to read\r\n*                   srcTxt      =   ASCII source\r\n*                   d           =   ptr to dwords to fill in\r\n*                   dstTxt      =   where to make a copy of ASCII source\r\n*                                   (NULL ok)\r\n*\r\n* Return:           Zero if no error.  Nonzero --> invalid hex or length\r\n*\r\n* Notes:  Note that the parameter d is a DWORD array, not a byte array.\r\n*   This routine is coded to work both for little-endian and big-endian\r\n*   architectures.  The character stream is interpreted as a LITTLE-ENDIAN\r\n*   byte stream, since that is how the Pentium works, but the conversion\r\n*   happens automatically below. \r\n*\r\n-****************************************************************************/\r\nint ParseHexDword(int bits,CONST char *srcTxt,DWORD *d,char *dstTxt)\r\n    {\r\n    int i;\r\n    char c;\r\n    DWORD b;\r\n\r\n    union   /* make sure LittleEndian is defined correctly */\r\n        {\r\n        BYTE  b[4];\r\n        DWORD d[1];\r\n        } v;\r\n    v.d[0]=1;\r\n    if (v.b[0 ^ ADDR_XOR] != 1)\r\n        return BAD_ENDIAN;      /* make sure compile-time switch is set ok */\r\n\r\n#if VALIDATE_PARMS\r\n  #if ALIGN32\r\n    if (((int)d) & 3)\r\n        return BAD_ALIGN32; \r\n  #endif\r\n#endif\r\n\r\n    for (i=0;i*32<bits;i++)\r\n        d[i]=0;                 /* first, zero the field */\r\n\r\n    for (i=0;i*4<bits;i++)      /* parse one nibble at a time */\r\n        {                       /* case out the hexadecimal characters */\r\n        c=srcTxt[i];\r\n        if (dstTxt) dstTxt[i]=c;\r\n        if ((c >= '0') && (c <= '9'))\r\n            b=c-'0';\r\n        else if ((c >= 'a') && (c <= 'f'))\r\n            b=c-'a'+10;\r\n        else if ((c >= 'A') && (c <= 'F'))\r\n            b=c-'A'+10;\r\n        else\r\n            return BAD_KEY_MAT; /* invalid hex character */\r\n        /* works for big and little endian! */\r\n        d[i/8] |= b << (4*((i^1)&7));       \r\n        }\r\n\r\n    return 0;                   /* no error */\r\n    }\r\n\r\n\r\n#if CHECK_TABLE\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    f32\r\n*\r\n* Function:         Run four bytes through keyed S-boxes and apply MDS matrix\r\n*\r\n* Arguments:        x           =   input to f function\r\n*                   k32         =   pointer to key dwords\r\n*                   keyLen      =   total key length (k32 --> keyLey/2 bits)\r\n*\r\n* Return:           The output of the keyed permutation applied to x.\r\n*\r\n* Notes:\r\n*   This function is a keyed 32-bit permutation.  It is the major building\r\n*   block for the Twofish round function, including the four keyed 8x8 \r\n*   permutations and the 4x4 MDS matrix multiply.  This function is used\r\n*   both for generating round subkeys and within the round function on the\r\n*   block being encrypted.  \r\n*\r\n*   This version is fairly slow and pedagogical, although a smartcard would\r\n*   probably perform the operation exactly this way in firmware.   For\r\n*   ultimate performance, the entire operation can be completed with four\r\n*   lookups into four 256x32-bit tables, with three dword xors.\r\n*\r\n*   The MDS matrix is defined in TABLE.H.  To multiply by Mij, just use the\r\n*   macro Mij(x).\r\n*\r\n-****************************************************************************/\r\nDWORD f32(DWORD x,CONST DWORD *k32,int keyLen)\r\n    {\r\n    BYTE  b[4];\r\n    \r\n    /* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. */\r\n    /* Note that each byte goes through a different combination of S-boxes.*/\r\n\r\n    *((DWORD *)b) = Bswap(x);   /* make b[0] = LSB, b[3] = MSB */\r\n    switch (((keyLen + 63)/64) & 3)\r\n        {\r\n        case 0:     /* 256 bits of key */\r\n            b[0] = p8(04)[b[0]] ^ b0(k32[3]);\r\n            b[1] = p8(14)[b[1]] ^ b1(k32[3]);\r\n            b[2] = p8(24)[b[2]] ^ b2(k32[3]);\r\n            b[3] = p8(34)[b[3]] ^ b3(k32[3]);\r\n            /* fall thru, having pre-processed b[0]..b[3] with k32[3] */\r\n        case 3:     /* 192 bits of key */\r\n            b[0] = p8(03)[b[0]] ^ b0(k32[2]);\r\n            b[1] = p8(13)[b[1]] ^ b1(k32[2]);\r\n            b[2] = p8(23)[b[2]] ^ b2(k32[2]);\r\n            b[3] = p8(33)[b[3]] ^ b3(k32[2]);\r\n            /* fall thru, having pre-processed b[0]..b[3] with k32[2] */\r\n        case 2:     /* 128 bits of key */\r\n            b[0] = p8(00)[p8(01)[p8(02)[b[0]] ^ b0(k32[1])] ^ b0(k32[0])];\r\n            b[1] = p8(10)[p8(11)[p8(12)[b[1]] ^ b1(k32[1])] ^ b1(k32[0])];\r\n            b[2] = p8(20)[p8(21)[p8(22)[b[2]] ^ b2(k32[1])] ^ b2(k32[0])];\r\n            b[3] = p8(30)[p8(31)[p8(32)[b[3]] ^ b3(k32[1])] ^ b3(k32[0])];\r\n        }\r\n\r\n    /* Now perform the MDS matrix multiply inline. */\r\n    return  ((M00(b[0]) ^ M01(b[1]) ^ M02(b[2]) ^ M03(b[3]))      ) ^\r\n            ((M10(b[0]) ^ M11(b[1]) ^ M12(b[2]) ^ M13(b[3])) <<  8) ^\r\n            ((M20(b[0]) ^ M21(b[1]) ^ M22(b[2]) ^ M23(b[3])) << 16) ^\r\n            ((M30(b[0]) ^ M31(b[1]) ^ M32(b[2]) ^ M33(b[3])) << 24) ;\r\n    }\r\n#endif  /* CHECK_TABLE */\r\n\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    RS_MDS_encode\r\n*\r\n* Function:         Use (12,8) Reed-Solomon code over GF(256) to produce\r\n*                   a key S-box dword from two key material dwords.\r\n*\r\n* Arguments:        k0  =   1st dword\r\n*                   k1  =   2nd dword\r\n*\r\n* Return:           Remainder polynomial generated using RS code\r\n*\r\n* Notes:\r\n*   Since this computation is done only once per reKey per 64 bits of key,\r\n*   the performance impact of this routine is imperceptible. The RS code\r\n*   chosen has \"simple\" coefficients to allow smartcard/hardware implementation\r\n*   without lookup tables.\r\n*\r\n-****************************************************************************/\r\nDWORD RS_MDS_Encode(DWORD k0,DWORD k1)\r\n    {\r\n    int i,j;\r\n    DWORD r;\r\n\r\n    for (i=r=0;i<2;i++)\r\n        {\r\n        r ^= (i) ? k0 : k1;         /* merge in 32 more key bits */\r\n        for (j=0;j<4;j++)           /* shift one byte at a time */\r\n            RS_rem(r);              \r\n        }\r\n    return r;\r\n    }\r\n\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    BuildMDS\r\n*\r\n* Function:         Initialize the MDStab array\r\n*\r\n* Arguments:        None.\r\n*\r\n* Return:           None.\r\n*\r\n* Notes:\r\n*   Here we precompute all the fixed MDS table.  This only needs to be done\r\n*   one time at initialization, after which the table is \"CONST\".\r\n*\r\n-****************************************************************************/\r\nvoid BuildMDS(void)\r\n    {\r\n    int i;\r\n    DWORD d;\r\n    BYTE m1[2],mX[2],mY[4];\r\n\r\n    for (i=0;i<256;i++)\r\n        {\r\n        m1[0]=P8x8[0][i];       /* compute all the matrix elements */\r\n        mX[0]=(BYTE) Mul_X(m1[0]);\r\n        mY[0]=(BYTE) Mul_Y(m1[0]);\r\n\r\n        m1[1]=P8x8[1][i];\r\n        mX[1]=(BYTE) Mul_X(m1[1]);\r\n        mY[1]=(BYTE) Mul_Y(m1[1]);\r\n\r\n#undef  Mul_1                   /* change what the pre-processor does with Mij */\r\n#undef  Mul_X\r\n#undef  Mul_Y\r\n#define Mul_1   m1              /* It will now access m01[], m5B[], and mEF[] */\r\n#define Mul_X   mX              \r\n#define Mul_Y   mY\r\n\r\n#define SetMDS(N)                   \\\r\n        b0(d) = M0##N[P_##N##0];    \\\r\n        b1(d) = M1##N[P_##N##0];    \\\r\n        b2(d) = M2##N[P_##N##0];    \\\r\n        b3(d) = M3##N[P_##N##0];    \\\r\n        MDStab[N][i] = d;\r\n\r\n        SetMDS(0);              /* fill in the matrix with elements computed above */\r\n        SetMDS(1);\r\n        SetMDS(2);\r\n        SetMDS(3);\r\n        }\r\n#undef  Mul_1\r\n#undef  Mul_X\r\n#undef  Mul_Y\r\n#define Mul_1   Mx_1            /* re-enable true multiply */\r\n#define Mul_X   Mx_X\r\n#define Mul_Y   Mx_Y\r\n    \r\n#if BIG_TAB\r\n    {\r\n    int j,k;\r\n    BYTE *q0,*q1;\r\n\r\n    for (i=0;i<4;i++)\r\n        {\r\n        switch (i)\r\n            {\r\n            case 0: q0=p8(01); q1=p8(02);   break;\r\n            case 1: q0=p8(11); q1=p8(12);   break;\r\n            case 2: q0=p8(21); q1=p8(22);   break;\r\n            case 3: q0=p8(31); q1=p8(32);   break;\r\n            }\r\n        for (j=0;j<256;j++)\r\n            for (k=0;k<256;k++)\r\n                bigTab[i][j][k]=q0[q1[k]^j];\r\n        }\r\n    }\r\n#endif\r\n\r\n    needToBuildMDS=0;           /* NEVER modify the table again! */\r\n    }\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    ReverseRoundSubkeys\r\n*\r\n* Function:         Reverse order of round subkeys to switch between encrypt/decrypt\r\n*\r\n* Arguments:        key     =   ptr to keyInstance to be reversed\r\n*                   newDir  =   new direction value\r\n*\r\n* Return:           None.\r\n*\r\n* Notes:\r\n*   This optimization allows both blockEncrypt and blockDecrypt to use the same\r\n*   \"fallthru\" switch statement based on the number of rounds.\r\n*   Note that key->numRounds must be even and >= 2 here.\r\n*\r\n-****************************************************************************/\r\nvoid ReverseRoundSubkeys(keyInstance *key,BYTE newDir)\r\n    {\r\n    DWORD t0,t1;\r\n    register DWORD *r0=key->subKeys+ROUND_SUBKEYS;\r\n    register DWORD *r1=r0 + 2*key->numRounds - 2;\r\n\r\n    for (;r0 < r1;r0+=2,r1-=2)\r\n        {\r\n        t0=r0[0];           /* swap the order */\r\n        t1=r0[1];\r\n        r0[0]=r1[0];        /* but keep relative order within pairs */\r\n        r0[1]=r1[1];\r\n        r1[0]=t0;\r\n        r1[1]=t1;\r\n        }\r\n\r\n    key->direction=newDir;\r\n    }\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    Xor256\r\n*\r\n* Function:         Copy an 8-bit permutation (256 bytes), xoring with a byte\r\n*\r\n* Arguments:        dst     =   where to put result\r\n*                   src     =   where to get data (can be same asa dst)\r\n*                   b       =   byte to xor\r\n*\r\n* Return:           None\r\n*\r\n* Notes:\r\n*   BorlandC's optimization is terrible!  When we put the code inline,\r\n*   it generates fairly good code in the *following* segment (not in the Xor256\r\n*   code itself).  If the call is made, the code following the call is awful!\r\n*   The penalty is nearly 50%!  So we take the code size hit for inlining for\r\n*   Borland, while Microsoft happily works with a call.\r\n*\r\n-****************************************************************************/\r\n#if defined(__BORLANDC__)   /* do it inline */\r\n#define Xor32(dst,src,i) { ((DWORD *)dst)[i] = ((DWORD *)src)[i] ^ tmpX; } \r\n#define Xor256(dst,src,b)               \\\r\n    {                                   \\\r\n    register DWORD tmpX=0x01010101u * b;\\\r\n    for (i=0;i<64;i+=4)                 \\\r\n        { Xor32(dst,src,i  ); Xor32(dst,src,i+1); Xor32(dst,src,i+2); Xor32(dst,src,i+3); } \\\r\n    }\r\n#else                       /* do it as a function call */\r\nvoid Xor256(void *dst,void *src,BYTE b)\r\n    {\r\n    register DWORD  x=b*0x01010101u;    /* replicate byte to all four bytes */\r\n    register DWORD *d=(DWORD *)dst;\r\n    register DWORD *s=(DWORD *)src;\r\n#define X_8(N)  { d[N]=s[N] ^ x; d[N+1]=s[N+1] ^ x; }\r\n#define X_32(N) { X_8(N); X_8(N+2); X_8(N+4); X_8(N+6); }\r\n    X_32(0 ); X_32( 8); X_32(16); X_32(24); /* all inline */\r\n    d+=32;  /* keep offsets small! */\r\n    s+=32;\r\n    X_32(0 ); X_32( 8); X_32(16); X_32(24); /* all inline */\r\n    }\r\n#endif\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    reKey\r\n*\r\n* Function:         Initialize the Twofish key schedule from key32\r\n*\r\n* Arguments:        key         =   ptr to keyInstance to be initialized\r\n*\r\n* Return:           TRUE on success\r\n*\r\n* Notes:\r\n*   Here we precompute all the round subkeys, although that is not actually\r\n*   required.  For example, on a smartcard, the round subkeys can \r\n*   be generated on-the-fly using f32()\r\n*\r\n-****************************************************************************/\r\nint reKey(keyInstance *key)\r\n    {\r\n    int     i,j,k64Cnt,keyLen;\r\n    int     subkeyCnt;\r\n    DWORD   A=0,B=0,q;\r\n    DWORD   sKey[MAX_KEY_BITS/64],k32e[MAX_KEY_BITS/64],k32o[MAX_KEY_BITS/64];\r\n    BYTE    L0[256],L1[256];    /* small local 8-bit permutations */\r\n\r\n#if VALIDATE_PARMS\r\n  #if ALIGN32\r\n    if (((int)key) & 3)\r\n        return BAD_ALIGN32;\r\n    if ((key->keyLen % 64) || (key->keyLen < MIN_KEY_BITS))\r\n        return BAD_KEY_INSTANCE;\r\n  #endif\r\n#endif\r\n\r\n    if (needToBuildMDS)         /* do this one time only */\r\n        BuildMDS();\r\n\r\n#define F32(res,x,k32)  \\\r\n    {                                                           \\\r\n    DWORD t=x;                                                  \\\r\n    switch (k64Cnt & 3)                                         \\\r\n        {                                                       \\\r\n        case 0:  /* same as 4 */                                \\\r\n                    b0(t)   = p8(04)[b0(t)] ^ b0(k32[3]);       \\\r\n                    b1(t)   = p8(14)[b1(t)] ^ b1(k32[3]);       \\\r\n                    b2(t)   = p8(24)[b2(t)] ^ b2(k32[3]);       \\\r\n                    b3(t)   = p8(34)[b3(t)] ^ b3(k32[3]);       \\\r\n                 /* fall thru, having pre-processed t */        \\\r\n        case 3:     b0(t)   = p8(03)[b0(t)] ^ b0(k32[2]);       \\\r\n                    b1(t)   = p8(13)[b1(t)] ^ b1(k32[2]);       \\\r\n                    b2(t)   = p8(23)[b2(t)] ^ b2(k32[2]);       \\\r\n                    b3(t)   = p8(33)[b3(t)] ^ b3(k32[2]);       \\\r\n                 /* fall thru, having pre-processed t */        \\\r\n        case 2:  /* 128-bit keys (optimize for this case) */    \\\r\n            res=    MDStab[0][p8(01)[p8(02)[b0(t)] ^ b0(k32[1])] ^ b0(k32[0])] ^    \\\r\n                    MDStab[1][p8(11)[p8(12)[b1(t)] ^ b1(k32[1])] ^ b1(k32[0])] ^    \\\r\n                    MDStab[2][p8(21)[p8(22)[b2(t)] ^ b2(k32[1])] ^ b2(k32[0])] ^    \\\r\n                    MDStab[3][p8(31)[p8(32)[b3(t)] ^ b3(k32[1])] ^ b3(k32[0])] ;    \\\r\n        }                                                       \\\r\n    }\r\n\r\n\r\n#if !CHECK_TABLE\r\n#if defined(USE_ASM)                /* only do this if not using assember */\r\nif (!(useAsm & 4))\r\n#endif\r\n#endif\r\n    {\r\n    subkeyCnt = ROUND_SUBKEYS + 2*key->numRounds;\r\n    keyLen=key->keyLen;\r\n    k64Cnt=(keyLen+63)/64;          /* number of 64-bit key words */\r\n    for (i=0,j=k64Cnt-1;i<k64Cnt;i++,j--)\r\n        {                           /* split into even/odd key dwords */\r\n        k32e[i]=key->key32[2*i  ];\r\n        k32o[i]=key->key32[2*i+1];\r\n        /* compute S-box keys using (12,8) Reed-Solomon code over GF(256) */\r\n        sKey[j]=key->sboxKeys[j]=RS_MDS_Encode(k32e[i],k32o[i]);    /* reverse order */\r\n        }\r\n    }\r\n\r\n#ifdef USE_ASM\r\nif (useAsm & 4)\r\n    {\r\n    #if defined(COMPILE_KEY) && defined(USE_ASM)\r\n        key->keySig     = VALID_SIG;            /* show that we are initialized */\r\n        key->codeSize   = sizeof(key->compiledCode);    /* set size */\r\n    #endif\r\n    reKey_86(key);\r\n    }\r\nelse\r\n#endif\r\n    {\r\n    for (i=q=0;i<subkeyCnt/2;i++,q+=SK_STEP)    \r\n        {                           /* compute round subkeys for PHT */\r\n        F32(A,q        ,k32e);      /* A uses even key dwords */\r\n        F32(B,q+SK_BUMP,k32o);      /* B uses odd  key dwords */\r\n        B = ROL(B,8);\r\n        key->subKeys[2*i  ] = A+B;  /* combine with a PHT */\r\n        B = A + 2*B;\r\n        key->subKeys[2*i+1] = ROL(B,SK_ROTL);\r\n        }\r\n#if !defined(ZERO_KEY)\r\n    switch (keyLen) /* case out key length for speed in generating S-boxes */\r\n        {\r\n        case 128:\r\n        #if defined(FULL_KEY) || defined(PART_KEY)\r\n#if BIG_TAB\r\n            #define one128(N,J) sbSet(N,i,J,L0[i+J])\r\n            #define sb128(N) {                      \\\r\n                BYTE *qq=bigTab[N][b##N(sKey[1])];  \\\r\n                Xor256(L0,qq,b##N(sKey[0]));        \\\r\n                for (i=0;i<256;i+=2) { one128(N,0); one128(N,1); } }\r\n#else\r\n            #define one128(N,J) sbSet(N,i,J,p8(N##1)[L0[i+J]]^k0)\r\n            #define sb128(N) {                  \\\r\n                Xor256(L0,p8(N##2),b##N(sKey[1]));  \\\r\n                { register DWORD k0=b##N(sKey[0]);  \\\r\n                for (i=0;i<256;i+=2) { one128(N,0); one128(N,1); } } }\r\n#endif\r\n        #elif defined(MIN_KEY)\r\n            #define sb128(N) Xor256(_sBox8_(N),p8(N##2),b##N(sKey[1]))\r\n        #endif\r\n            sb128(0); sb128(1); sb128(2); sb128(3);\r\n            break;\r\n        case 192:\r\n        #if defined(FULL_KEY) || defined(PART_KEY)\r\n            #define one192(N,J) sbSet(N,i,J,p8(N##1)[p8(N##2)[L0[i+J]]^k1]^k0)\r\n            #define sb192(N) {                      \\\r\n                Xor256(L0,p8(N##3),b##N(sKey[2]));  \\\r\n                { register DWORD k0=b##N(sKey[0]);  \\\r\n                  register DWORD k1=b##N(sKey[1]);  \\\r\n                  for (i=0;i<256;i+=2) { one192(N,0); one192(N,1); } } }\r\n        #elif defined(MIN_KEY)\r\n            #define one192(N,J) sbSet(N,i,J,p8(N##2)[L0[i+J]]^k1)\r\n            #define sb192(N) {                      \\\r\n                Xor256(L0,p8(N##3),b##N(sKey[2]));  \\\r\n                { register DWORD k1=b##N(sKey[1]);  \\\r\n                  for (i=0;i<256;i+=2) { one192(N,0); one192(N,1); } } }\r\n        #endif\r\n            sb192(0); sb192(1); sb192(2); sb192(3);\r\n            break;\r\n        case 256:\r\n        #if defined(FULL_KEY) || defined(PART_KEY)\r\n            #define one256(N,J) sbSet(N,i,J,p8(N##1)[p8(N##2)[L0[i+J]]^k1]^k0)\r\n            #define sb256(N) {                                      \\\r\n                Xor256(L1,p8(N##4),b##N(sKey[3]));                  \\\r\n                for (i=0;i<256;i+=2) {L0[i  ]=p8(N##3)[L1[i]];      \\\r\n                                      L0[i+1]=p8(N##3)[L1[i+1]]; }  \\\r\n                Xor256(L0,L0,b##N(sKey[2]));                        \\\r\n                { register DWORD k0=b##N(sKey[0]);                  \\\r\n                  register DWORD k1=b##N(sKey[1]);                  \\\r\n                  for (i=0;i<256;i+=2) { one256(N,0); one256(N,1); } } }\r\n        #elif defined(MIN_KEY)\r\n            #define one256(N,J) sbSet(N,i,J,p8(N##2)[L0[i+J]]^k1)\r\n            #define sb256(N) {                                      \\\r\n                Xor256(L1,p8(N##4),b##N(sKey[3]));                  \\\r\n                for (i=0;i<256;i+=2) {L0[i  ]=p8(N##3)[L1[i]];      \\\r\n                                      L0[i+1]=p8(N##3)[L1[i+1]]; }  \\\r\n                Xor256(L0,L0,b##N(sKey[2]));                        \\\r\n                { register DWORD k1=b##N(sKey[1]);                  \\\r\n                  for (i=0;i<256;i+=2) { one256(N,0); one256(N,1); } } }\r\n        #endif\r\n            sb256(0); sb256(1); sb256(2); sb256(3);\r\n            break;\r\n        }\r\n#endif\r\n    }\r\n\r\n#if CHECK_TABLE                     /* sanity check  vs. pedagogical code*/\r\n    {\r\n    GetSboxKey;\r\n    for (i=0;i<subkeyCnt/2;i++)\r\n        {\r\n        A = f32(i*SK_STEP        ,k32e,keyLen); /* A uses even key dwords */\r\n        B = f32(i*SK_STEP+SK_BUMP,k32o,keyLen); /* B uses odd  key dwords */\r\n        B = ROL(B,8);\r\n        assert(key->subKeys[2*i  ] == A+  B);\r\n        assert(key->subKeys[2*i+1] == ROL(A+2*B,SK_ROTL));\r\n        }\r\n  #if !defined(ZERO_KEY)            /* any S-boxes to check? */\r\n    for (i=q=0;i<256;i++,q+=0x01010101)\r\n        assert(f32(q,key->sboxKeys,keyLen) == Fe32_(q,0));\r\n  #endif\r\n    }\r\n#endif /* CHECK_TABLE */\r\n\r\n    DebugDumpKey(key);\r\n\r\n    if (key->direction == DIR_ENCRYPT)  \r\n        ReverseRoundSubkeys(key,DIR_ENCRYPT);   /* reverse the round subkey order */\r\n\r\n    return TRUE;\r\n    }\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    makeKey\r\n*\r\n* Function:         Initialize the Twofish key schedule\r\n*\r\n* Arguments:        key         =   ptr to keyInstance to be initialized\r\n*                   direction   =   DIR_ENCRYPT or DIR_DECRYPT\r\n*                   keyLen      =   # bits of key text at *keyMaterial\r\n*                   keyMaterial =   ptr to hex ASCII chars representing key bits\r\n*\r\n* Return:           TRUE on success\r\n*                   else error code (e.g., BAD_KEY_DIR)\r\n*\r\n* Notes:    This parses the key bits from keyMaterial.  Zeroes out unused key bits\r\n*\r\n-****************************************************************************/\r\nint makeKey(keyInstance *key, BYTE direction, int keyLen,CONST char *keyMaterial)\r\n    {\r\n#if VALIDATE_PARMS              /* first, sanity check on parameters */\r\n    if (key == NULL)            \r\n        return BAD_KEY_INSTANCE;/* must have a keyInstance to initialize */\r\n    if ((direction != DIR_ENCRYPT) && (direction != DIR_DECRYPT))\r\n        return BAD_KEY_DIR;     /* must have valid direction */\r\n    if ((keyLen > MAX_KEY_BITS) || (keyLen < 8) || (keyLen & 0x3F))\r\n        return BAD_KEY_MAT;     /* length must be valid */\r\n    key->keySig = VALID_SIG;    /* show that we are initialized */\r\n  #if ALIGN32\r\n    if ((((int)key) & 3) || (((int)key->key32) & 3))\r\n        return BAD_ALIGN32;\r\n  #endif\r\n#endif\r\n\r\n    key->direction  = direction;/* set our cipher direction */\r\n    key->keyLen     = (keyLen+63) & ~63;        /* round up to multiple of 64 */\r\n    key->numRounds  = numRounds[(keyLen-1)/64];\r\n    memset(key->key32,0,sizeof(key->key32));    /* zero unused bits */\r\n    key->keyMaterial[MAX_KEY_SIZE]=0;   /* terminate ASCII string */\r\n\r\n    if ((keyMaterial == NULL) || (keyMaterial[0]==0))\r\n        return TRUE;            /* allow a \"dummy\" call */\r\n        \r\n    if (ParseHexDword(keyLen,keyMaterial,key->key32,key->keyMaterial))\r\n        return BAD_KEY_MAT; \r\n\r\n    return reKey(key);          /* generate round subkeys */\r\n    }\r\n\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    cipherInit\r\n*\r\n* Function:         Initialize the Twofish cipher in a given mode\r\n*\r\n* Arguments:        cipher      =   ptr to cipherInstance to be initialized\r\n*                   mode        =   MODE_ECB, MODE_CBC, or MODE_CFB1\r\n*                   IV          =   ptr to hex ASCII test representing IV bytes\r\n*\r\n* Return:           TRUE on success\r\n*                   else error code (e.g., BAD_CIPHER_MODE)\r\n*\r\n-****************************************************************************/\r\nint cipherInit(cipherInstance *cipher, BYTE mode,CONST char *IV)\r\n    {\r\n    int i;\r\n#if VALIDATE_PARMS              /* first, sanity check on parameters */\r\n    if (cipher == NULL)         \r\n        return BAD_PARAMS;      /* must have a cipherInstance to initialize */\r\n    if ((mode != MODE_ECB) && (mode != MODE_CBC) && (mode != MODE_CFB1))\r\n        return BAD_CIPHER_MODE; /* must have valid cipher mode */\r\n    cipher->cipherSig   =   VALID_SIG;\r\n  #if ALIGN32\r\n    if ((((int)cipher) & 3) || (((int)cipher->IV) & 3) || (((int)cipher->iv32) & 3))\r\n        return BAD_ALIGN32;\r\n  #endif\r\n#endif\r\n\r\n    if ((mode != MODE_ECB) && (IV)) /* parse the IV */\r\n        {\r\n        if (ParseHexDword(BLOCK_SIZE,IV,cipher->iv32,NULL))\r\n            return BAD_IV_MAT;\r\n        for (i=0;i<BLOCK_SIZE/32;i++)   /* make byte-oriented copy for CFB1 */\r\n            ((DWORD *)cipher->IV)[i] = Bswap(cipher->iv32[i]);\r\n        }\r\n\r\n    cipher->mode        =   mode;\r\n\r\n    return TRUE;\r\n    }\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    blockEncrypt\r\n*\r\n* Function:         Encrypt block(s) of data using Twofish\r\n*\r\n* Arguments:        cipher      =   ptr to already initialized cipherInstance\r\n*                   key         =   ptr to already initialized keyInstance\r\n*                   input       =   ptr to data blocks to be encrypted\r\n*                   inputLen    =   # bits to encrypt (multiple of blockSize)\r\n*                   outBuffer   =   ptr to where to put encrypted blocks\r\n*\r\n* Return:           # bits ciphered (>= 0)\r\n*                   else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)\r\n*\r\n* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.\r\n*        If inputLen is not a multiple of BLOCK_SIZE bits in those modes,\r\n*        an error BAD_INPUT_LEN is returned.  In CFB1 mode, all block \r\n*        sizes can be supported.\r\n*\r\n-****************************************************************************/\r\nint blockEncrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,\r\n                int inputLen, BYTE *outBuffer)\r\n    {\r\n    int   i,n;                      /* loop counters */\r\n    DWORD x[BLOCK_SIZE/32];         /* block being encrypted */\r\n    DWORD t0,t1;                    /* temp variables */\r\n    int   rounds=key->numRounds;    /* number of rounds */\r\n    BYTE  bit,bit0,ctBit,carry;     /* temps for CFB */\r\n\r\n    /* make local copies of things for faster access */\r\n    int   mode = cipher->mode;\r\n    DWORD sk[TOTAL_SUBKEYS];\r\n    DWORD IV[BLOCK_SIZE/32];\r\n\r\n    GetSboxKey;\r\n\r\n#if VALIDATE_PARMS\r\n    if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))\r\n        return BAD_CIPHER_STATE;\r\n    if ((key == NULL) || (key->keySig != VALID_SIG))\r\n        return BAD_KEY_INSTANCE;\r\n    if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))\r\n        return BAD_KEY_INSTANCE;\r\n    if ((mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))\r\n        return BAD_INPUT_LEN;\r\n  #if ALIGN32\r\n    if ( (((int)cipher) & 3) || (((int)key      ) & 3) ||\r\n         (((int)input ) & 3) || (((int)outBuffer) & 3))\r\n        return BAD_ALIGN32;\r\n  #endif\r\n#endif\r\n\r\n    if (mode == MODE_CFB1)\r\n        {   /* use recursion here to handle CFB, one block at a time */\r\n        cipher->mode = MODE_ECB;    /* do encryption in ECB */\r\n        for (n=0;n<inputLen;n++)\r\n            {\r\n            blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);\r\n            bit0  = 0x80 >> (n & 7);/* which bit position in byte */\r\n            ctBit = (input[n/8] & bit0) ^ ((((BYTE *) x)[0] & 0x80) >> (n&7));\r\n            outBuffer[n/8] = (outBuffer[n/8] & ~ bit0) | ctBit;\r\n            carry = ctBit >> (7 - (n&7));\r\n            for (i=BLOCK_SIZE/8-1;i>=0;i--)\r\n                {\r\n                bit = cipher->IV[i] >> 7;   /* save next \"carry\" from shift */\r\n                cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;\r\n                carry = bit;\r\n                }\r\n            }\r\n        cipher->mode = MODE_CFB1;   /* restore mode for next time */\r\n        return inputLen;\r\n        }\r\n\r\n    /* here for ECB, CBC modes */\r\n    if (key->direction != DIR_ENCRYPT)\r\n        ReverseRoundSubkeys(key,DIR_ENCRYPT);   /* reverse the round subkey order */\r\n\r\n#ifdef USE_ASM\r\n    if ((useAsm & 1) && (inputLen))\r\n  #ifdef COMPILE_KEY\r\n        if (key->keySig == VALID_SIG)\r\n            return ((CipherProc *)(key->encryptFuncPtr))(cipher,key,input,inputLen,outBuffer);\r\n  #else \r\n        return (*blockEncrypt_86)(cipher,key,input,inputLen,outBuffer);\r\n  #endif\r\n#endif\r\n    /* make local copy of subkeys for speed */\r\n    memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));\r\n    if (mode == MODE_CBC)\r\n        BlockCopy(IV,cipher->iv32)\r\n    else\r\n        IV[0]=IV[1]=IV[2]=IV[3]=0;\r\n\r\n    for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)\r\n        {\r\n#ifdef DEBUG\r\n        DebugDump(input,\"\\n\",-1,0,0,0,1);\r\n        if (cipher->mode == MODE_CBC)\r\n            DebugDump(cipher->iv32,\"\",IV_ROUND,0,0,0,0);\r\n#endif\r\n#define LoadBlockE(N)  x[N]=Bswap(((DWORD *)input)[N]) ^ sk[INPUT_WHITEN+N] ^ IV[N]\r\n        LoadBlockE(0);  LoadBlockE(1);  LoadBlockE(2);  LoadBlockE(3);\r\n        DebugDump(x,\"\",0,0,0,0,0);\r\n#define EncryptRound(K,R,id)    \\\r\n            t0     = Fe32##id(x[K  ],0);                    \\\r\n            t1     = Fe32##id(x[K^1],3);                    \\\r\n            x[K^3] = ROL(x[K^3],1);                         \\\r\n            x[K^2]^= t0 +   t1 + sk[ROUND_SUBKEYS+2*(R)  ]; \\\r\n            x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1]; \\\r\n            x[K^2] = ROR(x[K^2],1);                         \\\r\n            DebugDump(x,\"\",rounds-(R),0,0,1,0);\r\n#define     Encrypt2(R,id)  { EncryptRound(0,R+1,id); EncryptRound(2,R,id); }\r\n\r\n#if defined(ZERO_KEY)\r\n        switch (key->keyLen)\r\n            {\r\n            case 128:\r\n                for (i=rounds-2;i>=0;i-=2)\r\n                    Encrypt2(i,_128);\r\n                break;\r\n            case 192:\r\n                for (i=rounds-2;i>=0;i-=2)\r\n                    Encrypt2(i,_192);\r\n                break;\r\n            case 256:\r\n                for (i=rounds-2;i>=0;i-=2)\r\n                    Encrypt2(i,_256);\r\n                break;\r\n            }\r\n#else\r\n        Encrypt2(14,_);\r\n        Encrypt2(12,_);\r\n        Encrypt2(10,_);\r\n        Encrypt2( 8,_);\r\n        Encrypt2( 6,_);\r\n        Encrypt2( 4,_);\r\n        Encrypt2( 2,_);\r\n        Encrypt2( 0,_);\r\n#endif\r\n\r\n        /* need to do (or undo, depending on your point of view) final swap */\r\n#if LittleEndian\r\n#define StoreBlockE(N)  ((DWORD *)outBuffer)[N]=x[N^2] ^ sk[OUTPUT_WHITEN+N]\r\n#else\r\n#define StoreBlockE(N)  { t0=x[N^2] ^ sk[OUTPUT_WHITEN+N]; ((DWORD *)outBuffer)[N]=Bswap(t0); }\r\n#endif\r\n        StoreBlockE(0); StoreBlockE(1); StoreBlockE(2); StoreBlockE(3);\r\n        if (mode == MODE_CBC)\r\n            {\r\n            IV[0]=Bswap(((DWORD *)outBuffer)[0]);\r\n            IV[1]=Bswap(((DWORD *)outBuffer)[1]);\r\n            IV[2]=Bswap(((DWORD *)outBuffer)[2]);\r\n            IV[3]=Bswap(((DWORD *)outBuffer)[3]);\r\n            }\r\n#ifdef DEBUG\r\n        DebugDump(outBuffer,\"\",rounds+1,0,0,0,1);\r\n        if (cipher->mode == MODE_CBC)\r\n            DebugDump(cipher->iv32,\"\",IV_ROUND,0,0,0,0);\r\n#endif\r\n        }\r\n\r\n    if (mode == MODE_CBC)\r\n        BlockCopy(cipher->iv32,IV);\r\n\r\n    return inputLen;\r\n    }\r\n\r\n/*\r\n+*****************************************************************************\r\n*\r\n* Function Name:    blockDecrypt\r\n*\r\n* Function:         Decrypt block(s) of data using Twofish\r\n*\r\n* Arguments:        cipher      =   ptr to already initialized cipherInstance\r\n*                   key         =   ptr to already initialized keyInstance\r\n*                   input       =   ptr to data blocks to be decrypted\r\n*                   inputLen    =   # bits to encrypt (multiple of blockSize)\r\n*                   outBuffer   =   ptr to where to put decrypted blocks\r\n*\r\n* Return:           # bits ciphered (>= 0)\r\n*                   else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)\r\n*\r\n* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.\r\n*        If inputLen is not a multiple of BLOCK_SIZE bits in those modes,\r\n*        an error BAD_INPUT_LEN is returned.  In CFB1 mode, all block \r\n*        sizes can be supported.\r\n*\r\n-****************************************************************************/\r\nint blockDecrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,\r\n                int inputLen, BYTE *outBuffer)\r\n    {\r\n    int   i,n;                      /* loop counters */\r\n    DWORD x[BLOCK_SIZE/32];         /* block being encrypted */\r\n    DWORD t0,t1;                    /* temp variables */\r\n    int   rounds=key->numRounds;    /* number of rounds */\r\n    BYTE  bit,bit0,ctBit,carry;     /* temps for CFB */\r\n\r\n    /* make local copies of things for faster access */\r\n    int   mode = cipher->mode;\r\n    DWORD sk[TOTAL_SUBKEYS];\r\n    DWORD IV[BLOCK_SIZE/32];\r\n\r\n    GetSboxKey;\r\n\r\n#if VALIDATE_PARMS\r\n    if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))\r\n        return BAD_CIPHER_STATE;\r\n    if ((key == NULL) || (key->keySig != VALID_SIG))\r\n        return BAD_KEY_INSTANCE;\r\n    if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))\r\n        return BAD_KEY_INSTANCE;\r\n    if ((cipher->mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))\r\n        return BAD_INPUT_LEN;\r\n  #if ALIGN32\r\n    if ( (((int)cipher) & 3) || (((int)key      ) & 3) ||\r\n         (((int)input)  & 3) || (((int)outBuffer) & 3))\r\n        return BAD_ALIGN32;\r\n  #endif\r\n#endif\r\n\r\n    if (cipher->mode == MODE_CFB1)\r\n        {   /* use blockEncrypt here to handle CFB, one block at a time */\r\n        cipher->mode = MODE_ECB;    /* do encryption in ECB */\r\n        for (n=0;n<inputLen;n++)\r\n            {\r\n            blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);\r\n            bit0  = 0x80 >> (n & 7);\r\n            ctBit = input[n/8] & bit0;\r\n            outBuffer[n/8] = (outBuffer[n/8] & ~ bit0) |\r\n                             (ctBit ^ ((((BYTE *) x)[0] & 0x80) >> (n&7)));\r\n            carry = ctBit >> (7 - (n&7));\r\n            for (i=BLOCK_SIZE/8-1;i>=0;i--)\r\n                {\r\n                bit = cipher->IV[i] >> 7;   /* save next \"carry\" from shift */\r\n                cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;\r\n                carry = bit;\r\n                }\r\n            }\r\n        cipher->mode = MODE_CFB1;   /* restore mode for next time */\r\n        return inputLen;\r\n        }\r\n\r\n    /* here for ECB, CBC modes */\r\n    if (key->direction != DIR_DECRYPT)\r\n        ReverseRoundSubkeys(key,DIR_DECRYPT);   /* reverse the round subkey order */\r\n#ifdef USE_ASM\r\n    if ((useAsm & 2) && (inputLen))\r\n  #ifdef COMPILE_KEY\r\n        if (key->keySig == VALID_SIG)\r\n            return ((CipherProc *)(key->decryptFuncPtr))(cipher,key,input,inputLen,outBuffer);\r\n  #else \r\n        return (*blockDecrypt_86)(cipher,key,input,inputLen,outBuffer);\r\n  #endif\r\n#endif\r\n    /* make local copy of subkeys for speed */\r\n    memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));\r\n    if (mode == MODE_CBC)\r\n        BlockCopy(IV,cipher->iv32)\r\n    else\r\n        IV[0]=IV[1]=IV[2]=IV[3]=0;\r\n\r\n    for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)\r\n        {\r\n        DebugDump(input,\"\\n\",rounds+1,0,0,0,1);\r\n#define LoadBlockD(N) x[N^2]=Bswap(((DWORD *)input)[N]) ^ sk[OUTPUT_WHITEN+N]\r\n        LoadBlockD(0);  LoadBlockD(1);  LoadBlockD(2);  LoadBlockD(3);\r\n\r\n#define DecryptRound(K,R,id)                                \\\r\n            t0     = Fe32##id(x[K  ],0);                    \\\r\n            t1     = Fe32##id(x[K^1],3);                    \\\r\n            DebugDump(x,\"\",(R)+1,0,0,1,0);                  \\\r\n            x[K^2] = ROL (x[K^2],1);                        \\\r\n            x[K^2]^= t0 +   t1 + sk[ROUND_SUBKEYS+2*(R)  ]; \\\r\n            x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1]; \\\r\n            x[K^3] = ROR (x[K^3],1);                        \\\r\n\r\n#define     Decrypt2(R,id)  { DecryptRound(2,R+1,id); DecryptRound(0,R,id); }\r\n\r\n#if defined(ZERO_KEY)\r\n        switch (key->keyLen)\r\n            {\r\n            case 128:\r\n                for (i=rounds-2;i>=0;i-=2)\r\n                    Decrypt2(i,_128);\r\n                break;\r\n            case 192:\r\n                for (i=rounds-2;i>=0;i-=2)\r\n                    Decrypt2(i,_192);\r\n                break;\r\n            case 256:\r\n                for (i=rounds-2;i>=0;i-=2)\r\n                    Decrypt2(i,_256);\r\n                break;\r\n            }\r\n#else\r\n        {\r\n        Decrypt2(14,_);\r\n        Decrypt2(12,_);\r\n        Decrypt2(10,_);\r\n        Decrypt2( 8,_);\r\n        Decrypt2( 6,_);\r\n        Decrypt2( 4,_);\r\n        Decrypt2( 2,_);\r\n        Decrypt2( 0,_);\r\n        }\r\n#endif\r\n        DebugDump(x,\"\",0,0,0,0,0);\r\n        if (cipher->mode == MODE_ECB)\r\n            {\r\n#if LittleEndian\r\n#define StoreBlockD(N)  ((DWORD *)outBuffer)[N] = x[N] ^ sk[INPUT_WHITEN+N]\r\n#else\r\n#define StoreBlockD(N)  { t0=x[N]^sk[INPUT_WHITEN+N]; ((DWORD *)outBuffer)[N] = Bswap(t0); }\r\n#endif\r\n            StoreBlockD(0); StoreBlockD(1); StoreBlockD(2); StoreBlockD(3);\r\n#undef  StoreBlockD\r\n            DebugDump(outBuffer,\"\",-1,0,0,0,1);\r\n            continue;\r\n            }\r\n        else\r\n            {\r\n#define StoreBlockD(N)  x[N]   ^= sk[INPUT_WHITEN+N] ^ IV[N];   \\\r\n                        IV[N]   = Bswap(((DWORD *)input)[N]);   \\\r\n                        ((DWORD *)outBuffer)[N] = Bswap(x[N]);\r\n            StoreBlockD(0); StoreBlockD(1); StoreBlockD(2); StoreBlockD(3);\r\n#undef  StoreBlockD\r\n            DebugDump(outBuffer,\"\",-1,0,0,0,1);\r\n            }\r\n        }\r\n    if (mode == MODE_CBC)   /* restore iv32 to cipher */\r\n        BlockCopy(cipher->iv32,IV)\r\n\r\n    return inputLen;\r\n    }\r\n\r\n#ifdef GetCodeSize\r\nDWORD TwofishCodeSize(void)\r\n    {\r\n    DWORD x= Here(0);\r\n#ifdef USE_ASM\r\n    if (useAsm & 3)\r\n        return TwofishAsmCodeSize();\r\n#endif\r\n    return x - TwofishCodeStart();\r\n    };\r\n#endif\r\n\r\n"
  },
  {
    "path": "Crypt/twofish.h",
    "content": "/* aes.h */\r\n\r\n/* ---------- See examples at end of this file for typical usage -------- */\r\n\r\n/* AES Cipher header file for ANSI C Submissions\r\n    Lawrence E. Bassham III\r\n    Computer Security Division\r\n    National Institute of Standards and Technology\r\n\r\n    This sample is to assist implementers developing to the\r\nCryptographic API Profile for AES Candidate Algorithm Submissions.\r\nPlease consult this document as a cross-reference.\r\n    \r\n    ANY CHANGES, WHERE APPROPRIATE, TO INFORMATION PROVIDED IN THIS FILE\r\nMUST BE DOCUMENTED. CHANGES ARE ONLY APPROPRIATE WHERE SPECIFIED WITH\r\nTHE STRING \"CHANGE POSSIBLE\". FUNCTION CALLS AND THEIR PARAMETERS\r\nCANNOT BE CHANGED. STRUCTURES CAN BE ALTERED TO ALLOW IMPLEMENTERS TO\r\nINCLUDE IMPLEMENTATION SPECIFIC INFORMATION.\r\n*/\r\n\r\n/* Includes:\r\n    Standard include files\r\n*/\r\n\r\n#pragma once\r\n#pragma pack(1)\r\n\r\n#include    <stdio.h>\r\n#include    \"platform.h\"            /* platform-specific defines */\r\n\r\n/*  Defines:\r\n        Add any additional defines you need\r\n*/\r\n\r\n#define     DIR_ENCRYPT     0       /* Are we encrpyting? */\r\n#define     DIR_DECRYPT     1       /* Are we decrpyting? */\r\n#define     MODE_ECB        1       /* Are we ciphering in ECB mode? */\r\n#define     MODE_CBC        2       /* Are we ciphering in CBC mode? */\r\n#define     MODE_CFB1       3       /* Are we ciphering in 1-bit CFB mode? */\r\n\r\n#define     TRUE            1\r\n#define     FALSE           0\r\n\r\n#define     BAD_KEY_DIR         -1  /* Key direction is invalid (unknown value) */\r\n#define     BAD_KEY_MAT         -2  /* Key material not of correct length */\r\n#define     BAD_KEY_INSTANCE    -3  /* Key passed is not valid */\r\n#define     BAD_CIPHER_MODE     -4  /* Params struct passed to cipherInit invalid */\r\n#define     BAD_CIPHER_STATE    -5  /* Cipher in wrong state (e.g., not initialized) */\r\n\r\n/* CHANGE POSSIBLE: inclusion of algorithm specific defines */\r\n/* TWOFISH specific definitions */\r\n#define     MAX_KEY_SIZE        64  /* # of ASCII chars needed to represent a key */\r\n#define     MAX_IV_SIZE         16  /* # of bytes needed to represent an IV */\r\n#define     BAD_INPUT_LEN       -6  /* inputLen not a multiple of block size */\r\n#define     BAD_PARAMS          -7  /* invalid parameters */\r\n#define     BAD_IV_MAT          -8  /* invalid IV text */\r\n#define     BAD_ENDIAN          -9  /* incorrect endianness define */\r\n#define     BAD_ALIGN32         -10 /* incorrect 32-bit alignment */\r\n\r\n#define     BLOCK_SIZE          128 /* number of bits per block */\r\n#define     MAX_ROUNDS           16 /* max # rounds (for allocating subkey array) */\r\n#define     ROUNDS_128           16 /* default number of rounds for 128-bit keys*/\r\n#define     ROUNDS_192           16 /* default number of rounds for 192-bit keys*/\r\n#define     ROUNDS_256           16 /* default number of rounds for 256-bit keys*/\r\n#define     MAX_KEY_BITS        256 /* max number of bits of key */\r\n#define     MIN_KEY_BITS        128 /* min number of bits of key (zero pad) */\r\n#define     VALID_SIG    0x48534946 /* initialization signature ('FISH') */\r\n#define     MCT_OUTER           400 /* MCT outer loop */\r\n#define     MCT_INNER         10000 /* MCT inner loop */\r\n#define     REENTRANT             1 /* nonzero forces reentrant code (slightly slower) */\r\n\r\n#define     INPUT_WHITEN        0   /* subkey array indices */\r\n#define     OUTPUT_WHITEN       ( INPUT_WHITEN + BLOCK_SIZE/32)\r\n#define     ROUND_SUBKEYS       (OUTPUT_WHITEN + BLOCK_SIZE/32) /* use 2 * (# rounds) */\r\n#define     TOTAL_SUBKEYS       (ROUND_SUBKEYS + 2*MAX_ROUNDS)\r\n\r\n/* Typedefs:\r\n    Typedef'ed data storage elements. Add any algorithm specific\r\n    parameters at the bottom of the structs as appropriate.\r\n*/\r\n\r\ntypedef unsigned char BYTE;\r\ntypedef unsigned long DWORD;        /* 32-bit unsigned quantity */\r\ntypedef DWORD fullSbox[4][256];\r\n\r\n/* The structure for key information */\r\ntypedef struct \r\n    {\r\n    BYTE direction;                 /* Key used for encrypting or decrypting? */\r\n#if ALIGN32\r\n    BYTE dummyAlign[3];             /* keep 32-bit alignment */\r\n#endif\r\n    int  keyLen;                    /* Length of the key */\r\n    char keyMaterial[MAX_KEY_SIZE+4];/* Raw key data in ASCII */\r\n\r\n    /* Twofish-specific parameters: */\r\n    DWORD keySig;                   /* set to VALID_SIG by makeKey() */\r\n    int   numRounds;                /* number of rounds in cipher */\r\n    DWORD key32[MAX_KEY_BITS/32];   /* actual key bits, in dwords */\r\n    DWORD sboxKeys[MAX_KEY_BITS/64];/* key bits used for S-boxes */\r\n    DWORD subKeys[TOTAL_SUBKEYS];   /* round subkeys, input/output whitening bits */\r\n#if REENTRANT\r\n    fullSbox sBox8x32;              /* fully expanded S-box */\r\n  #if defined(COMPILE_KEY) && defined(USE_ASM)\r\n#undef  VALID_SIG\r\n#define VALID_SIG    0x504D4F43     /* 'COMP':  C is compiled with -DCOMPILE_KEY */\r\n    DWORD cSig1;                    /* set after first \"compile\" (zero at \"init\") */\r\n    void *encryptFuncPtr;           /* ptr to asm encrypt function */\r\n    void *decryptFuncPtr;           /* ptr to asm decrypt function */\r\n    DWORD codeSize;                 /* size of compiledCode */\r\n    DWORD cSig2;                    /* set after first \"compile\" */\r\n    BYTE  compiledCode[5000];       /* make room for the code itself */\r\n  #endif\r\n#endif\r\n    } keyInstance;\r\n\r\n/* The structure for cipher information */\r\ntypedef struct \r\n    {\r\n    BYTE  mode;                     /* MODE_ECB, MODE_CBC, or MODE_CFB1 */\r\n#if ALIGN32\r\n    BYTE dummyAlign[3];             /* keep 32-bit alignment */\r\n#endif\r\n    BYTE  IV[MAX_IV_SIZE];          /* CFB1 iv bytes  (CBC uses iv32) */\r\n\r\n    /* Twofish-specific parameters: */\r\n    DWORD cipherSig;                /* set to VALID_SIG by cipherInit() */\r\n    DWORD iv32[BLOCK_SIZE/32];      /* CBC IV bytes arranged as dwords */\r\n    } cipherInstance;\r\n\r\n/* Function protoypes */\r\n\r\n#ifdef __cplusplus\r\nextern \"C\"{\r\n#endif\r\n\r\nint makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial);\r\n\r\nint cipherInit(cipherInstance *cipher, BYTE mode, char *IV);\r\n\r\nint blockEncrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,\r\n                int inputLen, BYTE *outBuffer);\r\n\r\nint blockDecrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,\r\n                int inputLen, BYTE *outBuffer);\r\n\r\nint reKey(keyInstance *key);    /* do key schedule using modified key.keyDwords */\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n/* API to check table usage, for use in ECB_TBL KAT */\r\n#define     TAB_DISABLE         0\r\n#define     TAB_ENABLE          1\r\n#define     TAB_RESET           2\r\n#define     TAB_QUERY           3\r\n#define     TAB_MIN_QUERY       50\r\nint TableOp(int op);\r\n\r\n#ifndef CONST\r\n#define     CONST               /* helpful C++ syntax sugar, NOP for ANSI C */\r\n#endif\r\n\r\n#if BLOCK_SIZE == 128           /* optimize block copies */\r\n#define     Copy1(d,s,N)    ((DWORD *)(d))[N] = ((DWORD *)(s))[N]\r\n#define     BlockCopy(d,s)  { Copy1(d,s,0);Copy1(d,s,1);Copy1(d,s,2);Copy1(d,s,3); }\r\n#else\r\n#define     BlockCopy(d,s)  { memcpy(d,s,BLOCK_SIZE/8); }\r\n#endif\r\n"
  },
  {
    "path": "Crypt/uo_huffman.cpp",
    "content": "////////////////////////////////////////////////////////////////////////////////\r\n//\r\n// uo_huffman.cpp\r\n//\r\n//\r\n// Decompression code based\ton:\r\n// Ultimate\tMelange. Client\tfor\tUO-Emulators\r\n// Copyright (C) 2000 Axel Kittenberger\r\n//\r\n// This\tprogram\tis free\tsoftware; you can redistribute it and/or modify\r\n// it under\tthe\tterms of the GNU General Public\tLicense\tas published by\r\n// the Free\tSoftware Foundation; either\tversion\t2 of the License, or\r\n// (at your\toption)\tany\tlater version.\r\n//\r\n////////////////////////////////////////////////////////////////////////////////\r\n#include \"stdafx.h\"\r\n#include \"uo_huffman.h\"\r\n\r\n\r\n/*\r\nDecompression Table\r\nThis is\ta static huffman tree that is walked down for decompression,\r\nnegative nodes (and\t0) are final values,\r\npositive nodes point to\tother nodes.\r\nIf drawn this tree is sorted from up to\tdown (layer\tby layer)\r\nand\tleft to\tright.\r\n*/\r\nint Compression::DecompressionTree[] =\r\n{\r\n    /*   0*/     1, 2,\r\n    /*   1*/     3, 4,\r\n    /*   2*/     5, 0,\r\n    /*   3*/     6, 7,\r\n    /*   4*/     8, 9,\r\n    /*   5*/    10,   11,\r\n    /*   6*/    12,   13,\r\n    /*   7*/  -256,   14,\r\n    /*   8*/    15,   16,\r\n    /*   9*/    17,   18,\r\n    /*  10*/    19,   20,\r\n    /*  11*/    21,   22,\r\n    /*  12*/    -1,   23,\r\n    /*  13*/    24,   25,\r\n    /*  14*/    26,   27,\r\n    /*  15*/    28,   29,\r\n    /*  16*/    30,   31,\r\n    /*  17*/    32,   33,\r\n    /*  18*/    34,   35,\r\n    /*  19*/    36,   37,\r\n    /*  20*/    38,   39,\r\n    /*  21*/    40,  -64,\r\n    /*  22*/    41,   42,\r\n    /*  23*/    43,   44,\r\n    /*  24*/    -6,   45,\r\n    /*  25*/    46,   47,\r\n    /*  26*/    48,   49,\r\n    /*  27*/    50,   51,\r\n    /*  28*/  -119,   52,\r\n    /*  29*/   -32,   53,\r\n    /*  30*/    54,  -14,\r\n    /*  31*/    55,   -5,\r\n    /*  32*/    56,   57,\r\n    /*  33*/    58,   59,\r\n    /*  34*/    60,   -2,\r\n    /*  35*/    61,   62,\r\n    /*  36*/    63,   64,\r\n    /*  37*/    65,   66,\r\n    /*  38*/    67,   68,\r\n    /*  39*/    69,   70,\r\n    /*  40*/    71,   72,\r\n    /*  41*/   -51,   73,\r\n    /*  42*/    74,   75,\r\n    /*  43*/    76,   77,\r\n    /*  44*/  -101, -111,\r\n    /*  45*/    -4,  -97,\r\n    /*  46*/    78,   79,\r\n    /*  47*/  -110,   80,\r\n    /*  48*/    81, -116,\r\n    /*  49*/    82,   83,\r\n    /*  50*/    84, -255,\r\n    /*  51*/    85,   86,\r\n    /*  52*/    87,   88,\r\n    /*  53*/    89,   90,\r\n    /*  54*/   -15,  -10,\r\n    /*  55*/    91,   92,\r\n    /*  56*/   -21,   93,\r\n    /*  57*/  -117,   94,\r\n    /*  58*/    95,   96,\r\n    /*  59*/    97,   98,\r\n    /*  60*/    99,  100,\r\n    /*  61*/  -114,  101,\r\n    /*  62*/  -105,  102,\r\n    /*  63*/   -26,  103,\r\n    /*  64*/   104,  105,\r\n    /*  65*/   106,  107,\r\n    /*  66*/   108,  109,\r\n    /*  67*/   110,  111,\r\n    /*  68*/   112,   -3,\r\n    /*  69*/   113,   -7,\r\n    /*  70*/   114, -131,\r\n    /*  71*/   115, -144,\r\n    /*  72*/   116,  117,\r\n    /*  73*/   -20,  118,\r\n    /*  74*/   119,  120,\r\n    /*  75*/   121,  122,\r\n    /*  76*/   123,  124,\r\n    /*  77*/   125,  126,\r\n    /*  78*/   127,  128,\r\n    /*  79*/   129, -100 ,\r\n    /*  80*/   130,   -8,\r\n    /*  81*/   131,  132,\r\n    /*  82*/   133,  134,\r\n    /*  83*/  -120,  135,\r\n    /*  84*/   136,  -31,\r\n    /*  85*/   137,  138,\r\n    /*  86*/  -109, -234,\r\n    /*  87*/   139,  140,\r\n    /*  88*/   141,  142,\r\n    /*  89*/   143,  144,\r\n    /*  90*/  -112,  145,\r\n    /*  91*/   -19,  146,\r\n    /*  92*/   147,  148,\r\n    /*  93*/   149,  -66,\r\n    /*  94*/   150, -145,\r\n    /*  95*/   -13,  -65,\r\n    /*  96*/   151,  152,\r\n    /*  97*/   153,  154,\r\n    /*  98*/   -30,  155,\r\n    /*  99*/   156,  157,\r\n    /* 100*/   -99,  158,\r\n    /* 101*/   159,  160,\r\n    /* 102*/   161,  162,\r\n    /* 103*/   -23,  163,\r\n    /* 104*/   -29,  164,\r\n    /* 105*/   -11,  165,\r\n    /* 106*/   166, -115,\r\n    /* 107*/   167,  168,\r\n    /* 108*/   169,  170,\r\n    /* 109*/   -16,  171,\r\n    /* 110*/   -34,  172,\r\n    /* 111*/   173, -132,\r\n    /* 112*/   174, -108,\r\n    /* 113*/   175,  -22,\r\n    /* 114*/   176,   -9,\r\n    /* 115*/   177,  -84,\r\n    /* 116*/   -17,  -37,\r\n    /* 117*/   -28,  178,\r\n    /* 118*/   179,  180,\r\n    /* 119*/   181,  182,\r\n    /* 120*/   183,  184,\r\n    /* 121*/   185,  186,\r\n    /* 122*/   187, -104,\r\n    /* 123*/   188,  -78,\r\n    /* 124*/   189,  -61,\r\n    /* 125*/   -79, -178,\r\n    /* 126*/   -59, -134,\r\n    /* 127*/   190,  -25,\r\n    /* 128*/   -83,  -18,\r\n    /* 129*/   191,  -57,\r\n    /* 130*/   -67,  192,\r\n    /* 131*/   -98,  193,\r\n    /* 132*/   -12,  -68,\r\n    /* 133*/   194,  195,\r\n    /* 134*/   -55, -128,\r\n    /* 135*/   -24,  -50,\r\n    /* 136*/   -70,  196,\r\n    /* 137*/   -94,  -33,\r\n    /* 138*/   197, -129,\r\n    /* 139*/   -74,  198,\r\n    /* 140*/   -82,  199,\r\n    /* 141*/   -56,  -87,\r\n    /* 142*/   -44,  200,\r\n    /* 143*/  -248,  201,\r\n    /* 144*/  -163,  -81,\r\n    /* 145*/   -52, -123,\r\n    /* 146*/   202, -113,\r\n    /* 147*/   -48,  -41,\r\n    /* 148*/  -122,  -40,\r\n    /* 149*/   203,  -90,\r\n    /* 150*/   -54,  204,\r\n    /* 151*/   -86, -192,\r\n    /* 152*/   205,  206,\r\n    /* 153*/   207, -130,\r\n    /* 154*/   -53,  208,\r\n    /* 155*/  -133,  -45,\r\n    /* 156*/   209,  210,\r\n    /* 157*/   211,  -91,\r\n    /* 158*/   212,  213,\r\n    /* 159*/  -106,  -88,\r\n    /* 160*/   214,  215,\r\n    /* 161*/   216,  217,\r\n    /* 162*/   218,  -49,\r\n    /* 163*/   219,  220,\r\n    /* 164*/   221,  222,\r\n    /* 165*/   223,  224,\r\n    /* 166*/   225,  226,\r\n    /* 167*/   227, -102,\r\n    /* 168*/  -160,  228,\r\n    /* 169*/   -46,  229,\r\n    /* 170*/  -127,  230,\r\n    /* 171*/  -103,  231,\r\n    /* 172*/   232,  233,\r\n    /* 173*/   -60,  234,\r\n    /* 174*/   235,  -76,\r\n    /* 175*/   236, -121,\r\n    /* 176*/   237,  -73,\r\n    /* 177*/  -149,  238,\r\n    /* 178*/   239, -107,\r\n    /* 179*/   -35,  240,\r\n    /* 180*/   -71,  -27,\r\n    /* 181*/   -69,  241,\r\n    /* 182*/   -89,  -77,\r\n    /* 183*/   -62, -118,\r\n    /* 184*/   -75,  -85,\r\n    /* 185*/   -72,  -58,\r\n    /* 186*/   -63,  -80,\r\n    /* 187*/   242,  -42,\r\n    /* 188*/  -150, -157,\r\n    /* 189*/  -139, -236,\r\n    /* 190*/  -126, -243,\r\n    /* 191*/  -142, -214,\r\n    /* 192*/  -138, -206,\r\n    /* 193*/  -240, -146,\r\n    /* 194*/  -204, -147,\r\n    /* 195*/  -152, -201,\r\n    /* 196*/  -227, -207,\r\n    /* 197*/  -154, -209,\r\n    /* 198*/  -153, -254,\r\n    /* 199*/  -176, -156,\r\n    /* 200*/  -165, -210,\r\n    /* 201*/  -172, -185,\r\n    /* 202*/  -195, -170,\r\n    /* 203*/  -232, -211,\r\n    /* 204*/  -219, -239,\r\n    /* 205*/  -200, -177,\r\n    /* 206*/  -175, -212,\r\n    /* 207*/  -244, -143,\r\n    /* 208*/  -246, -171,\r\n    /* 209*/  -203, -221,\r\n    /* 210*/  -202, -181,\r\n    /* 211*/  -173, -250,\r\n    /* 212*/  -184, -164,\r\n    /* 213*/  -193, -218,\r\n    /* 214*/  -199, -220,\r\n    /* 215*/  -190, -249,\r\n    /* 216*/  -230, -217,\r\n    /* 217*/  -169, -216,\r\n    /* 218*/  -191, -197,\r\n    /* 219*/   -47,  243,\r\n    /* 220*/   244,  245,\r\n    /* 221*/   246,  247,\r\n    /* 222*/  -148, -159,\r\n    /* 223*/   248,  249,\r\n    /* 224*/   -92,  -93,\r\n    /* 225*/   -96, -225,\r\n    /* 226*/  -151,  -95,\r\n    /* 227*/   250,  251,\r\n    /* 228*/  -241,  252,\r\n    /* 229*/  -161,  -36,\r\n    /* 230*/   253,  254,\r\n    /* 231*/  -135,  -39,\r\n    /* 232*/  -187, -124,\r\n    /* 233*/   255, -251,\r\n    /* 234*/  -162, -238,\r\n    /* 235*/  -242,  -38,\r\n    /* 236*/   -43, -125,\r\n    /* 237*/  -215, -253,\r\n    /* 238*/  -140, -208,\r\n    /* 239*/  -137, -235,\r\n    /* 240*/  -158, -237,\r\n    /* 241*/  -136, -205,\r\n    /* 242*/  -155, -141,\r\n    /* 243*/  -228, -229,\r\n    /* 244*/  -213, -168,\r\n    /* 245*/  -224, -194,\r\n    /* 246*/  -196, -226,\r\n    /* 247*/  -183, -233,\r\n    /* 248*/  -231, -167,\r\n    /* 249*/  -174, -189,\r\n    /* 250*/  -252, -166,\r\n    /* 251*/  -198, -222,\r\n    /* 252*/  -188, -179,\r\n    /* 253*/  -223, -182,\r\n    /* 254*/  -180, -186,\r\n    /* 255*/  -245, -247,\r\n};\r\n\r\nint Compression::CompressionTable[] = \r\n{\r\n\t0x2, 0x000,\t0x5, 0x01F,\t0x6, 0x022,\t0x7, 0x034,\t0x7, 0x075,\t0x6, 0x028,\t0x6, 0x03B,\t0x7, 0x032,\r\n\t0x8, 0x0E0,\t0x8, 0x062,\t0x7, 0x056,\t0x8, 0x079,\t0x9, 0x19D,\t0x8, 0x097,\t0x6, 0x02A,\t0x7, 0x057,\r\n\t0x8, 0x071,\t0x8, 0x05B,\t0x9, 0x1CC,\t0x8, 0x0A7,\t0x7, 0x025,\t0x7, 0x04F,\t0x8, 0x066,\t0x8, 0x07D,\r\n\t0x9, 0x191,\t0x9, 0x1CE,\t0x7, 0x03F,\t0x9, 0x090,\t0x8, 0x059,\t0x8, 0x07B,\t0x8, 0x091,\t0x8, 0x0C6,\r\n\t0x6, 0x02D,\t0x9, 0x186,\t0x8, 0x06F,\t0x9, 0x093,\t0xA, 0x1CC,\t0x8, 0x05A,\t0xA, 0x1AE,\t0xA, 0x1C0,\r\n\t0x9, 0x148,\t0x9, 0x14A,\t0x9, 0x082,\t0xA, 0x19F,\t0x9, 0x171,\t0x9, 0x120,\t0x9, 0x0E7,\t0xA, 0x1F3,\r\n\t0x9, 0x14B,\t0x9, 0x100,\t0x9, 0x190,\t0x6, 0x013,\t0x9, 0x161,\t0x9, 0x125,\t0x9, 0x133,\t0x9, 0x195,\r\n\t0x9, 0x173,\t0x9, 0x1CA,\t0x9, 0x086,\t0x9, 0x1E9,\t0x9, 0x0DB,\t0x9, 0x1EC,\t0x9, 0x08B,\t0x9, 0x085,\r\n\t0x5, 0x00A,\t0x8, 0x096,\t0x8, 0x09C,\t0x9, 0x1C3,\t0x9, 0x19C,\t0x9, 0x08F,\t0x9, 0x18F,\t0x9, 0x091,\r\n\t0x9, 0x087,\t0x9, 0x0C6,\t0x9, 0x177,\t0x9, 0x089,\t0x9, 0x0D6,\t0x9, 0x08C,\t0x9, 0x1EE,\t0x9, 0x1EB,\r\n\t0x9, 0x084,\t0x9, 0x164,\t0x9, 0x175,\t0x9, 0x1CD,\t0x8, 0x05E,\t0x9, 0x088,\t0x9, 0x12B,\t0x9, 0x172,\r\n\t0x9, 0x10A,\t0x9, 0x08D,\t0x9, 0x13A,\t0x9, 0x11C,\t0xA, 0x1E1,\t0xA, 0x1E0,\t0x9, 0x187,\t0xA, 0x1DC,\r\n\t0xA, 0x1DF,\t0x7, 0x074,\t0x9, 0x19F,\t0x8, 0x08D,\t0x8, 0x0E4,\t0x7, 0x079,\t0x9, 0x0EA,\t0x9, 0x0E1,\r\n\t0x8, 0x040,\t0x7, 0x041,\t0x9, 0x10B,\t0x9, 0x0B0,\t0x8, 0x06A,\t0x8, 0x0C1,\t0x7, 0x071,\t0x7, 0x078,\r\n\t0x8, 0x0B1,\t0x9, 0x14C,\t0x7, 0x043,\t0x8, 0x076,\t0x7, 0x066,\t0x7, 0x04D,\t0x9, 0x08A,\t0x6, 0x02F,\r\n\t0x8, 0x0C9,\t0x9, 0x0CE,\t0x9, 0x149,\t0x9, 0x160,\t0xA, 0x1BA,\t0xA, 0x19E,\t0xA, 0x39F,\t0x9, 0x0E5,\r\n\t0x9, 0x194,\t0x9, 0x184,\t0x9, 0x126,\t0x7, 0x030,\t0x8, 0x06C,\t0x9, 0x121,\t0x9, 0x1E8,\t0xA, 0x1C1,\r\n\t0xA, 0x11D,\t0xA, 0x163,\t0xA, 0x385,\t0xA, 0x3DB,\t0xA, 0x17D,\t0xA, 0x106,\t0xA, 0x397,\t0xA, 0x24E,\r\n\t0x7, 0x02E,\t0x8, 0x098,\t0xA, 0x33C,\t0xA, 0x32E,\t0xA, 0x1E9,\t0x9, 0x0BF,\t0xA, 0x3DF,\t0xA, 0x1DD,\r\n\t0xA, 0x32D,\t0xA, 0x2ED,\t0xA, 0x30B,\t0xA, 0x107,\t0xA, 0x2E8,\t0xA, 0x3DE,\t0xA, 0x125,\t0xA, 0x1E8,\r\n\t0x9, 0x0E9,\t0xA, 0x1CD,\t0xA, 0x1B5,\t0x9, 0x165,\t0xA, 0x232,\t0xA, 0x2E1,\t0xB, 0x3AE,\t0xB, 0x3C6,\r\n\t0xB, 0x3E2,\t0xA, 0x205,\t0xA, 0x29A,\t0xA, 0x248,\t0xA, 0x2CD,\t0xA, 0x23B,\t0xB, 0x3C5,\t0xA, 0x251,\r\n\t0xA, 0x2E9,\t0xA, 0x252,\t0x9, 0x1EA,\t0xB, 0x3A0,\t0xB, 0x391,\t0xA, 0x23C,\t0xB, 0x392,\t0xB, 0x3D5,\r\n\t0xA, 0x233,\t0xA, 0x2CC,\t0xB, 0x390,\t0xA, 0x1BB,\t0xB, 0x3A1,\t0xB, 0x3C4,\t0xA, 0x211,\t0xA, 0x203,\r\n\t0x9, 0x12A,\t0xA, 0x231,\t0xB, 0x3E0,\t0xA, 0x29B,\t0xB, 0x3D7,\t0xA, 0x202,\t0xB, 0x3AD,\t0xA, 0x213,\r\n\t0xA, 0x253,\t0xA, 0x32C,\t0xA, 0x23D,\t0xA, 0x23F,\t0xA, 0x32F,\t0xA, 0x11C,\t0xA, 0x384,\t0xA, 0x31C,\r\n\t0xA, 0x17C,\t0xA, 0x30A,\t0xA, 0x2E0,\t0xA, 0x276,\t0xA, 0x250,\t0xB, 0x3E3,\t0xA, 0x396,\t0xA, 0x18F,\r\n\t0xA, 0x204,\t0xA, 0x206,\t0xA, 0x230,\t0xA, 0x265,\t0xA, 0x212,\t0xA, 0x23E,\t0xB, 0x3AC,\t0xB, 0x393,\r\n\t0xB, 0x3E1,\t0xA, 0x1DE,\t0xB, 0x3D6,\t0xA, 0x31D,\t0xB, 0x3E5,\t0xB, 0x3E4,\t0xA, 0x207,\t0xB, 0x3C7,\r\n\t0xA, 0x277,\t0xB, 0x3D4,\t0x8, 0x0C0,\t0xA, 0x162,\t0xA, 0x3DA,\t0xA, 0x124,\t0xA, 0x1B4,\t0xA, 0x264,\r\n\t0xA, 0x33D,\t0xA, 0x1D1,\t0xA, 0x1AF,\t0xA, 0x39E,\t0xA, 0x24F,\t0xB, 0x373,\t0xA, 0x249,\t0xB, 0x372,\r\n\t0x9, 0x167,\t0xA, 0x210,\t0xA, 0x23A,\t0xA, 0x1B8,\t0xB, 0x3AF,\t0xA, 0x18E,\t0xA, 0x2EC,\t0x7, 0x062,\r\n\t0x4, 0x00D\r\n};\r\n\r\nint Compression::bit_num = 8, Compression::treepos = 0;\r\nint Compression::value, Compression::mask;\r\n\r\nint Compression::Compress( char *out_buff, const char *in_buff, int length )\r\n{\r\n\tconst unsigned char *input = (const unsigned char*)in_buff;\r\n\tunsigned char *output = (unsigned char *)out_buff;\r\n\r\n\tint holdCount = 0;\r\n\tint holdValue = 0;\r\n\r\n\tint packCount = 0;\r\n\tint packValue = 0;\r\n\r\n\tint byteValue = 0;\r\n\r\n\tint inputLength = length;\r\n\tint inputIndex = 0;\r\n\r\n\tint outputCount = 0;\r\n\r\n\twhile ( inputIndex < inputLength )\r\n\t{\r\n\t\tbyteValue = input[inputIndex++] << 1;\r\n\r\n\t\tpackCount = CompressionTable[byteValue];\r\n\t\tpackValue = CompressionTable[byteValue | 1];\r\n\r\n\t\tholdValue <<= packCount;\r\n\t\tholdValue  |= packValue;\r\n\t\tholdCount  += packCount;\r\n\r\n\t\twhile ( holdCount >= 8 )\r\n\t\t{\r\n\t\t\tholdCount -= 8;\r\n\r\n\t\t\toutput[outputCount++] = (unsigned char)(holdValue >> holdCount);\r\n\t\t}\r\n\t}\r\n\r\n\tpackCount = CompressionTable[0x200];\r\n\tpackValue = CompressionTable[0x201];\r\n\r\n\tholdValue <<= packCount;\r\n\tholdValue  |= packValue;\r\n\tholdCount  += packCount;\r\n\r\n\twhile ( holdCount >= 8 )\r\n\t{\r\n\t\tholdCount -= 8;\r\n\r\n\t\toutput[outputCount++] = (unsigned char)(holdValue >> holdCount);\r\n\t}\r\n\r\n\tif ( holdCount > 0 )\r\n\t\toutput[outputCount++] = (unsigned char)(holdValue << (8 - holdCount));\r\n\r\n\treturn outputCount;\r\n}\r\n\r\nvoid Compression::Reset()\r\n{\r\n\tbit_num = 8;\r\n\ttreepos = 0;\r\n}\r\n\r\nint Compression::Decompress( char *output, const char *input, int length )\r\n{\r\n\tunsigned char *\tpdest =\treinterpret_cast<unsigned char *>(output);\r\n\tconst unsigned char\t* psrc = reinterpret_cast<const\tunsigned char *>(input);\r\n    int len = length; // len will decrease\r\n    int dest_index = 0;\r\n\r\n    while(true)\r\n    {\r\n        if(bit_num == 8)\r\n        {\r\n            // End of input.\r\n            if(len == 0)\r\n                return dest_index;\r\n\r\n            len--;\r\n            value = *psrc++;\r\n            bit_num = 0;\r\n            mask = 0x80;\r\n        }\r\n        if(value & mask)\r\n            treepos = DecompressionTree[treepos * 2];\r\n        else\r\n            treepos = DecompressionTree[treepos * 2 + 1];\r\n        mask >>= 1; // shift on reck\r\n        bit_num++;\r\n\r\n        if(treepos <= 0) // this is a leaf.\r\n        {\r\n            if(treepos == -256) // special flush character\r\n            {\r\n                bit_num = 8; // flush rest of byte\r\n                treepos = 0; // start on tree top again\r\n                continue;\r\n            }\r\n\r\n            pdest[dest_index++] = -treepos;   // data is negative value\r\n            treepos = 0;      // start on tree top again\r\n        }\r\n    }\r\n\r\n\treturn 0;\r\n}\r\n"
  },
  {
    "path": "Crypt/uo_huffman.h",
    "content": "#pragma once\r\n\r\nclass Compression\r\n{\r\npublic:\r\n\tstatic int Compress( char *out, const char *in, int inlen );\r\n\tstatic int Decompress( char *out, const char *in, int inlen );\r\n\r\n\tstatic void Reset();\r\n\r\nprotected:\r\n\tstatic int bit_num, treepos;\r\n\tstatic int value, mask;\r\n\r\n\tstatic int CompressionTable[];\r\n\tstatic int DecompressionTree[];\r\n};\r\n\r\n"
  },
  {
    "path": "FastColoredTextBox/AutocompleteItem.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Drawing.Printing;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Item of autocomplete menu\n    /// </summary>\n    public class AutocompleteItem\n    {\n        public string Text;\n        public int ImageIndex = -1;\n        public object Tag;\n        string toolTipTitle;\n        string toolTipText;\n        string menuText;\n        public AutocompleteMenu Parent { get; internal set; }\n\n\n        public AutocompleteItem()\n        {\n        }\n\n        public AutocompleteItem(string text)\n        {\n            Text = text;\n        }\n\n        public AutocompleteItem(string text, int imageIndex)\n            : this(text)\n        {\n            this.ImageIndex = imageIndex;\n        }\n\n        public AutocompleteItem(string text, int imageIndex, string menuText)\n            : this(text, imageIndex)\n        {\n            this.menuText = menuText;\n        }\n\n        public AutocompleteItem(string text, int imageIndex, string menuText, string toolTipTitle, string toolTipText)\n            : this(text, imageIndex, menuText)\n        {\n            this.toolTipTitle = toolTipTitle;\n            this.toolTipText = toolTipText;\n        }\n\n        /// <summary>\n        /// Returns text for inserting into Textbox\n        /// </summary>\n        public virtual string GetTextForReplace()\n        {\n            return Text;\n        }\n\n        /// <summary>\n        /// Compares fragment text with this item\n        /// </summary>\n        public virtual CompareResult Compare(string fragmentText)\n        {\n            if (Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) &&\n                Text != fragmentText)\n                return CompareResult.VisibleAndSelected;\n\n            return CompareResult.Hidden;\n        }\n\n        /// <summary>\n        /// Returns text for display into popup menu\n        /// </summary>\n        public override string ToString()\n        {\n            return menuText ?? Text;\n        }\n\n        /// <summary>\n        /// This method is called after item inserted into text\n        /// </summary>\n        public virtual void OnSelected(AutocompleteMenu popupMenu, SelectedEventArgs e)\n        {\n            ;\n        }\n\n        /// <summary>\n        /// Title for tooltip.\n        /// </summary>\n        /// <remarks>Return null for disable tooltip for this item</remarks>\n        public virtual string ToolTipTitle\n        {\n            get { return toolTipTitle; }\n            set { toolTipTitle = value; }\n        }\n\n        /// <summary>\n        /// Tooltip text.\n        /// </summary>\n        /// <remarks>For display tooltip text, ToolTipTitle must be not null</remarks>\n        public virtual string ToolTipText\n        {\n            get { return toolTipText; }\n            set { toolTipText = value; }\n        }\n\n        /// <summary>\n        /// Menu text. This text is displayed in the drop-down menu.\n        /// </summary>\n        public virtual string MenuText\n        {\n            get { return menuText; }\n            set { menuText = value; }\n        }\n\n        /// <summary>\n        /// Fore color of text of item\n        /// </summary>\n        public virtual Color ForeColor\n        {\n            get { return Color.Transparent; }\n            set { throw new NotImplementedException(\"Override this property to change color\"); }\n        }\n\n        /// <summary>\n        /// Back color of item\n        /// </summary>\n        public virtual Color BackColor\n        {\n            get { return Color.Transparent; }\n            set { throw new NotImplementedException(\"Override this property to change color\"); }\n        }\n    }\n\n    public enum CompareResult\n    {\n        /// <summary>\n        /// Item do not appears\n        /// </summary>\n        Hidden,\n\n        /// <summary>\n        /// Item appears\n        /// </summary>\n        Visible,\n\n        /// <summary>\n        /// Item appears and will selected\n        /// </summary>\n        VisibleAndSelected\n    }\n\n    /// <summary>\n    /// Autocomplete item for code snippets\n    /// </summary>\n    /// <remarks>Snippet can contain special char ^ for caret position.</remarks>\n    public class SnippetAutocompleteItem : AutocompleteItem\n    {\n        public SnippetAutocompleteItem(string snippet)\n        {\n            Text = snippet.Replace(\"\\r\", \"\");\n            ToolTipTitle = \"Code snippet:\";\n            ToolTipText = Text;\n        }\n\n        public override string ToString()\n        {\n            return MenuText ?? Text.Replace(\"\\n\", \" \").Replace(\"^\", \"\");\n        }\n\n        public override string GetTextForReplace()\n        {\n            return Text;\n        }\n\n        public override void OnSelected(AutocompleteMenu popupMenu, SelectedEventArgs e)\n        {\n            e.Tb.BeginUpdate();\n            e.Tb.Selection.BeginUpdate();\n            //remember places\n            var p1 = popupMenu.Fragment.Start;\n            var p2 = e.Tb.Selection.Start;\n            //do auto indent\n            if (e.Tb.AutoIndent)\n            {\n                for (int iLine = p1.iLine + 1; iLine <= p2.iLine; iLine++)\n                {\n                    e.Tb.Selection.Start = new Place(0, iLine);\n                    e.Tb.DoAutoIndent(iLine);\n                }\n            }\n\n            e.Tb.Selection.Start = p1;\n            //move caret position right and find char ^\n            while (e.Tb.Selection.CharBeforeStart != '^')\n                if (!e.Tb.Selection.GoRightThroughFolded())\n                    break;\n            //remove char ^\n            e.Tb.Selection.GoLeft(true);\n            e.Tb.InsertText(\"\");\n            //\n            e.Tb.Selection.EndUpdate();\n            e.Tb.EndUpdate();\n        }\n\n        /// <summary>\n        /// Compares fragment text with this item\n        /// </summary>\n        public override CompareResult Compare(string fragmentText)\n        {\n            if (Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) &&\n                Text != fragmentText)\n                return CompareResult.Visible;\n\n            return CompareResult.Hidden;\n        }\n    }\n\n    /// <summary>\n    /// This autocomplete item appears after dot\n    /// </summary>\n    public class MethodAutocompleteItem : AutocompleteItem\n    {\n        string firstPart;\n        string lowercaseText;\n\n        public MethodAutocompleteItem(string text)\n            : base(text)\n        {\n            lowercaseText = Text.ToLower();\n        }\n\n        public override CompareResult Compare(string fragmentText)\n        {\n            int i = fragmentText.LastIndexOf(' ');\n            if (i < 0)\n                return CompareResult.Hidden;\n            string lastPart = fragmentText.Substring(i + 1);\n            firstPart = fragmentText.Substring(0, i);\n\n            if (lastPart == \"\") return CompareResult.Visible;\n            if (Text.StartsWith(lastPart, StringComparison.InvariantCultureIgnoreCase))\n                return CompareResult.VisibleAndSelected;\n            if (lowercaseText.Contains(lastPart.ToLower()))\n                return CompareResult.Visible;\n\n            return CompareResult.Hidden;\n        }\n\n        public override string GetTextForReplace()\n        {\n            return firstPart + \" \" + Text;\n        }\n    }\n\n    /// <summary>\n    /// This Item does not check correspondence to current text fragment.\n    /// SuggestItem is intended for dynamic menus.\n    /// </summary>\n    public class SuggestItem : AutocompleteItem\n    {\n        public SuggestItem(string text, int imageIndex) : base(text, imageIndex)\n        {\n        }\n\n        public override CompareResult Compare(string fragmentText)\n        {\n            return CompareResult.Visible;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/AutocompleteMenu.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Windows.Forms;\nusing System.Drawing;\nusing System.ComponentModel;\nusing System.Drawing.Drawing2D;\nusing System.Text.RegularExpressions;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Popup menu for autocomplete\n    /// </summary>\n    [Browsable(false)]\n    public class AutocompleteMenu : UserControl, IDisposable\n    {\n        AutocompleteListView listView;\n        public Range Fragment { get; internal set; }\n\n        /// <summary>\n        /// Regex pattern for serach fragment around caret\n        /// </summary>\n        public string SearchPattern { get; set; }\n\n        /// <summary>\n        /// Minimum fragment length for popup\n        /// </summary>\n        public int MinFragmentLength { get; set; }\n\n        /// <summary>\n        /// User selects item\n        /// </summary>\n        public event EventHandler<SelectingEventArgs> Selecting;\n\n        /// <summary>\n        /// It fires after item inserting\n        /// </summary>\n        public event EventHandler<SelectedEventArgs> Selected;\n\n        /// <summary>\n        /// Occurs when popup menu is opening\n        /// </summary>\n        public new event EventHandler<CancelEventArgs> Opening;\n\n        /// <summary>\n        /// Allow TAB for select menu item\n        /// </summary>\n        public bool AllowTabKey\n        {\n            get { return listView.AllowTabKey; }\n            set { listView.AllowTabKey = value; }\n        }\n\n        /// <summary>\n        /// Interval of menu appear (ms)\n        /// </summary>\n        public int AppearInterval\n        {\n            get { return listView.AppearInterval; }\n            set { listView.AppearInterval = value; }\n        }\n\n        /// <summary>\n        /// Sets the max tooltip window size\n        /// </summary>\n        public Size MaxTooltipSize\n        {\n            get { return listView.MaxToolTipSize; }\n            set { listView.MaxToolTipSize = value; }\n        }\n\n        /// <summary>\n        /// Tooltip will perm show and duration will be ignored\n        /// </summary>\n        public bool AlwaysShowTooltip\n        {\n            get { return listView.AlwaysShowTooltip; }\n            set { listView.AlwaysShowTooltip = value; }\n        }\n\n        /// <summary>\n        /// Back color of selected item\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Orange\")]\n        public Color SelectedColor\n        {\n            get { return listView.SelectedColor; }\n            set { listView.SelectedColor = value; }\n        }\n\n        /// <summary>\n        /// Border color of hovered item\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Red\")]\n        public Color HoveredColor\n        {\n            get { return listView.HoveredColor; }\n            set { listView.HoveredColor = value; }\n        }\n\n        public AutocompleteMenu(FastColoredTextBox tb)\n        {\n            // create a new popup and add the list view to it\n            Visible = false;\n            BorderStyle = BorderStyle.FixedSingle;\n            AutoSize = false;\n            Margin = Padding.Empty;\n            Padding = Padding.Empty;\n            BackColor = Color.White;\n            listView = new AutocompleteListView(tb);\n           \n            CalcSize();\n            listView.Parent = this;\n            SearchPattern = @\"[\\w\\.]\";\n            MinFragmentLength = 2;\n        }\n\n\n        public new Font Font\n        {\n            get { return listView.Font; }\n            set { listView.Font = value; }\n        }\n\n        new internal void OnOpening(CancelEventArgs args)\n        {\n            if (Opening != null)\n                Opening(this, args);\n        }\n\n        public new void Close()\n        {\n            listView.toolTip.Hide(listView);\n            Hide();\n        }\n\n        internal void CalcSize()\n        {\n            Size = new System.Drawing.Size(listView.Size.Width + 4, listView.Size.Height + 4);\n        }\n\n        public virtual void OnSelecting()\n        {\n            listView.OnSelecting();\n        }\n\n        public void SelectNext(int shift)\n        {\n            listView.SelectNext(shift);\n        }\n\n        internal void OnSelecting(SelectingEventArgs args)\n        {\n            if (Selecting != null)\n                Selecting(this, args);\n        }\n\n        public void OnSelected(SelectedEventArgs args)\n        {\n            if (Selected != null)\n                Selected(this, args);\n        }\n\n        public new AutocompleteListView Items\n        {\n            get { return listView; }\n        }\n\n        /// <summary>\n        /// Shows popup menu immediately\n        /// </summary>\n        /// <param name=\"forced\">If True - MinFragmentLength will be ignored</param>\n        public void Show(bool forced)\n        {\n            Items.DoAutocomplete(forced);\n        }\n\n        /// <summary>\n        /// Minimal size of menu\n        /// </summary>\n        public new Size MinimumSize\n        {\n            get { return Items.MinimumSize; }\n            set { Items.MinimumSize = value; }\n        }\n\n        /// <summary>\n        /// Image list of menu\n        /// </summary>\n        public new ImageList ImageList\n        {\n            get { return Items.ImageList; }\n            set { Items.ImageList = value; }\n        }\n\n        /// <summary>\n        /// Tooltip duration (ms)\n        /// </summary>\n        public int ToolTipDuration\n        {\n            get { return Items.ToolTipDuration; }\n            set { Items.ToolTipDuration = value; }\n        }\n\n        /// <summary>\n        /// Tooltip\n        /// </summary>\n        public ToolTip ToolTip\n        {\n            get { return Items.toolTip; }\n            set { Items.toolTip = value; }\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            base.Dispose(disposing);\n            if (listView != null && !listView.IsDisposed)\n                listView.Dispose();\n        }\n    }\n\n    [System.ComponentModel.ToolboxItem(false)]\n    public class AutocompleteListView : UserControl, IDisposable\n    {\n        public event EventHandler FocussedItemIndexChanged;\n\n        internal List<AutocompleteItem> visibleItems;\n        IEnumerable<AutocompleteItem> sourceItems = new List<AutocompleteItem>();\n        int focussedItemIndex = 0;\n        int hoveredItemIndex = -1;\n\n        private int ItemHeight\n        {\n            get { return Font.Height + 2; }\n        }\n\n        AutocompleteMenu Menu\n        {\n            get { return Parent as AutocompleteMenu; }\n        }\n\n        int oldItemCount = 0;\n        FastColoredTextBox tb;\n        internal ToolTip toolTip = new ToolTip();\n        System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();\n\n        internal bool AllowTabKey { get; set; }\n        public ImageList ImageList { get; set; }\n\n        internal int AppearInterval\n        {\n            get { return timer.Interval; }\n            set { timer.Interval = value; }\n        }\n\n        internal int ToolTipDuration { get; set; }\n        internal Size MaxToolTipSize { get; set; }\n\n        internal bool AlwaysShowTooltip\n        {\n            get { return toolTip.ShowAlways; }\n            set { toolTip.ShowAlways = value; }\n        }\n\n        public Color SelectedColor { get; set; }\n        public Color HoveredColor { get; set; }\n\n        public int FocussedItemIndex\n        {\n            get { return focussedItemIndex; }\n            set\n            {\n                if (focussedItemIndex != value)\n                {\n                    focussedItemIndex = value;\n                    if (FocussedItemIndexChanged != null)\n                        FocussedItemIndexChanged(this, EventArgs.Empty);\n                }\n            }\n        }\n\n        public AutocompleteItem FocussedItem\n        {\n            get\n            {\n                if (FocussedItemIndex >= 0 && focussedItemIndex < visibleItems.Count)\n                    return visibleItems[focussedItemIndex];\n                return null;\n            }\n            set { FocussedItemIndex = visibleItems.IndexOf(value); }\n        }\n\n        internal AutocompleteListView(FastColoredTextBox tb)\n        {\n            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint,\n                true);\n            base.Font = new Font(FontFamily.GenericSansSerif, 9);\n            visibleItems = new List<AutocompleteItem>();\n            VerticalScroll.SmallChange = ItemHeight;\n            MaximumSize = new Size(Size.Width, 180);\n            toolTip.ShowAlways = false;\n            AppearInterval = 500;\n            timer.Tick += new EventHandler(timer_Tick);\n            SelectedColor = Color.Orange;\n            HoveredColor = Color.Red;\n            ToolTipDuration = 3000;\n            toolTip.Popup += ToolTip_Popup;\n\n            MouseDown += new MouseEventHandler(ListMouseDown);\n\n            this.tb = tb;\n\n            tb.KeyDown += new KeyEventHandler(tb_KeyDown);\n            tb.SelectionChanged += new EventHandler(tb_SelectionChanged);\n            tb.KeyPressed += new KeyPressEventHandler(tb_KeyPressed);\n\n            Form form = tb.FindForm();\n            if (form != null)\n            {\n                form.LocationChanged += delegate { SafetyClose(); };\n                form.ResizeBegin += delegate { SafetyClose(); };\n                form.FormClosing += delegate { SafetyClose(); };\n                form.LostFocus += delegate { SafetyClose(); };\n            }\n\n            tb.LostFocus += (o, e) =>\n            {\n                if (Menu != null && !Menu.IsDisposed)\n                    if (!Menu.Focused)\n                        SafetyClose();\n            };\n\n            tb.Scroll += delegate { SafetyClose(); };\n\n            this.VisibleChanged += (o, e) =>\n            {\n                if (this.Visible)\n                    DoSelectedVisible();\n            };\n        }\n\n        private void ListMouseDown(object sender, MouseEventArgs e)\n        {\n            DoAutocomplete(false);\n        }\n\n        private void ToolTip_Popup(object sender, PopupEventArgs e)\n        {\n            if (MaxToolTipSize.Height > 0 && MaxToolTipSize.Width > 0)\n                e.ToolTipSize = MaxToolTipSize;\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            if (toolTip != null)\n            {\n                toolTip.Popup -= ToolTip_Popup;\n                toolTip.Dispose();\n            }\n\n            if (tb != null)\n            {\n                tb.KeyDown -= tb_KeyDown;\n                tb.KeyPress -= tb_KeyPressed;\n                tb.SelectionChanged -= tb_SelectionChanged;\n            }\n\n            if (timer != null)\n            {\n                timer.Stop();\n                timer.Tick -= timer_Tick;\n                timer.Dispose();\n            }\n\n            base.Dispose(disposing);\n        }\n\n        void SafetyClose()\n        {\n            if (Menu != null && !Menu.IsDisposed)\n                Menu.Close();\n        }\n\n        void tb_KeyPressed(object sender, KeyPressEventArgs e)\n        {\n            bool backspaceORdel = e.KeyChar == '\\b' || e.KeyChar == 0xff;\n\n            /*\n            if (backspaceORdel)\n                prevSelection = tb.Selection.Start;*/\n\n            if (Menu.Visible && !backspaceORdel)\n                DoAutocomplete(false);\n            else\n                ResetTimer(timer);\n        }\n\n        void timer_Tick(object sender, EventArgs e)\n        {\n            timer.Stop();\n            DoAutocomplete(false);\n        }\n\n        void ResetTimer(System.Windows.Forms.Timer timer)\n        {\n            timer.Stop();\n            timer.Start();\n        }\n\n        internal void DoAutocomplete()\n        {\n            DoAutocomplete(false);\n        }\n\n        internal void DoAutocomplete(bool forced)\n        {\n            if (!Menu.Enabled)\n            {\n                Menu.Close();\n                return;\n            }\n\n            visibleItems.Clear();\n            FocussedItemIndex = 0;\n            VerticalScroll.Value = 0;\n            //some magic for update scrolls\n            AutoScrollMinSize -= new Size(1, 0);\n            AutoScrollMinSize += new Size(1, 0);\n            //get fragment around caret\n            Range fragment = tb.Selection.GetFragment(Menu.SearchPattern);\n            string text = fragment.Text;\n            //calc screen point for popup menu\n            Point point = tb.PlaceToPoint(fragment.End);\n            point.Offset(2, tb.CharHeight);\n            //\n            if (forced || (text.Length >= Menu.MinFragmentLength\n                           && tb.Selection.IsEmpty /*pops up only if selected range is empty*/\n                           && (tb.Selection.Start > fragment.Start ||\n                               text.Length == 0 /*pops up only if caret is after first letter*/)))\n            {\n                Menu.Fragment = fragment;\n                bool foundSelected = false;\n                //build popup menu\n                foreach (var item in sourceItems)\n                {\n                    item.Parent = Menu;\n                    CompareResult res = item.Compare(text);\n                    if (res != CompareResult.Hidden)\n                        visibleItems.Add(item);\n                    if (res == CompareResult.VisibleAndSelected && !foundSelected)\n                    {\n                        foundSelected = true;\n                        FocussedItemIndex = visibleItems.Count - 1;\n                    }\n                }\n\n                if (foundSelected)\n                {\n                    AdjustScroll();\n                }\n            }\n\n            //show popup menu\n            if (Count > 0)\n            {\n                if (!Menu.Visible)\n                {\n                    CancelEventArgs args = new CancelEventArgs();\n                    Menu.OnOpening(args);\n                    if (!args.Cancel)\n                    {\n                        Menu.Location = point;\n                        Menu.Parent = tb;\n                        Menu.Show();\n                    }\n                }\n\n                DoSelectedVisible();\n                Invalidate();\n            }\n            else\n                Menu.Close();\n        }\n\n        void tb_SelectionChanged(object sender, EventArgs e)\n        {\n            /*\n            FastColoredTextBox tb = sender as FastColoredTextBox;\n\n            if (Math.Abs(prevSelection.iChar - tb.Selection.Start.iChar) > 1 ||\n                        prevSelection.iLine != tb.Selection.Start.iLine)\n                Menu.Close();\n            prevSelection = tb.Selection.Start;*/\n            if (Menu.Visible)\n            {\n                bool needClose = false;\n\n                if (!tb.Selection.IsEmpty)\n                    needClose = true;\n                else if (!Menu.Fragment.Contains(tb.Selection.Start))\n                {\n                    if (tb.Selection.Start.iLine == Menu.Fragment.End.iLine &&\n                        tb.Selection.Start.iChar == Menu.Fragment.End.iChar + 1)\n                    {\n                        //user press key at end of fragment\n                        char c = tb.Selection.CharBeforeStart;\n                        if (!Regex.IsMatch(c.ToString(), Menu.SearchPattern)) //check char\n                            needClose = true;\n                    }\n                    else\n                        needClose = true;\n                }\n\n                if (needClose)\n                    Menu.Close();\n            }\n        }\n\n        void tb_KeyDown(object sender, KeyEventArgs e)\n        {\n            var tb = sender as FastColoredTextBox;\n\n            if (Menu.Visible)\n                if (ProcessKey(e.KeyCode, e.Modifiers))\n                    e.Handled = true;\n\n            if (!Menu.Visible)\n            {\n                if (tb.HotkeysMapping.ContainsKey(e.KeyData) &&\n                    tb.HotkeysMapping[e.KeyData] == FCTBAction.AutocompleteMenu)\n                {\n                    DoAutocomplete();\n                    e.Handled = true;\n                }\n                else\n                {\n                    if (e.KeyCode == Keys.Escape && timer.Enabled)\n                        timer.Stop();\n                }\n            }\n        }\n\n        void AdjustScroll()\n        {\n            if (oldItemCount == visibleItems.Count)\n                return;\n\n            int needHeight = ItemHeight * visibleItems.Count + 1;\n            Height = Math.Min(needHeight, MaximumSize.Height);\n            Menu.CalcSize();\n\n            AutoScrollMinSize = new Size(0, needHeight);\n            oldItemCount = visibleItems.Count;\n        }\n\n        protected override void OnPaint(PaintEventArgs e)\n        {\n            AdjustScroll();\n\n            var itemHeight = ItemHeight;\n            int startI = VerticalScroll.Value / itemHeight - 1;\n            int finishI = (VerticalScroll.Value + ClientSize.Height) / itemHeight + 1;\n            startI = Math.Max(startI, 0);\n            finishI = Math.Min(finishI, visibleItems.Count);\n            int y = 0;\n            int leftPadding = 18;\n            for (int i = startI; i < finishI; i++)\n            {\n                y = i * itemHeight - VerticalScroll.Value;\n\n                var item = visibleItems[i];\n\n                if (item.BackColor != Color.Transparent)\n                    using (var brush = new SolidBrush(item.BackColor))\n                        e.Graphics.FillRectangle(brush, 1, y, ClientSize.Width - 1 - 1, itemHeight - 1);\n\n                if (ImageList != null && visibleItems[i].ImageIndex >= 0)\n                    e.Graphics.DrawImage(ImageList.Images[item.ImageIndex], 1, y);\n\n                if (i == FocussedItemIndex)\n                    using (var selectedBrush = new LinearGradientBrush(new Point(0, y - 3),\n                        new Point(0, y + itemHeight), Color.Transparent, SelectedColor))\n                    using (var pen = new Pen(SelectedColor))\n                    {\n                        e.Graphics.FillRectangle(selectedBrush, leftPadding, y, ClientSize.Width - 1 - leftPadding,\n                            itemHeight - 1);\n                        e.Graphics.DrawRectangle(pen, leftPadding, y, ClientSize.Width - 1 - leftPadding,\n                            itemHeight - 1);\n                    }\n\n                if (i == hoveredItemIndex)\n                    using (var pen = new Pen(HoveredColor))\n                        e.Graphics.DrawRectangle(pen, leftPadding, y, ClientSize.Width - 1 - leftPadding,\n                            itemHeight - 1);\n\n                using (var brush = new SolidBrush(item.ForeColor != Color.Transparent ? item.ForeColor : ForeColor))\n                    e.Graphics.DrawString(item.ToString(), Font, brush, leftPadding, y);\n            }\n        }\n\n        public override Color ForeColor { get { return Color.Black; } set { }\n        }\n\n        protected override void OnScroll(ScrollEventArgs se)\n        {\n            base.OnScroll(se);\n            Invalidate();\n        }\n\n        protected override void OnMouseClick(MouseEventArgs e)\n        {\n            base.OnMouseClick(e);\n\n            if (e.Button == System.Windows.Forms.MouseButtons.Left || Environment.OSVersion.Platform == PlatformID.Unix)\n            {\n                FocussedItemIndex = PointToItemIndex(e.Location);\n                DoSelectedVisible();\n                Invalidate();\n            }\n        }\n\n        protected override void OnMouseDoubleClick(MouseEventArgs e)\n        {\n            base.OnMouseDoubleClick(e);\n            FocussedItemIndex = PointToItemIndex(e.Location);\n            Invalidate();\n            OnSelecting();\n        }\n\n        internal virtual void OnSelecting()\n        {\n            if (FocussedItemIndex < 0 || FocussedItemIndex >= visibleItems.Count)\n                return;\n            tb.TextSource.Manager.BeginAutoUndoCommands();\n            try\n            {\n                AutocompleteItem item = FocussedItem;\n                SelectingEventArgs args = new SelectingEventArgs()\n                {\n                    Item = item,\n                    SelectedIndex = FocussedItemIndex\n                };\n\n                Menu.OnSelecting(args);\n\n                if (args.Cancel)\n                {\n                    FocussedItemIndex = args.SelectedIndex;\n                    Invalidate();\n                    return;\n                }\n\n                if (!args.Handled)\n                {\n                    var fragment = Menu.Fragment;\n                    DoAutocomplete(item, fragment);\n                }\n\n                Menu.Close();\n                //\n                SelectedEventArgs args2 = new SelectedEventArgs()\n                {\n                    Item = item,\n                    Tb = Menu.Fragment.tb\n                };\n                item.OnSelected(Menu, args2);\n                Menu.OnSelected(args2);\n            }\n            finally\n            {\n                tb.TextSource.Manager.EndAutoUndoCommands();\n            }\n        }\n\n        private void DoAutocomplete(AutocompleteItem item, Range fragment)\n        {\n            string newText = fragment.Text;\n            int last = newText.LastIndexOf('.');\n            if (last > 0)\n            {\n                newText = newText.Substring(0, last + 1);\n            }\n            else\n            {\n                newText = \"\";\n            }\n\n            newText = newText + item;\n            if (item.ToolTipText != null)\n            {\n                newText = newText + \" \";\n            }\n\n            //replace text of fragment\n            var tb = fragment.tb;\n\n            tb.BeginAutoUndo();\n            tb.TextSource.Manager.ExecuteCommand(new SelectCommand(tb.TextSource));\n            if (tb.Selection.ColumnSelectionMode)\n            {\n                var start = tb.Selection.Start;\n                var end = tb.Selection.End;\n                start.iChar = fragment.Start.iChar;\n                end.iChar = fragment.End.iChar;\n                tb.Selection.Start = start;\n                tb.Selection.End = end;\n            }\n            else\n            {\n                tb.Selection.Start = fragment.Start;\n                tb.Selection.End = fragment.End;\n            }\n\n            tb.InsertText(newText);\n            tb.TextSource.Manager.ExecuteCommand(new SelectCommand(tb.TextSource));\n            tb.EndAutoUndo();\n            tb.Focus();\n        }\n\n        int PointToItemIndex(Point p)\n        {\n            return (p.Y + VerticalScroll.Value) / ItemHeight;\n        }\n\n        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)\n        {\n            ProcessKey(keyData, Keys.None);\n\n            return base.ProcessCmdKey(ref msg, keyData);\n        }\n\n        private bool ProcessKey(Keys keyData, Keys keyModifiers)\n        {\n            if (keyModifiers == Keys.None)\n                switch (keyData)\n                {\n                    case Keys.Down:\n                        SelectNext(+1);\n                        return true;\n                    case Keys.PageDown:\n                        SelectNext(+10);\n                        return true;\n                    case Keys.Up:\n                        SelectNext(-1);\n                        return true;\n                    case Keys.PageUp:\n                        SelectNext(-10);\n                        return true;\n                    case Keys.Enter:\n                        OnSelecting();\n                        return true;\n                    case Keys.Tab:\n                        if (!AllowTabKey)\n                            break;\n                        OnSelecting();\n                        return true;\n                    case Keys.Escape:\n                        Menu.Close();\n                        return true;\n                }\n\n            return false;\n        }\n\n        public void SelectNext(int shift)\n        {\n            FocussedItemIndex = Math.Max(0, Math.Min(FocussedItemIndex + shift, visibleItems.Count - 1));\n            DoSelectedVisible();\n            Invalidate();\n        }\n\n        private void DoSelectedVisible()\n        {\n            if (FocussedItem != null)\n                SetToolTip(FocussedItem);\n\n            var y = FocussedItemIndex * ItemHeight - VerticalScroll.Value;\n            if (y < 0)\n                VerticalScroll.Value = FocussedItemIndex * ItemHeight;\n            if (y > ClientSize.Height - ItemHeight)\n                VerticalScroll.Value = Math.Min(VerticalScroll.Maximum,\n                    FocussedItemIndex * ItemHeight - ClientSize.Height + ItemHeight);\n            //some magic for update scrolls\n            AutoScrollMinSize -= new Size(1, 0);\n            AutoScrollMinSize += new Size(1, 0);\n        }\n\n        private void SetToolTip(AutocompleteItem autocompleteItem)\n        {\n            var title = autocompleteItem.ToolTipTitle;\n            var text = autocompleteItem.ToolTipText;\n\n            if (string.IsNullOrEmpty(title))\n            {\n                toolTip.ToolTipTitle = null;\n                toolTip.SetToolTip(this, null);\n                return;\n            }\n\n            if (this.Parent != null)\n            {\n                IWin32Window window = this.Parent ?? this;\n               /* Point location;\n\n                if ((this.PointToScreen(this.Location).X + MaxToolTipSize.Width + 105) <\n                    Screen.FromControl(this.Parent).WorkingArea.Right)\n                    location = new Point(Right + 5, 0);\n                else\n                    location = new Point(Left - 105 - MaximumSize.Width, 0);*/\n                var location = new Point(Right + 3 + Menu.Left, Menu.Top);\n\n                if (string.IsNullOrEmpty(text))\n                    toolTip.ToolTipTitle = null;\n                else\n                    toolTip.ToolTipTitle = title;\n\n                toolTip.Show(text, window, location.X, location.Y, ToolTipDuration);\n            }\n        }\n\n        public int Count\n        {\n            get { return visibleItems.Count; }\n        }\n\n        public void SetAutocompleteItems(ICollection<string> items)\n        {\n            List<AutocompleteItem> list = new List<AutocompleteItem>(items.Count);\n            foreach (var item in items)\n                list.Add(new AutocompleteItem(item));\n            SetAutocompleteItems(list);\n        }\n\n        public void SetAutocompleteItems(IEnumerable<AutocompleteItem> items)\n        {\n            sourceItems = items;\n        }\n    }\n\n    public class SelectingEventArgs : EventArgs\n    {\n        public AutocompleteItem Item { get; internal set; }\n        public bool Cancel { get; set; }\n        public int SelectedIndex { get; set; }\n        public bool Handled { get; set; }\n    }\n\n    public class SelectedEventArgs : EventArgs\n    {\n        public AutocompleteItem Item { get; internal set; }\n        public FastColoredTextBox Tb { get; set; }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Bookmarks.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Text;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Base class for bookmark collection\n    /// </summary>\n    public abstract class BaseBookmarks : ICollection<Bookmark>, IDisposable\n    {\n        #region ICollection\n\n        public abstract void Add(Bookmark item);\n        public abstract void Clear();\n        public abstract bool Contains(Bookmark item);\n        public abstract void CopyTo(Bookmark[] array, int arrayIndex);\n        public abstract int Count { get; }\n        public abstract bool IsReadOnly { get; }\n        public abstract bool Remove(Bookmark item);\n        public abstract IEnumerator<Bookmark> GetEnumerator();\n\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        #endregion\n\n        #region IDisposable\n\n        public abstract void Dispose();\n\n        #endregion\n\n        #region Additional properties\n\n        public abstract void Add(int lineIndex, string bookmarkName);\n        public abstract void Add(int lineIndex);\n        public abstract bool Contains(int lineIndex);\n        public abstract bool Remove(int lineIndex);\n        public abstract Bookmark GetBookmark(int i);\n\n        #endregion\n    }\n\n    /// <summary>\n    /// Collection of bookmarks\n    /// </summary>\n    public class Bookmarks : BaseBookmarks\n    {\n        protected FastColoredTextBox tb;\n        protected List<Bookmark> items = new List<Bookmark>();\n        protected int counter;\n\n        public Bookmarks(FastColoredTextBox tb)\n        {\n            this.tb = tb;\n            tb.LineInserted += tb_LineInserted;\n            tb.LineRemoved += tb_LineRemoved;\n        }\n\n        protected virtual void tb_LineRemoved(object sender, LineRemovedEventArgs e)\n        {\n            for (int i = 0; i < Count; i++)\n                if (items[i].LineIndex >= e.Index)\n                {\n                    if (items[i].LineIndex >= e.Index + e.Count)\n                    {\n                        items[i].LineIndex = items[i].LineIndex - e.Count;\n                        continue;\n                    }\n\n                    var was = e.Index <= 0;\n                    foreach (var b in items)\n                        if (b.LineIndex == e.Index - 1)\n                            was = true;\n\n                    if (was)\n                    {\n                        items.RemoveAt(i);\n                        i--;\n                    }\n                    else\n                        items[i].LineIndex = e.Index - 1;\n\n                    //if (items[i].LineIndex == e.Index + e.Count - 1)\n                    //{\n                    //    items[i].LineIndex = items[i].LineIndex - e.Count;\n                    //    continue;\n                    //}\n                    //\n                    //items.RemoveAt(i);\n                    //i--;\n                }\n        }\n\n        protected virtual void tb_LineInserted(object sender, LineInsertedEventArgs e)\n        {\n            for (int i = 0; i < Count; i++)\n                if (items[i].LineIndex >= e.Index)\n                {\n                    items[i].LineIndex = items[i].LineIndex + e.Count;\n                }\n                else if (items[i].LineIndex == e.Index - 1 && e.Count == 1)\n                {\n                    if (tb[e.Index - 1].StartSpacesCount == tb[e.Index - 1].Count)\n                        items[i].LineIndex = items[i].LineIndex + e.Count;\n                }\n        }\n\n        public override void Dispose()\n        {\n            tb.LineInserted -= tb_LineInserted;\n            tb.LineRemoved -= tb_LineRemoved;\n        }\n\n        public override IEnumerator<Bookmark> GetEnumerator()\n        {\n            foreach (var item in items)\n                yield return item;\n        }\n\n        public override void Add(int lineIndex, string bookmarkName)\n        {\n            Add(new Bookmark(tb, bookmarkName ?? \"Bookmark \" + counter, lineIndex));\n        }\n\n        public override void Add(int lineIndex)\n        {\n            Add(new Bookmark(tb, \"Bookmark \" + counter, lineIndex));\n        }\n\n        public override void Clear()\n        {\n            items.Clear();\n            counter = 0;\n        }\n\n        public override void Add(Bookmark bookmark)\n        {\n            foreach (var bm in items)\n                if (bm.LineIndex == bookmark.LineIndex)\n                    return;\n\n            items.Add(bookmark);\n            counter++;\n            tb.Invalidate();\n        }\n\n        public override bool Contains(Bookmark item)\n        {\n            return items.Contains(item);\n        }\n\n        public override bool Contains(int lineIndex)\n        {\n            foreach (var item in items)\n                if (item.LineIndex == lineIndex)\n                    return true;\n            return false;\n        }\n\n        public override void CopyTo(Bookmark[] array, int arrayIndex)\n        {\n            items.CopyTo(array, arrayIndex);\n        }\n\n        public override int Count\n        {\n            get { return items.Count; }\n        }\n\n        public override bool IsReadOnly\n        {\n            get { return false; }\n        }\n\n        public override bool Remove(Bookmark item)\n        {\n            tb.Invalidate();\n            return items.Remove(item);\n        }\n\n        /// <summary>\n        /// Removes bookmark by line index\n        /// </summary>\n        public override bool Remove(int lineIndex)\n        {\n            bool was = false;\n            for (int i = 0; i < Count; i++)\n                if (items[i].LineIndex == lineIndex)\n                {\n                    items.RemoveAt(i);\n                    i--;\n                    was = true;\n                }\n\n            tb.Invalidate();\n\n            return was;\n        }\n\n        /// <summary>\n        /// Returns Bookmark by index.\n        /// </summary>\n        public override Bookmark GetBookmark(int i)\n        {\n            return items[i];\n        }\n    }\n\n    /// <summary>\n    /// Bookmark of FastColoredTextbox\n    /// </summary>\n    public class Bookmark\n    {\n        public FastColoredTextBox TB { get; private set; }\n\n        /// <summary>\n        /// Name of bookmark\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Line index\n        /// </summary>\n        public int LineIndex { get; set; }\n\n        /// <summary>\n        /// Color of bookmark sign\n        /// </summary>\n        public Color Color { get; set; }\n\n        /// <summary>\n        /// Scroll textbox to the bookmark\n        /// </summary>\n        public virtual void DoVisible()\n        {\n            TB.Selection.Start = new Place(0, LineIndex);\n            TB.DoRangeVisible(TB.Selection, true);\n            TB.Invalidate();\n        }\n\n        public Bookmark(FastColoredTextBox tb, string name, int lineIndex)\n        {\n            this.TB = tb;\n            this.Name = name;\n            this.LineIndex = lineIndex;\n            Color = tb.BookmarkColor;\n        }\n\n        public virtual void Paint(Graphics gr, Rectangle lineRect)\n        {\n            var size = TB.CharHeight - 1;\n            using (var brush =\n                new LinearGradientBrush(new Rectangle(0, lineRect.Top, size, size), Color.White, Color, 45))\n                gr.FillEllipse(brush, 0, lineRect.Top, size, size);\n            using (var pen = new Pen(Color))\n                gr.DrawEllipse(pen, 0, lineRect.Top, size, size);\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Char.cs",
    "content": "﻿using System;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Char and style\n    /// </summary>\n    public struct Char\n    {\n        /// <summary>\n        /// Unicode character\n        /// </summary>\n        public char c;\n\n        /// <summary>\n        /// Style bit mask\n        /// </summary>\n        /// <remarks>Bit 1 in position n means that this char will rendering by FastColoredTextBox.Styles[n]</remarks>\n        public StyleIndex style;\n\n        public Char(char c)\n        {\n            this.c = c;\n            style = StyleIndex.None;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/CommandManager.cs",
    "content": "﻿using System.Collections.Generic;\nusing System;\n\nnamespace FastColoredTextBoxNS\n{\n    public class CommandManager\n    {\n        readonly int maxHistoryLength = 200;\n        LimitedStack<UndoableCommand> history;\n        Stack<UndoableCommand> redoStack = new Stack<UndoableCommand>();\n        public TextSource TextSource { get; private set; }\n        public bool UndoRedoStackIsEnabled { get; set; }\n\n        public event EventHandler RedoCompleted = delegate { };\n\n        public CommandManager(TextSource ts)\n        {\n            history = new LimitedStack<UndoableCommand>(maxHistoryLength);\n            TextSource = ts;\n            UndoRedoStackIsEnabled = true;\n        }\n\n        public virtual void ExecuteCommand(Command cmd)\n        {\n            if (disabledCommands > 0)\n                return;\n\n            //multirange ?\n            if (cmd.ts.CurrentTB.Selection.ColumnSelectionMode)\n                if (cmd is UndoableCommand)\n                    //make wrapper\n                    cmd = new MultiRangeCommand((UndoableCommand) cmd);\n\n\n            if (cmd is UndoableCommand)\n            {\n                //if range is ColumnRange, then create wrapper\n                (cmd as UndoableCommand).autoUndo = autoUndoCommands > 0;\n                history.Push(cmd as UndoableCommand);\n            }\n\n            try\n            {\n                cmd.Execute();\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n                //OnTextChanging cancels enter of the text\n                if (cmd is UndoableCommand)\n                    history.Pop();\n            }\n\n            //\n            if (!UndoRedoStackIsEnabled)\n                ClearHistory();\n            //\n            redoStack.Clear();\n            //\n            TextSource.CurrentTB.OnUndoRedoStateChanged();\n        }\n\n        public void Undo()\n        {\n            if (history.Count > 0)\n            {\n                var cmd = history.Pop();\n                //\n                BeginDisableCommands(); //prevent text changing into handlers\n                try\n                {\n                    cmd.Undo();\n                }\n                finally\n                {\n                    EndDisableCommands();\n                }\n\n                //\n                redoStack.Push(cmd);\n            }\n\n            //undo next autoUndo command\n            if (history.Count > 0)\n            {\n                if (history.Peek().autoUndo)\n                    Undo();\n            }\n\n            TextSource.CurrentTB.OnUndoRedoStateChanged();\n        }\n\n        protected int disabledCommands = 0;\n\n        private void EndDisableCommands()\n        {\n            disabledCommands--;\n        }\n\n        private void BeginDisableCommands()\n        {\n            disabledCommands++;\n        }\n\n        int autoUndoCommands = 0;\n\n        public void EndAutoUndoCommands()\n        {\n            autoUndoCommands--;\n            if (autoUndoCommands == 0)\n                if (history.Count > 0)\n                    history.Peek().autoUndo = false;\n        }\n\n        public void BeginAutoUndoCommands()\n        {\n            autoUndoCommands++;\n        }\n\n        internal void ClearHistory()\n        {\n            history.Clear();\n            redoStack.Clear();\n            TextSource.CurrentTB.OnUndoRedoStateChanged();\n        }\n\n        internal void Redo()\n        {\n            if (redoStack.Count == 0)\n                return;\n            UndoableCommand cmd;\n            BeginDisableCommands(); //prevent text changing into handlers\n            try\n            {\n                cmd = redoStack.Pop();\n                if (TextSource.CurrentTB.Selection.ColumnSelectionMode)\n                    TextSource.CurrentTB.Selection.ColumnSelectionMode = false;\n                TextSource.CurrentTB.Selection.Start = cmd.sel.Start;\n                TextSource.CurrentTB.Selection.End = cmd.sel.End;\n                cmd.Execute();\n                history.Push(cmd);\n            }\n            finally\n            {\n                EndDisableCommands();\n            }\n\n            //call event\n            RedoCompleted(this, EventArgs.Empty);\n\n            //redo command after autoUndoable command\n            if (cmd.autoUndo)\n                Redo();\n\n            TextSource.CurrentTB.OnUndoRedoStateChanged();\n        }\n\n        public bool UndoEnabled\n        {\n            get { return history.Count > 0; }\n        }\n\n        public bool RedoEnabled\n        {\n            get { return redoStack.Count > 0; }\n        }\n    }\n\n    public abstract class Command\n    {\n        public TextSource ts;\n        public abstract void Execute();\n    }\n\n    internal class RangeInfo\n    {\n        public Place Start { get; set; }\n        public Place End { get; set; }\n\n        public RangeInfo(Range r)\n        {\n            Start = r.Start;\n            End = r.End;\n        }\n\n        internal int FromX\n        {\n            get\n            {\n                if (End.iLine < Start.iLine) return End.iChar;\n                if (End.iLine > Start.iLine) return Start.iChar;\n                return Math.Min(End.iChar, Start.iChar);\n            }\n        }\n    }\n\n    public abstract class UndoableCommand : Command\n    {\n        internal RangeInfo sel;\n        internal RangeInfo lastSel;\n        internal bool autoUndo;\n\n        public UndoableCommand(TextSource ts)\n        {\n            this.ts = ts;\n            sel = new RangeInfo(ts.CurrentTB.Selection);\n        }\n\n        public virtual void Undo()\n        {\n            OnTextChanged(true);\n        }\n\n        public override void Execute()\n        {\n            lastSel = new RangeInfo(ts.CurrentTB.Selection);\n            OnTextChanged(false);\n        }\n\n        protected virtual void OnTextChanged(bool invert)\n        {\n            bool b = sel.Start.iLine < lastSel.Start.iLine;\n            if (invert)\n            {\n                if (b)\n                    ts.OnTextChanged(sel.Start.iLine, sel.Start.iLine);\n                else\n                    ts.OnTextChanged(sel.Start.iLine, lastSel.Start.iLine);\n            }\n            else\n            {\n                if (b)\n                    ts.OnTextChanged(sel.Start.iLine, lastSel.Start.iLine);\n                else\n                    ts.OnTextChanged(lastSel.Start.iLine, lastSel.Start.iLine);\n            }\n        }\n\n        public abstract UndoableCommand Clone();\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Commands.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Insert single char\n    /// </summary>\n    /// <remarks>This operation includes also insertion of new line and removing char by backspace</remarks>\n    public class InsertCharCommand : UndoableCommand\n    {\n        public char c;\n        char deletedChar = '\\x0';\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"tb\">Underlaying textbox</param>\n        /// <param name=\"c\">Inserting char</param>\n        public InsertCharCommand(TextSource ts, char c) : base(ts)\n        {\n            this.c = c;\n        }\n\n        /// <summary>\n        /// Undo operation\n        /// </summary>\n        public override void Undo()\n        {\n            ts.OnTextChanging();\n            switch (c)\n            {\n                case '\\n':\n                    MergeLines(sel.Start.iLine, ts);\n                    break;\n                case '\\r': break;\n                case '\\b':\n                    ts.CurrentTB.Selection.Start = lastSel.Start;\n                    char cc = '\\x0';\n                    if (deletedChar != '\\x0')\n                    {\n                        ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);\n                        InsertChar(deletedChar, ref cc, ts);\n                    }\n\n                    break;\n                case '\\t':\n                    ts.CurrentTB.ExpandBlock(sel.Start.iLine);\n                    for (int i = sel.FromX; i < lastSel.FromX; i++)\n                        ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);\n                    ts.CurrentTB.Selection.Start = sel.Start;\n                    break;\n                default:\n                    ts.CurrentTB.ExpandBlock(sel.Start.iLine);\n                    ts[sel.Start.iLine].RemoveAt(sel.Start.iChar);\n                    ts.CurrentTB.Selection.Start = sel.Start;\n                    break;\n            }\n\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(sel.Start.iLine, sel.Start.iLine));\n\n            base.Undo();\n        }\n\n        /// <summary>\n        /// Execute operation\n        /// </summary>\n        public override void Execute()\n        {\n            ts.CurrentTB.ExpandBlock(ts.CurrentTB.Selection.Start.iLine);\n            string s = c.ToString();\n            ts.OnTextChanging(ref s);\n            if (s.Length == 1)\n                c = s[0];\n\n            if (String.IsNullOrEmpty(s))\n                throw new ArgumentOutOfRangeException();\n\n\n            if (ts.Count == 0)\n                InsertLine(ts);\n            InsertChar(c, ref deletedChar, ts);\n\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(ts.CurrentTB.Selection.Start.iLine,\n                ts.CurrentTB.Selection.Start.iLine));\n            base.Execute();\n        }\n\n        internal static void InsertChar(char c, ref char deletedChar, TextSource ts)\n        {\n            var tb = ts.CurrentTB;\n\n            switch (c)\n            {\n                case '\\n':\n                    if (!ts.CurrentTB.AllowInsertRemoveLines)\n                        throw new ArgumentOutOfRangeException(\"Cant insert this char in ColumnRange mode\");\n                    if (ts.Count == 0)\n                        InsertLine(ts);\n                    InsertLine(ts);\n                    break;\n                case '\\r': break;\n                case '\\b': //backspace\n                    if (tb.Selection.Start.iChar == 0 && tb.Selection.Start.iLine == 0)\n                        return;\n                    if (tb.Selection.Start.iChar == 0)\n                    {\n                        if (!ts.CurrentTB.AllowInsertRemoveLines)\n                            throw new ArgumentOutOfRangeException(\"Cant insert this char in ColumnRange mode\");\n                        if (tb.LineInfos[tb.Selection.Start.iLine - 1].VisibleState != VisibleState.Visible)\n                            tb.ExpandBlock(tb.Selection.Start.iLine - 1);\n                        deletedChar = '\\n';\n                        MergeLines(tb.Selection.Start.iLine - 1, ts);\n                    }\n                    else\n                    {\n                        deletedChar = ts[tb.Selection.Start.iLine][tb.Selection.Start.iChar - 1].c;\n                        ts[tb.Selection.Start.iLine].RemoveAt(tb.Selection.Start.iChar - 1);\n                        tb.Selection.Start = new Place(tb.Selection.Start.iChar - 1, tb.Selection.Start.iLine);\n                    }\n\n                    break;\n                case '\\t':\n                    int spaceCountNextTabStop = tb.TabLength - (tb.Selection.Start.iChar % tb.TabLength);\n                    if (spaceCountNextTabStop == 0)\n                        spaceCountNextTabStop = tb.TabLength;\n\n                    for (int i = 0; i < spaceCountNextTabStop; i++)\n                        ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(' '));\n\n                    tb.Selection.Start = new Place(tb.Selection.Start.iChar + spaceCountNextTabStop,\n                        tb.Selection.Start.iLine);\n                    break;\n                default:\n                    ts[tb.Selection.Start.iLine].Insert(tb.Selection.Start.iChar, new Char(c));\n                    tb.Selection.Start = new Place(tb.Selection.Start.iChar + 1, tb.Selection.Start.iLine);\n                    break;\n            }\n        }\n\n        internal static void InsertLine(TextSource ts)\n        {\n            var tb = ts.CurrentTB;\n\n            if (!tb.Multiline && tb.LinesCount > 0)\n                return;\n\n            if (ts.Count == 0)\n                ts.InsertLine(0, ts.CreateLine());\n            else\n                BreakLines(tb.Selection.Start.iLine, tb.Selection.Start.iChar, ts);\n\n            tb.Selection.Start = new Place(0, tb.Selection.Start.iLine + 1);\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n        }\n\n        /// <summary>\n        /// Merge lines i and i+1\n        /// </summary>\n        internal static void MergeLines(int i, TextSource ts)\n        {\n            var tb = ts.CurrentTB;\n\n            if (i + 1 >= ts.Count)\n                return;\n            tb.ExpandBlock(i);\n            tb.ExpandBlock(i + 1);\n            int pos = ts[i].Count;\n            //\n            /*\n            if(ts[i].Count == 0)\n                ts.RemoveLine(i);\n            else*/\n            if (ts[i + 1].Count == 0)\n                ts.RemoveLine(i + 1);\n            else\n            {\n                ts[i].AddRange(ts[i + 1]);\n                ts.RemoveLine(i + 1);\n            }\n\n            tb.Selection.Start = new Place(pos, i);\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n        }\n\n        internal static void BreakLines(int iLine, int pos, TextSource ts)\n        {\n            Line newLine = ts.CreateLine();\n            for (int i = pos; i < ts[iLine].Count; i++)\n                newLine.Add(ts[iLine][i]);\n            ts[iLine].RemoveRange(pos, ts[iLine].Count - pos);\n            //\n            ts.InsertLine(iLine + 1, newLine);\n        }\n\n        public override UndoableCommand Clone()\n        {\n            return new InsertCharCommand(ts, c);\n        }\n    }\n\n    /// <summary>\n    /// Insert text\n    /// </summary>\n    public class InsertTextCommand : UndoableCommand\n    {\n        public string InsertedText;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"tb\">Underlaying textbox</param>\n        /// <param name=\"insertedText\">Text for inserting</param>\n        public InsertTextCommand(TextSource ts, string insertedText) : base(ts)\n        {\n            this.InsertedText = insertedText;\n        }\n\n        /// <summary>\n        /// Undo operation\n        /// </summary>\n        public override void Undo()\n        {\n            ts.CurrentTB.Selection.Start = sel.Start;\n            ts.CurrentTB.Selection.End = lastSel.Start;\n            ts.OnTextChanging();\n            ClearSelectedCommand.ClearSelected(ts);\n            base.Undo();\n        }\n\n        /// <summary>\n        /// Execute operation\n        /// </summary>\n        public override void Execute()\n        {\n            ts.OnTextChanging(ref InsertedText);\n            InsertText(InsertedText, ts);\n            base.Execute();\n        }\n\n        internal static void InsertText(string insertedText, TextSource ts)\n        {\n            var tb = ts.CurrentTB;\n            try\n            {\n                tb.Selection.BeginUpdate();\n                char cc = '\\x0';\n\n                if (ts.Count == 0)\n                {\n                    InsertCharCommand.InsertLine(ts);\n                    tb.Selection.Start = Place.Empty;\n                }\n\n                tb.ExpandBlock(tb.Selection.Start.iLine);\n                var len = insertedText.Length;\n                for (int i = 0; i < len; i++)\n                {\n                    var c = insertedText[i];\n                    if (c == '\\r' && (i >= len - 1 || insertedText[i + 1] != '\\n'))\n                        InsertCharCommand.InsertChar('\\n', ref cc, ts);\n                    else\n                        InsertCharCommand.InsertChar(c, ref cc, ts);\n                }\n\n                ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n            }\n            finally\n            {\n                tb.Selection.EndUpdate();\n            }\n        }\n\n        public override UndoableCommand Clone()\n        {\n            return new InsertTextCommand(ts, InsertedText);\n        }\n    }\n\n    /// <summary>\n    /// Insert text into given ranges\n    /// </summary>\n    public class ReplaceTextCommand : UndoableCommand\n    {\n        string insertedText;\n        List<Range> ranges;\n        List<string> prevText = new List<string>();\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"tb\">Underlaying textbox</param>\n        /// <param name=\"ranges\">List of ranges for replace</param>\n        /// <param name=\"insertedText\">Text for inserting</param>\n        public ReplaceTextCommand(TextSource ts, List<Range> ranges, string insertedText)\n            : base(ts)\n        {\n            //sort ranges by place\n            ranges.Sort((r1, r2) =>\n            {\n                if (r1.Start.iLine == r2.Start.iLine)\n                    return r1.Start.iChar.CompareTo(r2.Start.iChar);\n                return r1.Start.iLine.CompareTo(r2.Start.iLine);\n            });\n            //\n            this.ranges = ranges;\n            this.insertedText = insertedText;\n            lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);\n        }\n\n        /// <summary>\n        /// Undo operation\n        /// </summary>\n        public override void Undo()\n        {\n            var tb = ts.CurrentTB;\n\n            ts.OnTextChanging();\n            tb.BeginUpdate();\n\n            tb.Selection.BeginUpdate();\n            for (int i = 0; i < ranges.Count; i++)\n            {\n                tb.Selection.Start = ranges[i].Start;\n                for (int j = 0; j < insertedText.Length; j++)\n                    tb.Selection.GoRight(true);\n                ClearSelected(ts);\n                InsertTextCommand.InsertText(prevText[prevText.Count - i - 1], ts);\n            }\n\n            tb.Selection.EndUpdate();\n            tb.EndUpdate();\n\n            if (ranges.Count > 0)\n                ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);\n\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n        }\n\n        /// <summary>\n        /// Execute operation\n        /// </summary>\n        public override void Execute()\n        {\n            var tb = ts.CurrentTB;\n            prevText.Clear();\n\n            ts.OnTextChanging(ref insertedText);\n\n            tb.Selection.BeginUpdate();\n            tb.BeginUpdate();\n            for (int i = ranges.Count - 1; i >= 0; i--)\n            {\n                tb.Selection.Start = ranges[i].Start;\n                tb.Selection.End = ranges[i].End;\n                prevText.Add(tb.Selection.Text);\n                ClearSelected(ts);\n                if (insertedText != \"\")\n                    InsertTextCommand.InsertText(insertedText, ts);\n            }\n\n            if (ranges.Count > 0)\n                ts.OnTextChanged(ranges[0].Start.iLine, ranges[ranges.Count - 1].End.iLine);\n            tb.EndUpdate();\n            tb.Selection.EndUpdate();\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n\n            lastSel = new RangeInfo(tb.Selection);\n        }\n\n        public override UndoableCommand Clone()\n        {\n            return new ReplaceTextCommand(ts, new List<Range>(ranges), insertedText);\n        }\n\n        internal static void ClearSelected(TextSource ts)\n        {\n            var tb = ts.CurrentTB;\n\n            tb.Selection.Normalize();\n\n            Place start = tb.Selection.Start;\n            Place end = tb.Selection.End;\n            int fromLine = Math.Min(end.iLine, start.iLine);\n            int toLine = Math.Max(end.iLine, start.iLine);\n            int fromChar = tb.Selection.FromX;\n            int toChar = tb.Selection.ToX;\n            if (fromLine < 0) return;\n            //\n            if (fromLine == toLine)\n                ts[fromLine].RemoveRange(fromChar, toChar - fromChar);\n            else\n            {\n                ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);\n                ts[toLine].RemoveRange(0, toChar);\n                ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);\n                InsertCharCommand.MergeLines(fromLine, ts);\n            }\n        }\n    }\n\n    /// <summary>\n    /// Clear selected text\n    /// </summary>\n    public class ClearSelectedCommand : UndoableCommand\n    {\n        string deletedText;\n\n        /// <summary>\n        /// Construstor\n        /// </summary>\n        /// <param name=\"tb\">Underlaying textbox</param>\n        public ClearSelectedCommand(TextSource ts) : base(ts)\n        {\n        }\n\n        /// <summary>\n        /// Undo operation\n        /// </summary>\n        public override void Undo()\n        {\n            ts.CurrentTB.Selection.Start = new Place(sel.FromX, Math.Min(sel.Start.iLine, sel.End.iLine));\n            ts.OnTextChanging();\n            InsertTextCommand.InsertText(deletedText, ts);\n            ts.OnTextChanged(sel.Start.iLine, sel.End.iLine);\n            ts.CurrentTB.Selection.Start = sel.Start;\n            ts.CurrentTB.Selection.End = sel.End;\n        }\n\n        /// <summary>\n        /// Execute operation\n        /// </summary>\n        public override void Execute()\n        {\n            var tb = ts.CurrentTB;\n\n            string temp = null;\n            ts.OnTextChanging(ref temp);\n            if (temp == \"\")\n                throw new ArgumentOutOfRangeException();\n\n            deletedText = tb.Selection.Text;\n            ClearSelected(ts);\n            lastSel = new RangeInfo(tb.Selection);\n            ts.OnTextChanged(lastSel.Start.iLine, lastSel.Start.iLine);\n        }\n\n        internal static void ClearSelected(TextSource ts)\n        {\n            var tb = ts.CurrentTB;\n\n            Place start = tb.Selection.Start;\n            Place end = tb.Selection.End;\n            int fromLine = Math.Min(end.iLine, start.iLine);\n            int toLine = Math.Max(end.iLine, start.iLine);\n            int fromChar = tb.Selection.FromX;\n            int toChar = tb.Selection.ToX;\n            if (fromLine < 0) return;\n            //\n            if (fromLine == toLine)\n                ts[fromLine].RemoveRange(fromChar, toChar - fromChar);\n            else\n            {\n                ts[fromLine].RemoveRange(fromChar, ts[fromLine].Count - fromChar);\n                ts[toLine].RemoveRange(0, toChar);\n                ts.RemoveLine(fromLine + 1, toLine - fromLine - 1);\n                InsertCharCommand.MergeLines(fromLine, ts);\n            }\n\n            //\n            tb.Selection.Start = new Place(fromChar, fromLine);\n            //\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(fromLine, toLine));\n        }\n\n        public override UndoableCommand Clone()\n        {\n            return new ClearSelectedCommand(ts);\n        }\n    }\n\n    /// <summary>\n    /// Replaces text\n    /// </summary>\n    public class ReplaceMultipleTextCommand : UndoableCommand\n    {\n        List<ReplaceRange> ranges;\n        List<string> prevText = new List<string>();\n\n        public class ReplaceRange\n        {\n            public Range ReplacedRange { get; set; }\n            public String ReplaceText { get; set; }\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"ts\">Underlaying textsource</param>\n        /// <param name=\"ranges\">List of ranges for replace</param>\n        public ReplaceMultipleTextCommand(TextSource ts, List<ReplaceRange> ranges)\n            : base(ts)\n        {\n            //sort ranges by place\n            ranges.Sort((r1, r2) =>\n            {\n                if (r1.ReplacedRange.Start.iLine == r2.ReplacedRange.Start.iLine)\n                    return r1.ReplacedRange.Start.iChar.CompareTo(r2.ReplacedRange.Start.iChar);\n                return r1.ReplacedRange.Start.iLine.CompareTo(r2.ReplacedRange.Start.iLine);\n            });\n            //\n            this.ranges = ranges;\n            lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);\n        }\n\n        /// <summary>\n        /// Undo operation\n        /// </summary>\n        public override void Undo()\n        {\n            var tb = ts.CurrentTB;\n\n            ts.OnTextChanging();\n\n            tb.Selection.BeginUpdate();\n            for (int i = 0; i < ranges.Count; i++)\n            {\n                tb.Selection.Start = ranges[i].ReplacedRange.Start;\n                for (int j = 0; j < ranges[i].ReplaceText.Length; j++)\n                    tb.Selection.GoRight(true);\n                ClearSelectedCommand.ClearSelected(ts);\n                var prevTextIndex = ranges.Count - 1 - i;\n                InsertTextCommand.InsertText(prevText[prevTextIndex], ts);\n                ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.Start.iLine);\n            }\n\n            tb.Selection.EndUpdate();\n\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n        }\n\n        /// <summary>\n        /// Execute operation\n        /// </summary>\n        public override void Execute()\n        {\n            var tb = ts.CurrentTB;\n            prevText.Clear();\n\n            ts.OnTextChanging();\n\n            tb.Selection.BeginUpdate();\n            for (int i = ranges.Count - 1; i >= 0; i--)\n            {\n                tb.Selection.Start = ranges[i].ReplacedRange.Start;\n                tb.Selection.End = ranges[i].ReplacedRange.End;\n                prevText.Add(tb.Selection.Text);\n                ClearSelectedCommand.ClearSelected(ts);\n                InsertTextCommand.InsertText(ranges[i].ReplaceText, ts);\n                ts.OnTextChanged(ranges[i].ReplacedRange.Start.iLine, ranges[i].ReplacedRange.End.iLine);\n            }\n\n            tb.Selection.EndUpdate();\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n\n            lastSel = new RangeInfo(tb.Selection);\n        }\n\n        public override UndoableCommand Clone()\n        {\n            return new ReplaceMultipleTextCommand(ts, new List<ReplaceRange>(ranges));\n        }\n    }\n\n    /// <summary>\n    /// Removes lines\n    /// </summary>\n    public class RemoveLinesCommand : UndoableCommand\n    {\n        List<int> iLines;\n        List<string> prevText = new List<string>();\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"tb\">Underlaying textbox</param>\n        /// <param name=\"ranges\">List of ranges for replace</param>\n        /// <param name=\"insertedText\">Text for inserting</param>\n        public RemoveLinesCommand(TextSource ts, List<int> iLines)\n            : base(ts)\n        {\n            //sort iLines\n            iLines.Sort();\n            //\n            this.iLines = iLines;\n            lastSel = sel = new RangeInfo(ts.CurrentTB.Selection);\n        }\n\n        /// <summary>\n        /// Undo operation\n        /// </summary>\n        public override void Undo()\n        {\n            var tb = ts.CurrentTB;\n\n            ts.OnTextChanging();\n\n            tb.Selection.BeginUpdate();\n            //tb.BeginUpdate();\n            for (int i = 0; i < iLines.Count; i++)\n            {\n                var iLine = iLines[i];\n\n                if (iLine < ts.Count)\n                    tb.Selection.Start = new Place(0, iLine);\n                else\n                    tb.Selection.Start = new Place(ts[ts.Count - 1].Count, ts.Count - 1);\n\n                InsertCharCommand.InsertLine(ts);\n                tb.Selection.Start = new Place(0, iLine);\n                var text = prevText[prevText.Count - i - 1];\n                InsertTextCommand.InsertText(text, ts);\n                ts[iLine].IsChanged = true;\n                if (iLine < ts.Count - 1)\n                    ts[iLine + 1].IsChanged = true;\n                else\n                    ts[iLine - 1].IsChanged = true;\n                if (text.Trim() != string.Empty)\n                    ts.OnTextChanged(iLine, iLine);\n            }\n\n            //tb.EndUpdate();\n            tb.Selection.EndUpdate();\n\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n        }\n\n        /// <summary>\n        /// Execute operation\n        /// </summary>\n        public override void Execute()\n        {\n            var tb = ts.CurrentTB;\n            prevText.Clear();\n\n            ts.OnTextChanging();\n\n            tb.Selection.BeginUpdate();\n            for (int i = iLines.Count - 1; i >= 0; i--)\n            {\n                var iLine = iLines[i];\n\n                prevText.Add(ts[iLine].Text); //backward\n                ts.RemoveLine(iLine);\n                //ts.OnTextChanged(ranges[i].Start.iLine, ranges[i].End.iLine);\n            }\n\n            tb.Selection.Start = new Place(0, 0);\n            tb.Selection.EndUpdate();\n            ts.NeedRecalc(new TextSource.TextChangedEventArgs(0, 1));\n\n            lastSel = new RangeInfo(tb.Selection);\n        }\n\n        public override UndoableCommand Clone()\n        {\n            return new RemoveLinesCommand(ts, new List<int>(iLines));\n        }\n    }\n\n    /// <summary>\n    /// Wrapper for multirange commands\n    /// </summary>\n    public class MultiRangeCommand : UndoableCommand\n    {\n        private UndoableCommand cmd;\n        private Range range;\n        private List<UndoableCommand> commandsByRanges = new List<UndoableCommand>();\n\n        public MultiRangeCommand(UndoableCommand command) : base(command.ts)\n        {\n            this.cmd = command;\n            range = ts.CurrentTB.Selection.Clone();\n        }\n\n        public override void Execute()\n        {\n            commandsByRanges.Clear();\n            var prevSelection = range.Clone();\n            var iChar = -1;\n            var iStartLine = prevSelection.Start.iLine;\n            var iEndLine = prevSelection.End.iLine;\n            ts.CurrentTB.Selection.ColumnSelectionMode = false;\n            ts.CurrentTB.Selection.BeginUpdate();\n            ts.CurrentTB.BeginUpdate();\n            ts.CurrentTB.AllowInsertRemoveLines = false;\n            try\n            {\n                if (cmd is InsertTextCommand)\n                    ExecuteInsertTextCommand(ref iChar, (cmd as InsertTextCommand).InsertedText);\n                else if (cmd is InsertCharCommand && (cmd as InsertCharCommand).c != '\\x0' &&\n                         (cmd as InsertCharCommand).c != '\\b') //if not DEL or BACKSPACE\n                    ExecuteInsertTextCommand(ref iChar, (cmd as InsertCharCommand).c.ToString());\n                else\n                    ExecuteCommand(ref iChar);\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n            }\n            finally\n            {\n                ts.CurrentTB.AllowInsertRemoveLines = true;\n                ts.CurrentTB.EndUpdate();\n\n                ts.CurrentTB.Selection = range;\n                if (iChar >= 0)\n                {\n                    ts.CurrentTB.Selection.Start = new Place(iChar, iStartLine);\n                    ts.CurrentTB.Selection.End = new Place(iChar, iEndLine);\n                }\n\n                ts.CurrentTB.Selection.ColumnSelectionMode = true;\n                ts.CurrentTB.Selection.EndUpdate();\n            }\n        }\n\n        private void ExecuteInsertTextCommand(ref int iChar, string text)\n        {\n            var lines = text.Split('\\n');\n            var iLine = 0;\n            foreach (var r in range.GetSubRanges(true))\n            {\n                var line = ts.CurrentTB[r.Start.iLine];\n                var lineIsEmpty = r.End < r.Start && line.StartSpacesCount == line.Count;\n                if (!lineIsEmpty)\n                {\n                    var insertedText = lines[iLine % lines.Length];\n                    if (r.End < r.Start && insertedText != \"\")\n                    {\n                        //add forwarding spaces\n                        insertedText = new string(' ', r.Start.iChar - r.End.iChar) + insertedText;\n                        r.Start = r.End;\n                    }\n\n                    ts.CurrentTB.Selection = r;\n                    var c = new InsertTextCommand(ts, insertedText);\n                    c.Execute();\n                    if (ts.CurrentTB.Selection.End.iChar > iChar)\n                        iChar = ts.CurrentTB.Selection.End.iChar;\n                    commandsByRanges.Add(c);\n                }\n\n                iLine++;\n            }\n        }\n\n        private void ExecuteCommand(ref int iChar)\n        {\n            foreach (var r in range.GetSubRanges(false))\n            {\n                ts.CurrentTB.Selection = r;\n                var c = cmd.Clone();\n                c.Execute();\n                if (ts.CurrentTB.Selection.End.iChar > iChar)\n                    iChar = ts.CurrentTB.Selection.End.iChar;\n                commandsByRanges.Add(c);\n            }\n        }\n\n        public override void Undo()\n        {\n            ts.CurrentTB.BeginUpdate();\n            ts.CurrentTB.Selection.BeginUpdate();\n            try\n            {\n                for (int i = commandsByRanges.Count - 1; i >= 0; i--)\n                    commandsByRanges[i].Undo();\n            }\n            finally\n            {\n                ts.CurrentTB.Selection.EndUpdate();\n                ts.CurrentTB.EndUpdate();\n            }\n\n            ts.CurrentTB.Selection = range.Clone();\n            ts.CurrentTB.OnTextChanged(range);\n            ts.CurrentTB.OnSelectionChanged();\n            ts.CurrentTB.Selection.ColumnSelectionMode = true;\n        }\n\n        public override UndoableCommand Clone()\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n    /// <summary>\n    /// Remembers current selection and restore it after Undo\n    /// </summary>\n    public class SelectCommand : UndoableCommand\n    {\n        public SelectCommand(TextSource ts) : base(ts)\n        {\n        }\n\n        public override void Execute()\n        {\n            //remember selection\n            lastSel = new RangeInfo(ts.CurrentTB.Selection);\n        }\n\n        protected override void OnTextChanged(bool invert)\n        {\n        }\n\n        public override void Undo()\n        {\n            //restore selection\n            ts.CurrentTB.Selection = new Range(ts.CurrentTB, lastSel.Start, lastSel.End);\n        }\n\n        public override UndoableCommand Clone()\n        {\n            var result = new SelectCommand(ts);\n            if (lastSel != null)\n                result.lastSel = new RangeInfo(new Range(ts.CurrentTB, lastSel.Start, lastSel.End));\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/DocumentMap.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Drawing;\nusing System.Data;\nusing System.Drawing.Drawing2D;\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Shows document map of FCTB\n    /// </summary>\n    public class DocumentMap : Control\n    {\n        public EventHandler TargetChanged;\n\n        FastColoredTextBox target;\n        private float scale = 0.3f;\n        private bool needRepaint = true;\n        private Place startPlace = Place.Empty;\n        private bool scrollbarVisible = true;\n\n        [Description(\"Target FastColoredTextBox\")]\n        public FastColoredTextBox Target\n        {\n            get { return target; }\n            set\n            {\n                if (target != null)\n                    UnSubscribe(target);\n\n                target = value;\n                if (value != null)\n                {\n                    Subscribe(target);\n                }\n\n                OnTargetChanged();\n            }\n        }\n\n        /// <summary>\n        /// Scale\n        /// </summary>\n        public float GetScale()\n        {\n            return scale;\n        }\n\n        /// <summary>\n        /// Scale\n        /// </summary>\n        public void SetScale(float value)\n        {\n            scale = value;\n            NeedRepaint();\n        }\n\n        /// <summary>\n        /// Scrollbar visibility\n        /// </summary>\n        [Description(\"Scrollbar visibility\")]\n        [DefaultValue(true)]\n        public bool ScrollbarVisible\n        {\n            get { return scrollbarVisible; }\n            set\n            {\n                scrollbarVisible = value;\n                NeedRepaint();\n            }\n        }\n\n        public DocumentMap()\n        {\n            ForeColor = Color.Maroon;\n            SetStyle(\n                ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint |\n                ControlStyles.ResizeRedraw, true);\n            Application.Idle += Application_Idle;\n        }\n\n        void Application_Idle(object sender, EventArgs e)\n        {\n            if (needRepaint)\n                Invalidate();\n        }\n\n        protected virtual void OnTargetChanged()\n        {\n            NeedRepaint();\n\n            if (TargetChanged != null)\n                TargetChanged(this, EventArgs.Empty);\n        }\n\n        protected virtual void UnSubscribe(FastColoredTextBox target)\n        {\n            target.Scroll -= new ScrollEventHandler(Target_Scroll);\n            target.SelectionChangedDelayed -= new EventHandler(Target_SelectionChanged);\n            target.VisibleRangeChanged -= new EventHandler(Target_VisibleRangeChanged);\n        }\n\n        protected virtual void Subscribe(FastColoredTextBox target)\n        {\n            target.Scroll += new ScrollEventHandler(Target_Scroll);\n            target.SelectionChangedDelayed += new EventHandler(Target_SelectionChanged);\n            target.VisibleRangeChanged += new EventHandler(Target_VisibleRangeChanged);\n        }\n\n        protected virtual void Target_VisibleRangeChanged(object sender, EventArgs e)\n        {\n            NeedRepaint();\n        }\n\n        protected virtual void Target_SelectionChanged(object sender, EventArgs e)\n        {\n            NeedRepaint();\n        }\n\n        protected virtual void Target_Scroll(object sender, ScrollEventArgs e)\n        {\n            NeedRepaint();\n        }\n\n        protected override void OnResize(EventArgs e)\n        {\n            base.OnResize(e);\n            NeedRepaint();\n        }\n\n        public void NeedRepaint()\n        {\n            needRepaint = true;\n        }\n\n        protected override void OnPaint(PaintEventArgs e)\n        {\n            if (target == null)\n                return;\n\n            var zoom = this.GetScale() * 100 / target.Zoom;\n\n            if (zoom <= float.Epsilon)\n                return;\n\n            //calc startPlace\n            var r = target.VisibleRange;\n            if (startPlace.iLine > r.Start.iLine)\n                startPlace.iLine = r.Start.iLine;\n            else\n            {\n                var endP = target.PlaceToPoint(r.End);\n                endP.Offset(0, -(int) (ClientSize.Height / zoom) + target.CharHeight);\n                var pp = target.PointToPlace(endP);\n                if (pp.iLine > startPlace.iLine)\n                    startPlace.iLine = pp.iLine;\n            }\n\n            startPlace.iChar = 0;\n            //calc scroll pos\n            var linesCount = target.Lines.Count;\n            var sp1 = (float) r.Start.iLine / linesCount;\n            var sp2 = (float) r.End.iLine / linesCount;\n\n            //scale graphics\n            e.Graphics.ScaleTransform(zoom, zoom);\n            //draw text\n            var size = new SizeF(ClientSize.Width / zoom, ClientSize.Height / zoom);\n            target.DrawText(e.Graphics, startPlace, size.ToSize());\n\n            //draw visible rect\n            var p0 = target.PlaceToPoint(startPlace);\n            var p1 = target.PlaceToPoint(r.Start);\n            var p2 = target.PlaceToPoint(r.End);\n            var y1 = p1.Y - p0.Y;\n            var y2 = p2.Y + target.CharHeight - p0.Y;\n\n            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;\n\n            using (var brush = new SolidBrush(Color.FromArgb(50, ForeColor)))\n            using (var pen = new Pen(brush, 1 / zoom))\n            {\n                var rect = new Rectangle(0, y1, (int) ((ClientSize.Width - 1) / zoom), y2 - y1);\n                e.Graphics.FillRectangle(brush, rect);\n                e.Graphics.DrawRectangle(pen, rect);\n            }\n\n            //draw scrollbar\n            if (scrollbarVisible)\n            {\n                e.Graphics.ResetTransform();\n                e.Graphics.SmoothingMode = SmoothingMode.None;\n\n                using (var brush = new SolidBrush(Color.FromArgb(200, ForeColor)))\n                {\n                    var rect = new RectangleF(ClientSize.Width - 3, ClientSize.Height * sp1, 2,\n                        ClientSize.Height * (sp2 - sp1));\n                    e.Graphics.FillRectangle(brush, rect);\n                }\n            }\n\n            needRepaint = false;\n        }\n\n        protected override void OnMouseDown(MouseEventArgs e)\n        {\n            if (e.Button == System.Windows.Forms.MouseButtons.Left)\n                Scroll(e.Location);\n            base.OnMouseDown(e);\n        }\n\n        protected override void OnMouseMove(MouseEventArgs e)\n        {\n            if (e.Button == System.Windows.Forms.MouseButtons.Left)\n                Scroll(e.Location);\n            base.OnMouseMove(e);\n        }\n\n        private void Scroll(Point point)\n        {\n            if (target == null)\n                return;\n\n            var zoom = this.GetScale() * 100 / target.Zoom;\n\n            if (zoom <= float.Epsilon)\n                return;\n\n            var p0 = target.PlaceToPoint(startPlace);\n            p0 = new Point(0, p0.Y + (int) (point.Y / zoom));\n            var pp = target.PointToPlace(p0);\n            target.DoRangeVisible(new Range(target, pp, pp), true);\n            BeginInvoke((MethodInvoker) OnScroll);\n        }\n\n        private void OnScroll()\n        {\n            Refresh();\n            target.Refresh();\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                Application.Idle -= Application_Idle;\n                if (target != null)\n                    UnSubscribe(target);\n            }\n\n            base.Dispose(disposing);\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/EncodingDetector.cs",
    "content": "﻿//          Copyright Tao Klerks, 2010-2012, tao@klerks.biz         \n//          Licensed under the modified BSD license.\n\n\nusing System;\nusing System.IO;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace FastColoredTextBoxNS\n{\n    public static class EncodingDetector\n    {\n        const long\n            _defaultHeuristicSampleSize =\n                0x10000; //completely arbitrary - inappropriate for high numbers of files / high speed requirements\n\n        public static Encoding DetectTextFileEncoding(string InputFilename)\n        {\n            using (FileStream textfileStream = File.OpenRead(InputFilename))\n            {\n                return DetectTextFileEncoding(textfileStream, _defaultHeuristicSampleSize);\n            }\n        }\n\n        public static Encoding DetectTextFileEncoding(FileStream InputFileStream, long HeuristicSampleSize)\n        {\n            bool uselessBool = false;\n            return DetectTextFileEncoding(InputFileStream, _defaultHeuristicSampleSize, out uselessBool);\n        }\n\n        public static Encoding DetectTextFileEncoding(FileStream InputFileStream, long HeuristicSampleSize,\n            out bool HasBOM)\n        {\n            Encoding encodingFound = null;\n\n            long originalPos = InputFileStream.Position;\n\n            InputFileStream.Position = 0;\n\n\n            //First read only what we need for BOM detection\n            byte[] bomBytes = new byte[InputFileStream.Length > 4 ? 4 : InputFileStream.Length];\n            InputFileStream.Read(bomBytes, 0, bomBytes.Length);\n\n            encodingFound = DetectBOMBytes(bomBytes);\n\n            if (encodingFound != null)\n            {\n                InputFileStream.Position = originalPos;\n                HasBOM = true;\n                return encodingFound;\n            }\n\n\n            //BOM Detection failed, going for heuristics now.\n            //  create sample byte array and populate it\n            byte[] sampleBytes = new byte[HeuristicSampleSize > InputFileStream.Length\n                ? InputFileStream.Length\n                : HeuristicSampleSize];\n            Array.Copy(bomBytes, sampleBytes, bomBytes.Length);\n            if (InputFileStream.Length > bomBytes.Length)\n                InputFileStream.Read(sampleBytes, bomBytes.Length, sampleBytes.Length - bomBytes.Length);\n            InputFileStream.Position = originalPos;\n\n            //test byte array content\n            encodingFound = DetectUnicodeInByteSampleByHeuristics(sampleBytes);\n\n            HasBOM = false;\n            return encodingFound;\n        }\n\n        public static Encoding DetectBOMBytes(byte[] BOMBytes)\n        {\n            if (BOMBytes.Length < 2)\n                return null;\n\n            if (BOMBytes[0] == 0xff\n                && BOMBytes[1] == 0xfe\n                && (BOMBytes.Length < 4\n                    || BOMBytes[2] != 0\n                    || BOMBytes[3] != 0\n                )\n            )\n                return Encoding.Unicode;\n\n            if (BOMBytes[0] == 0xfe\n                && BOMBytes[1] == 0xff\n            )\n                return Encoding.BigEndianUnicode;\n\n            if (BOMBytes.Length < 3)\n                return null;\n\n            if (BOMBytes[0] == 0xef && BOMBytes[1] == 0xbb && BOMBytes[2] == 0xbf)\n                return Encoding.UTF8;\n\n            if (BOMBytes[0] == 0x2b && BOMBytes[1] == 0x2f && BOMBytes[2] == 0x76)\n                return Encoding.UTF7;\n\n            if (BOMBytes.Length < 4)\n                return null;\n\n            if (BOMBytes[0] == 0xff && BOMBytes[1] == 0xfe && BOMBytes[2] == 0 && BOMBytes[3] == 0)\n                return Encoding.UTF32;\n\n            if (BOMBytes[0] == 0 && BOMBytes[1] == 0 && BOMBytes[2] == 0xfe && BOMBytes[3] == 0xff)\n                return Encoding.GetEncoding(12001);\n\n            return null;\n        }\n\n        public static Encoding DetectUnicodeInByteSampleByHeuristics(byte[] SampleBytes)\n        {\n            long oddBinaryNullsInSample = 0;\n            long evenBinaryNullsInSample = 0;\n            long suspiciousUTF8SequenceCount = 0;\n            long suspiciousUTF8BytesTotal = 0;\n            long likelyUSASCIIBytesInSample = 0;\n\n            //Cycle through, keeping count of binary null positions, possible UTF-8 \n            //  sequences from upper ranges of Windows-1252, and probable US-ASCII \n            //  character counts.\n\n            long currentPos = 0;\n            int skipUTF8Bytes = 0;\n\n            while (currentPos < SampleBytes.Length)\n            {\n                //binary null distribution\n                if (SampleBytes[currentPos] == 0)\n                {\n                    if (currentPos % 2 == 0)\n                        evenBinaryNullsInSample++;\n                    else\n                        oddBinaryNullsInSample++;\n                }\n\n                //likely US-ASCII characters\n                if (IsCommonUSASCIIByte(SampleBytes[currentPos]))\n                    likelyUSASCIIBytesInSample++;\n\n                //suspicious sequences (look like UTF-8)\n                if (skipUTF8Bytes == 0)\n                {\n                    int lengthFound = DetectSuspiciousUTF8SequenceLength(SampleBytes, currentPos);\n\n                    if (lengthFound > 0)\n                    {\n                        suspiciousUTF8SequenceCount++;\n                        suspiciousUTF8BytesTotal += lengthFound;\n                        skipUTF8Bytes = lengthFound - 1;\n                    }\n                }\n                else\n                {\n                    skipUTF8Bytes--;\n                }\n\n                currentPos++;\n            }\n\n            //1: UTF-16 LE - in english / european environments, this is usually characterized by a \n            //  high proportion of odd binary nulls (starting at 0), with (as this is text) a low \n            //  proportion of even binary nulls.\n            //  The thresholds here used (less than 20% nulls where you expect non-nulls, and more than\n            //  60% nulls where you do expect nulls) are completely arbitrary.\n\n            if (((evenBinaryNullsInSample * 2.0) / SampleBytes.Length) < 0.2\n                && ((oddBinaryNullsInSample * 2.0) / SampleBytes.Length) > 0.6\n            )\n                return Encoding.Unicode;\n\n\n            //2: UTF-16 BE - in english / european environments, this is usually characterized by a \n            //  high proportion of even binary nulls (starting at 0), with (as this is text) a low \n            //  proportion of odd binary nulls.\n            //  The thresholds here used (less than 20% nulls where you expect non-nulls, and more than\n            //  60% nulls where you do expect nulls) are completely arbitrary.\n\n            if (((oddBinaryNullsInSample * 2.0) / SampleBytes.Length) < 0.2\n                && ((evenBinaryNullsInSample * 2.0) / SampleBytes.Length) > 0.6\n            )\n                return Encoding.BigEndianUnicode;\n\n\n            //3: UTF-8 - Martin Dürst outlines a method for detecting whether something CAN be UTF-8 content \n            //  using regexp, in his w3c.org unicode FAQ entry: \n            //  http://www.w3.org/International/questions/qa-forms-utf-8\n            //  adapted here for C#.\n            string potentiallyMangledString = Encoding.ASCII.GetString(SampleBytes);\n            Regex UTF8Validator = new Regex(@\"\\A(\"\n                                            + @\"[\\x09\\x0A\\x0D\\x20-\\x7E]\"\n                                            + @\"|[\\xC2-\\xDF][\\x80-\\xBF]\"\n                                            + @\"|\\xE0[\\xA0-\\xBF][\\x80-\\xBF]\"\n                                            + @\"|[\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2}\"\n                                            + @\"|\\xED[\\x80-\\x9F][\\x80-\\xBF]\"\n                                            + @\"|\\xF0[\\x90-\\xBF][\\x80-\\xBF]{2}\"\n                                            + @\"|[\\xF1-\\xF3][\\x80-\\xBF]{3}\"\n                                            + @\"|\\xF4[\\x80-\\x8F][\\x80-\\xBF]{2}\"\n                                            + @\")*\\z\");\n            if (UTF8Validator.IsMatch(potentiallyMangledString))\n            {\n                //Unfortunately, just the fact that it CAN be UTF-8 doesn't tell you much about probabilities.\n                //If all the characters are in the 0-127 range, no harm done, most western charsets are same as UTF-8 in these ranges.\n                //If some of the characters were in the upper range (western accented characters), however, they would likely be mangled to 2-byte by the UTF-8 encoding process.\n                // So, we need to play stats.\n\n                // The \"Random\" likelihood of any pair of randomly generated characters being one \n                //   of these \"suspicious\" character sequences is:\n                //     128 / (256 * 256) = 0.2%.\n                //\n                // In western text data, that is SIGNIFICANTLY reduced - most text data stays in the <127 \n                //   character range, so we assume that more than 1 in 500,000 of these character \n                //   sequences indicates UTF-8. The number 500,000 is completely arbitrary - so sue me.\n                //\n                // We can only assume these character sequences will be rare if we ALSO assume that this\n                //   IS in fact western text - in which case the bulk of the UTF-8 encoded data (that is \n                //   not already suspicious sequences) should be plain US-ASCII bytes. This, I \n                //   arbitrarily decided, should be 80% (a random distribution, eg binary data, would yield \n                //   approx 40%, so the chances of hitting this threshold by accident in random data are \n                //   VERY low). \n\n                if ((suspiciousUTF8SequenceCount * 500000.0 / SampleBytes.Length >= 1) //suspicious sequences\n                    && (\n                        //all suspicious, so cannot evaluate proportion of US-Ascii\n                        SampleBytes.Length - suspiciousUTF8BytesTotal == 0\n                        ||\n                        likelyUSASCIIBytesInSample * 1.0 / (SampleBytes.Length - suspiciousUTF8BytesTotal) >= 0.8\n                    )\n                )\n                    return Encoding.UTF8;\n            }\n\n            return null;\n        }\n\n        private static bool IsCommonUSASCIIByte(byte testByte)\n        {\n            if (testByte == 0x0A //lf\n                || testByte == 0x0D //cr\n                || testByte == 0x09 //tab\n                || (testByte >= 0x20 && testByte <= 0x2F) //common punctuation\n                || (testByte >= 0x30 && testByte <= 0x39) //digits\n                || (testByte >= 0x3A && testByte <= 0x40) //common punctuation\n                || (testByte >= 0x41 && testByte <= 0x5A) //capital letters\n                || (testByte >= 0x5B && testByte <= 0x60) //common punctuation\n                || (testByte >= 0x61 && testByte <= 0x7A) //lowercase letters\n                || (testByte >= 0x7B && testByte <= 0x7E) //common punctuation\n            )\n                return true;\n            else\n                return false;\n        }\n\n        private static int DetectSuspiciousUTF8SequenceLength(byte[] SampleBytes, long currentPos)\n        {\n            int lengthFound = 0;\n\n            if (SampleBytes.Length >= currentPos + 1\n                && SampleBytes[currentPos] == 0xC2\n            )\n            {\n                if (SampleBytes[currentPos + 1] == 0x81\n                    || SampleBytes[currentPos + 1] == 0x8D\n                    || SampleBytes[currentPos + 1] == 0x8F\n                )\n                    lengthFound = 2;\n                else if (SampleBytes[currentPos + 1] == 0x90\n                         || SampleBytes[currentPos + 1] == 0x9D\n                )\n                    lengthFound = 2;\n                else if (SampleBytes[currentPos + 1] >= 0xA0\n                         && SampleBytes[currentPos + 1] <= 0xBF\n                )\n                    lengthFound = 2;\n            }\n            else if (SampleBytes.Length >= currentPos + 1\n                     && SampleBytes[currentPos] == 0xC3\n            )\n            {\n                if (SampleBytes[currentPos + 1] >= 0x80\n                    && SampleBytes[currentPos + 1] <= 0xBF\n                )\n                    lengthFound = 2;\n            }\n            else if (SampleBytes.Length >= currentPos + 1\n                     && SampleBytes[currentPos] == 0xC5\n            )\n            {\n                if (SampleBytes[currentPos + 1] == 0x92\n                    || SampleBytes[currentPos + 1] == 0x93\n                )\n                    lengthFound = 2;\n                else if (SampleBytes[currentPos + 1] == 0xA0\n                         || SampleBytes[currentPos + 1] == 0xA1\n                )\n                    lengthFound = 2;\n                else if (SampleBytes[currentPos + 1] == 0xB8\n                         || SampleBytes[currentPos + 1] == 0xBD\n                         || SampleBytes[currentPos + 1] == 0xBE\n                )\n                    lengthFound = 2;\n            }\n            else if (SampleBytes.Length >= currentPos + 1\n                     && SampleBytes[currentPos] == 0xC6\n            )\n            {\n                if (SampleBytes[currentPos + 1] == 0x92)\n                    lengthFound = 2;\n            }\n            else if (SampleBytes.Length >= currentPos + 1\n                     && SampleBytes[currentPos] == 0xCB\n            )\n            {\n                if (SampleBytes[currentPos + 1] == 0x86\n                    || SampleBytes[currentPos + 1] == 0x9C\n                )\n                    lengthFound = 2;\n            }\n            else if (SampleBytes.Length >= currentPos + 2\n                     && SampleBytes[currentPos] == 0xE2\n            )\n            {\n                if (SampleBytes[currentPos + 1] == 0x80)\n                {\n                    if (SampleBytes[currentPos + 2] == 0x93\n                        || SampleBytes[currentPos + 2] == 0x94\n                    )\n                        lengthFound = 3;\n                    if (SampleBytes[currentPos + 2] == 0x98\n                        || SampleBytes[currentPos + 2] == 0x99\n                        || SampleBytes[currentPos + 2] == 0x9A\n                    )\n                        lengthFound = 3;\n                    if (SampleBytes[currentPos + 2] == 0x9C\n                        || SampleBytes[currentPos + 2] == 0x9D\n                        || SampleBytes[currentPos + 2] == 0x9E\n                    )\n                        lengthFound = 3;\n                    if (SampleBytes[currentPos + 2] == 0xA0\n                        || SampleBytes[currentPos + 2] == 0xA1\n                        || SampleBytes[currentPos + 2] == 0xA2\n                    )\n                        lengthFound = 3;\n                    if (SampleBytes[currentPos + 2] == 0xA6)\n                        lengthFound = 3;\n                    if (SampleBytes[currentPos + 2] == 0xB0)\n                        lengthFound = 3;\n                    if (SampleBytes[currentPos + 2] == 0xB9\n                        || SampleBytes[currentPos + 2] == 0xBA\n                    )\n                        lengthFound = 3;\n                }\n                else if (SampleBytes[currentPos + 1] == 0x82\n                         && SampleBytes[currentPos + 2] == 0xAC\n                )\n                    lengthFound = 3;\n                else if (SampleBytes[currentPos + 1] == 0x84\n                         && SampleBytes[currentPos + 2] == 0xA2\n                )\n                    lengthFound = 3;\n            }\n\n            return lengthFound;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/ExportToHTML.cs",
    "content": "﻿using System.Text;\nusing System.Drawing;\nusing System.Collections.Generic;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Exports colored text as HTML\n    /// </summary>\n    /// <remarks>At this time only TextStyle renderer is supported. Other styles is not exported.</remarks>\n    public class ExportToHTML\n    {\n        public string LineNumbersCSS =\n            \"<style type=\\\"text/css\\\"> .lineNumber{font-family : monospace; font-size : small; font-style : normal; font-weight : normal; color : Teal; background-color : ThreedFace;} </style>\";\n\n        /// <summary>\n        /// Use nbsp; instead space\n        /// </summary>\n        public bool UseNbsp { get; set; }\n\n        /// <summary>\n        /// Use nbsp; instead space in beginning of line\n        /// </summary>\n        public bool UseForwardNbsp { get; set; }\n\n        /// <summary>\n        /// Use original font\n        /// </summary>\n        public bool UseOriginalFont { get; set; }\n\n        /// <summary>\n        /// Use style tag instead style attribute\n        /// </summary>\n        public bool UseStyleTag { get; set; }\n\n        /// <summary>\n        /// Use 'br' tag instead of '\\n'\n        /// </summary>\n        public bool UseBr { get; set; }\n\n        /// <summary>\n        /// Includes line numbers\n        /// </summary>\n        public bool IncludeLineNumbers { get; set; }\n\n        FastColoredTextBox tb;\n\n        public ExportToHTML()\n        {\n            UseNbsp = true;\n            UseOriginalFont = true;\n            UseStyleTag = true;\n            UseBr = true;\n        }\n\n        public string GetHtml(FastColoredTextBox tb)\n        {\n            this.tb = tb;\n            Range sel = new Range(tb);\n            sel.SelectAll();\n            return GetHtml(sel);\n        }\n\n        public string GetHtml(Range r)\n        {\n            this.tb = r.tb;\n            Dictionary<StyleIndex, object> styles = new Dictionary<StyleIndex, object>();\n            StringBuilder sb = new StringBuilder();\n            StringBuilder tempSB = new StringBuilder();\n            StyleIndex currentStyleId = StyleIndex.None;\n            r.Normalize();\n            int currentLine = r.Start.iLine;\n            styles[currentStyleId] = null;\n            //\n            if (UseOriginalFont)\n                sb.AppendFormat(\"<font style=\\\"font-family: {0}, monospace; font-size: {1}pt; line-height: {2}px;\\\">\",\n                    r.tb.Font.Name, r.tb.Font.SizeInPoints, r.tb.CharHeight);\n\n            //\n            if (IncludeLineNumbers)\n                tempSB.AppendFormat(\"<span class=lineNumber>{0}</span>  \", currentLine + 1);\n            //\n            bool hasNonSpace = false;\n            foreach (Place p in r)\n            {\n                Char c = r.tb[p.iLine][p.iChar];\n                if (c.style != currentStyleId)\n                {\n                    Flush(sb, tempSB, currentStyleId);\n                    currentStyleId = c.style;\n                    styles[currentStyleId] = null;\n                }\n\n                if (p.iLine != currentLine)\n                {\n                    for (int i = currentLine; i < p.iLine; i++)\n                    {\n                        tempSB.Append(UseBr ? \"<br>\" : \"\\r\\n\");\n                        if (IncludeLineNumbers)\n                            tempSB.AppendFormat(\"<span class=lineNumber>{0}</span>  \", i + 2);\n                    }\n\n                    currentLine = p.iLine;\n                    hasNonSpace = false;\n                }\n\n                switch (c.c)\n                {\n                    case ' ':\n                        if ((hasNonSpace || !UseForwardNbsp) && !UseNbsp)\n                            goto default;\n\n                        tempSB.Append(\"&nbsp;\");\n                        break;\n                    case '<':\n                        tempSB.Append(\"&lt;\");\n                        break;\n                    case '>':\n                        tempSB.Append(\"&gt;\");\n                        break;\n                    case '&':\n                        tempSB.Append(\"&amp;\");\n                        break;\n                    default:\n                        hasNonSpace = true;\n                        tempSB.Append(c.c);\n                        break;\n                }\n            }\n\n            Flush(sb, tempSB, currentStyleId);\n\n            if (UseOriginalFont)\n                sb.Append(\"</font>\");\n\n            //build styles\n            if (UseStyleTag)\n            {\n                tempSB.Length = 0;\n                tempSB.Append(\"<style type=\\\"text/css\\\">\");\n                foreach (var styleId in styles.Keys)\n                    tempSB.AppendFormat(\".fctb{0}{{ {1} }}\\r\\n\", GetStyleName(styleId), GetCss(styleId));\n                tempSB.Append(\"</style>\");\n\n                sb.Insert(0, tempSB.ToString());\n            }\n\n            if (IncludeLineNumbers)\n                sb.Insert(0, LineNumbersCSS);\n\n            return sb.ToString();\n        }\n\n        private string GetCss(StyleIndex styleIndex)\n        {\n            List<Style> styles = new List<Style>();\n            //find text renderer\n            TextStyle textStyle = null;\n            int mask = 1;\n            bool hasTextStyle = false;\n            for (int i = 0; i < tb.Styles.Length; i++)\n            {\n                if (tb.Styles[i] != null && ((int) styleIndex & mask) != 0)\n                    if (tb.Styles[i].IsExportable)\n                    {\n                        var style = tb.Styles[i];\n                        styles.Add(style);\n\n                        bool isTextStyle = style is TextStyle;\n                        if (isTextStyle)\n                            if (!hasTextStyle || tb.AllowSeveralTextStyleDrawing)\n                            {\n                                hasTextStyle = true;\n                                textStyle = style as TextStyle;\n                            }\n                    }\n\n                mask = mask << 1;\n            }\n\n            //add TextStyle css\n            string result = \"\";\n\n            if (!hasTextStyle)\n            {\n                //draw by default renderer\n                result = tb.DefaultStyle.GetCSS();\n            }\n            else\n            {\n                result = textStyle.GetCSS();\n            }\n\n            //add no TextStyle css\n            foreach (var style in styles)\n//            if (style != textStyle)\n                if (!(style is TextStyle))\n                    result += style.GetCSS();\n\n            return result;\n        }\n\n        public static string GetColorAsString(Color color)\n        {\n            if (color == Color.Transparent)\n                return \"\";\n            return string.Format(\"#{0:x2}{1:x2}{2:x2}\", color.R, color.G, color.B);\n        }\n\n        string GetStyleName(StyleIndex styleIndex)\n        {\n            return styleIndex.ToString().Replace(\" \", \"\").Replace(\",\", \"\");\n        }\n\n        private void Flush(StringBuilder sb, StringBuilder tempSB, StyleIndex currentStyle)\n        {\n            //find textRenderer\n            if (tempSB.Length == 0)\n                return;\n            if (UseStyleTag)\n                sb.AppendFormat(\"<font class=fctb{0}>{1}</font>\", GetStyleName(currentStyle), tempSB.ToString());\n            else\n            {\n                string css = GetCss(currentStyle);\n                if (css != \"\")\n                    sb.AppendFormat(\"<font style=\\\"{0}\\\">\", css);\n                sb.Append(tempSB.ToString());\n                if (css != \"\")\n                    sb.Append(\"</font>\");\n            }\n\n            tempSB.Length = 0;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/ExportToRTF.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Text;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Exports colored text as RTF\n    /// </summary>\n    /// <remarks>At this time only TextStyle renderer is supported. Other styles are not exported.</remarks>\n    public class ExportToRTF\n    {\n        /// <summary>\n        /// Includes line numbers\n        /// </summary>\n        public bool IncludeLineNumbers { get; set; }\n\n        /// <summary>\n        /// Use original font\n        /// </summary>\n        public bool UseOriginalFont { get; set; }\n\n        FastColoredTextBox tb;\n        Dictionary<Color, int> colorTable = new Dictionary<Color, int>();\n\n        public ExportToRTF()\n        {\n            UseOriginalFont = true;\n        }\n\n        public string GetRtf(FastColoredTextBox tb)\n        {\n            this.tb = tb;\n            Range sel = new Range(tb);\n            sel.SelectAll();\n            return GetRtf(sel);\n        }\n\n        public string GetRtf(Range r)\n        {\n            this.tb = r.tb;\n            var styles = new Dictionary<StyleIndex, object>();\n            var sb = new StringBuilder();\n            var tempSB = new StringBuilder();\n            var currentStyleId = StyleIndex.None;\n            r.Normalize();\n            int currentLine = r.Start.iLine;\n            styles[currentStyleId] = null;\n            colorTable.Clear();\n            //\n            var lineNumberColor = GetColorTableNumber(r.tb.LineNumberColor);\n\n            if (IncludeLineNumbers)\n                tempSB.AppendFormat(@\"{{\\cf{1} {0}}}\\tab\", currentLine + 1, lineNumberColor);\n            //\n            foreach (Place p in r)\n            {\n                Char c = r.tb[p.iLine][p.iChar];\n                if (c.style != currentStyleId)\n                {\n                    Flush(sb, tempSB, currentStyleId);\n                    currentStyleId = c.style;\n                    styles[currentStyleId] = null;\n                }\n\n                if (p.iLine != currentLine)\n                {\n                    for (int i = currentLine; i < p.iLine; i++)\n                    {\n                        tempSB.AppendLine(@\"\\line\");\n                        if (IncludeLineNumbers)\n                            tempSB.AppendFormat(@\"{{\\cf{1} {0}}}\\tab\", i + 2, lineNumberColor);\n                    }\n\n                    currentLine = p.iLine;\n                }\n\n                switch (c.c)\n                {\n                    case '\\\\':\n                        tempSB.Append(@\"\\\\\");\n                        break;\n                    case '{':\n                        tempSB.Append(@\"\\{\");\n                        break;\n                    case '}':\n                        tempSB.Append(@\"\\}\");\n                        break;\n                    default:\n                        var ch = c.c;\n                        var code = (int) ch;\n                        if (code < 128)\n                            tempSB.Append(c.c);\n                        else\n                            tempSB.AppendFormat(@\"{{\\u{0}}}\", code);\n                        break;\n                }\n            }\n\n            Flush(sb, tempSB, currentStyleId);\n\n            //build color table\n            var list = new SortedList<int, Color>();\n            foreach (var pair in colorTable)\n                list.Add(pair.Value, pair.Key);\n\n            tempSB.Length = 0;\n            tempSB.AppendFormat(@\"{{\\colortbl;\");\n\n            foreach (var pair in list)\n                tempSB.Append(GetColorAsString(pair.Value) + \";\");\n            tempSB.AppendLine(\"}\");\n\n            //\n            if (UseOriginalFont)\n            {\n                sb.Insert(0, string.Format(@\"{{\\fonttbl{{\\f0\\fmodern {0};}}}}{{\\fs{1} \",\n                    tb.Font.Name, (int) (2 * tb.Font.SizeInPoints), tb.CharHeight));\n                sb.AppendLine(@\"}\");\n            }\n\n            sb.Insert(0, tempSB.ToString());\n\n            sb.Insert(0, @\"{\\rtf1\\ud\\deff0\");\n            sb.AppendLine(@\"}\");\n\n            return sb.ToString();\n        }\n\n        private RTFStyleDescriptor GetRtfDescriptor(StyleIndex styleIndex)\n        {\n            List<Style> styles = new List<Style>();\n            //find text renderer\n            TextStyle textStyle = null;\n            int mask = 1;\n            bool hasTextStyle = false;\n            for (int i = 0; i < tb.Styles.Length; i++)\n            {\n                if (tb.Styles[i] != null && ((int) styleIndex & mask) != 0)\n                    if (tb.Styles[i].IsExportable)\n                    {\n                        var style = tb.Styles[i];\n                        styles.Add(style);\n\n                        bool isTextStyle = style is TextStyle;\n                        if (isTextStyle)\n                            if (!hasTextStyle || tb.AllowSeveralTextStyleDrawing)\n                            {\n                                hasTextStyle = true;\n                                textStyle = style as TextStyle;\n                            }\n                    }\n\n                mask = mask << 1;\n            }\n\n            //add TextStyle css\n            RTFStyleDescriptor result = null;\n\n            if (!hasTextStyle)\n            {\n                //draw by default renderer\n                result = tb.DefaultStyle.GetRTF();\n            }\n            else\n            {\n                result = textStyle.GetRTF();\n            }\n\n            return result;\n        }\n\n        public static string GetColorAsString(Color color)\n        {\n            if (color == Color.Transparent)\n                return \"\";\n            return string.Format(@\"\\red{0}\\green{1}\\blue{2}\", color.R, color.G, color.B);\n        }\n\n        private void Flush(StringBuilder sb, StringBuilder tempSB, StyleIndex currentStyle)\n        {\n            //find textRenderer\n            if (tempSB.Length == 0)\n                return;\n\n            var desc = GetRtfDescriptor(currentStyle);\n            var cf = GetColorTableNumber(desc.ForeColor);\n            var cb = GetColorTableNumber(desc.BackColor);\n            var tags = new StringBuilder();\n            if (cf >= 0)\n                tags.AppendFormat(@\"\\cf{0}\", cf);\n            if (cb >= 0)\n                tags.AppendFormat(@\"\\highlight{0}\", cb);\n            if (!string.IsNullOrEmpty(desc.AdditionalTags))\n                tags.Append(desc.AdditionalTags.Trim());\n\n            if (tags.Length > 0)\n                sb.AppendFormat(@\"{{{0} {1}}}\", tags, tempSB.ToString());\n            else\n                sb.Append(tempSB.ToString());\n            tempSB.Length = 0;\n        }\n\n        private int GetColorTableNumber(Color color)\n        {\n            if (color.A == 0)\n                return -1;\n\n            if (!colorTable.ContainsKey(color))\n                colorTable[color] = colorTable.Count + 1;\n\n            return colorTable[color];\n        }\n    }\n\n    public class RTFStyleDescriptor\n    {\n        public Color ForeColor { get; set; }\n        public Color BackColor { get; set; }\n        public string AdditionalTags { get; set; }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/FastColoredTextBox.cs",
    "content": "﻿//\n//  THIS CODE AND INFORMATION IS PROVIDED \"AS IS\" WITHOUT WARRANTY OF ANY\n//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR\n//  PURPOSE.\n//\n//  License: GNU Lesser General Public License (LGPLv3)\n//\n//  Email: pavel_torgashov@ukr.net\n//\n//  Copyright (C) Pavel Torgashov, 2011-2016. \n\n// #define debug\n\n\n// -------------------------------------------------------------------------------\n// By default the FastColoredTextbox supports no more 16 styles at the same time.\n// This restriction saves memory.\n// However, you can to compile FCTB with 32 styles supporting.\n// Uncomment following definition if you need 32 styles instead of 16:\n//\n// #define Styles32\n\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Drawing;\nusing System.Drawing.Design;\nusing System.Drawing.Drawing2D;\nusing System.IO;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading;\nusing System.Windows.Forms;\nusing System.Windows.Forms.Design;\nusing Microsoft.Win32;\nusing Timer = System.Windows.Forms.Timer;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Fast colored textbox\n    /// </summary>\n    public partial class FastColoredTextBox : UserControl, ISupportInitialize\n    {\n        internal const int minLeftIndent = 8;\n        private const int maxBracketSearchIterations = 1000;\n        private const int maxLinesForFolding = 3000;\n        private const int minLinesForAccuracy = 100000;\n        private const int WM_IME_SETCONTEXT = 0x0281;\n        private const int WM_HSCROLL = 0x114;\n        private const int WM_VSCROLL = 0x115;\n        private const int SB_ENDSCROLL = 0x8;\n\n        public readonly List<LineInfo> LineInfos = new List<LineInfo>();\n        private readonly Range selection;\n        private readonly Timer timer = new Timer();\n        private readonly Timer timer2 = new Timer();\n        private readonly Timer timer3 = new Timer();\n        private readonly List<VisualMarker> visibleMarkers = new List<VisualMarker>();\n        public int TextHeight;\n        public bool AllowInsertRemoveLines = true;\n        private Brush backBrush;\n        private BaseBookmarks bookmarks;\n        private bool caretVisible;\n        private Color changedLineColor;\n        private int charHeight;\n        private Color currentLineColor;\n        private Cursor defaultCursor;\n        private Range delayedTextChangedRange;\n        private string descriptionFile;\n        private int endFoldingLine = -1;\n        private Color foldingIndicatorColor;\n        protected Dictionary<int, int> foldingPairs = new Dictionary<int, int>();\n        private bool handledChar;\n        private bool highlightFoldingIndicator;\n        private Hints hints;\n        private Color indentBackColor;\n        private bool isChanged;\n        private bool isLineSelect;\n        private bool isReplaceMode;\n        private Language language;\n        private Keys lastModifiers;\n        private Point lastMouseCoord;\n        private DateTime lastNavigatedDateTime;\n        private Range leftBracketPosition;\n        private Range leftBracketPosition2;\n        private int leftPadding;\n        private int lineInterval;\n        private Color lineNumberColor;\n        private uint lineNumberStartValue;\n        private int lineSelectFrom;\n        private TextSource lines;\n        private IntPtr m_hImc;\n        private int maxLineLength;\n        private bool mouseIsDrag;\n        private bool mouseIsDragDrop;\n        private bool multiline;\n        protected bool needRecalc;\n        protected bool needRecalcWordWrap;\n        private Point needRecalcWordWrapInterval;\n        private bool needRecalcFoldingLines;\n        private bool needRiseSelectionChangedDelayed;\n        private bool needRiseTextChangedDelayed;\n        private bool needRiseVisibleRangeChangedDelayed;\n        private Color paddingBackColor;\n        private int preferredLineWidth;\n        private Range rightBracketPosition;\n        private Range rightBracketPosition2;\n        private bool scrollBars;\n        private Color selectionColor;\n        private Color serviceLinesColor;\n        private bool showFoldingLines;\n        private bool showLineNumbers;\n        private FastColoredTextBox sourceTextBox;\n        private int startFoldingLine = -1;\n        private int updating;\n        private Range updatingRange;\n        private Range visibleRange;\n        private bool wordWrap;\n        private WordWrapMode wordWrapMode = WordWrapMode.WordWrapControlWidth;\n        private int reservedCountOfLineNumberChars = 1;\n        private int zoom = 100;\n        private Size localAutoScrollMinSize;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        public FastColoredTextBox()\n        {\n            //register type provider\n            TypeDescriptionProvider prov = TypeDescriptor.GetProvider(GetType());\n            object theProvider =\n                prov.GetType().GetField(\"Provider\", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(prov);\n            if (theProvider.GetType() != typeof(FCTBDescriptionProvider))\n                TypeDescriptor.AddProvider(new FCTBDescriptionProvider(GetType()), GetType());\n            //drawing optimization\n            SetStyle(\n                ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer |\n                ControlStyles.ResizeRedraw, true);\n            //append monospace font\n            Font = new Font(FontFamily.GenericMonospace, 9.75f);\n            //create one line\n            InitTextSource(CreateTextSource());\n            if (lines.Count == 0)\n                lines.InsertLine(0, lines.CreateLine());\n            selection = new Range(this) {Start = new Place(0, 0)};\n            //default settings\n            Cursor = Cursors.IBeam;\n            BackColor = Color.White;\n            LineNumberColor = Color.Teal;\n            IndentBackColor = Color.WhiteSmoke;\n            ServiceLinesColor = Color.Silver;\n            FoldingIndicatorColor = Color.Green;\n            CurrentLineColor = Color.Transparent;\n            ChangedLineColor = Color.Transparent;\n            HighlightFoldingIndicator = true;\n            ShowLineNumbers = true;\n            TabLength = 4;\n            FoldedBlockStyle = new FoldedBlockStyle(Brushes.Gray, null, FontStyle.Regular);\n            SelectionColor = Color.Blue;\n            BracketsStyle = new MarkerStyle(new SolidBrush(Color.FromArgb(80, Color.Lime)));\n            BracketsStyle2 = new MarkerStyle(new SolidBrush(Color.FromArgb(60, Color.Red)));\n            DelayedEventsInterval = 100;\n            DelayedTextChangedInterval = 100;\n            AllowSeveralTextStyleDrawing = false;\n            LeftBracket = '\\x0';\n            RightBracket = '\\x0';\n            LeftBracket2 = '\\x0';\n            RightBracket2 = '\\x0';\n            SyntaxHighlighter = new SyntaxHighlighter(this);\n            language = Language.Razor;\n            PreferredLineWidth = 0;\n            needRecalc = true;\n            lastNavigatedDateTime = DateTime.Now;\n            AutoIndent = true;\n            AutoIndentExistingLines = true;\n            CommentPrefix = \"//\";\n            lineNumberStartValue = 1;\n            multiline = true;\n            scrollBars = true;\n            AcceptsTab = true;\n            AcceptsReturn = true;\n            caretVisible = true;\n            CaretColor = Color.Black;\n            WideCaret = false;\n            Paddings = new Padding(0, 0, 0, 0);\n            PaddingBackColor = Color.Transparent;\n            DisabledColor = Color.FromArgb(100, 180, 180, 180);\n            needRecalcFoldingLines = true;\n            AllowDrop = true;\n            FindEndOfFoldingBlockStrategy = FindEndOfFoldingBlockStrategy.Strategy1;\n            VirtualSpace = false;\n            bookmarks = new Bookmarks(this);\n            BookmarkColor = Color.PowderBlue;\n            ToolTip = new ToolTip();\n            timer3.Interval = 500;\n            hints = new Hints(this);\n            SelectionHighlightingForLineBreaksEnabled = true;\n            textAreaBorder = TextAreaBorderType.None;\n            textAreaBorderColor = Color.Black;\n            macrosManager = new MacrosManager(this);\n            HotkeysMapping = new HotkeysMapping();\n            HotkeysMapping.InitDefault();\n            WordWrapAutoIndent = true;\n            FoldedBlocks = new Dictionary<int, int>();\n            AutoCompleteBrackets = false;\n            AutoIndentCharsPatterns = @\"^\\s*[\\w\\.]+\\s*(?<range>=)\\s*(?<range>[^;]+);\";\n            AutoIndentChars = true;\n            CaretBlinking = true;\n            ServiceColors = new ServiceColors();\n            //\n            base.AutoScroll = true;\n            timer.Tick += timer_Tick;\n            timer2.Tick += timer2_Tick;\n            timer3.Tick += timer3_Tick;\n            middleClickScrollingTimer.Tick += middleClickScrollingTimer_Tick;\n        }\n\n        private char[] autoCompleteBracketsList = {'(', ')', '{', '}', '[', ']', '\"', '\"', '\\'', '\\''};\n\n        public char[] AutoCompleteBracketsList\n        {\n            get { return autoCompleteBracketsList; }\n            set { autoCompleteBracketsList = value; }\n        }\n\n        /// <summary>\n        /// AutoComplete brackets\n        /// </summary>\n        [DefaultValue(false)]\n        [Description(\"AutoComplete brackets.\")]\n        public bool AutoCompleteBrackets { get; set; }\n\n        /// <summary>\n        /// Colors of some service visual markers\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Colors of some service visual markers.\")]\n        [TypeConverter(typeof(ExpandableObjectConverter))]\n        public ServiceColors ServiceColors { get; set; }\n\n        /// <summary>\n        /// Contains UniqueId of start lines of folded blocks\n        /// </summary>\n        /// <remarks>This dictionary remembers folding state of blocks.\n        /// It is needed to restore child folding after user collapsed/expanded top-level folding block.</remarks>\n        [Browsable(false)]\n        public Dictionary<int, int> FoldedBlocks { get; private set; }\n\n        /// <summary>\n        /// Strategy of search of brackets to highlighting\n        /// </summary>\n        [DefaultValue(typeof(BracketsHighlightStrategy), \"Strategy1\")]\n        [Description(\"Strategy of search of brackets to highlighting.\")]\n        public BracketsHighlightStrategy BracketsHighlightStrategy { get; set; }\n\n        /// <summary>\n        /// Automatically shifts secondary wordwrap lines on the shift amount of the first line\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Automatically shifts secondary wordwrap lines on the shift amount of the first line.\")]\n        public bool WordWrapAutoIndent { get; set; }\n\n        /// <summary>\n        /// Indent of secondary wordwrap lines (in chars)\n        /// </summary>\n        [DefaultValue(0)]\n        [Description(\"Indent of secondary wordwrap lines (in chars).\")]\n        public int WordWrapIndent { get; set; }\n\n        MacrosManager macrosManager;\n\n        /// <summary>\n        /// MacrosManager records, stores and executes the macroses\n        /// </summary>\n        [Browsable(false)]\n        public MacrosManager MacrosManager\n        {\n            get { return macrosManager; }\n        }\n\n        /// <summary>\n        /// Allows drag and drop\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Allows drag and drop\")]\n        public override bool AllowDrop\n        {\n            get { return base.AllowDrop; }\n            set { base.AllowDrop = value; }\n        }\n\n        /// <summary>\n        /// Collection of Hints.\n        /// This is temporary buffer for currently displayed hints.\n        /// </summary>\n        /// <remarks>You can asynchronously add, remove and clear hints. Appropriate hints will be shown or hidden from the screen.</remarks>\n        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),\n         EditorBrowsable(EditorBrowsableState.Never)]\n        public Hints Hints\n        {\n            get { return hints; }\n            set { hints = value; }\n        }\n\n        /// <summary>\n        /// Delay (ms) of ToolTip\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(500)]\n        [Description(\"Delay(ms) of ToolTip.\")]\n        public int ToolTipDelay\n        {\n            get { return timer3.Interval; }\n            set { timer3.Interval = value; }\n        }\n\n        /// <summary>\n        /// ToolTip component\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"ToolTip component.\")]\n        public ToolTip ToolTip { get; set; }\n\n        /// <summary>\n        /// Color of bookmarks\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(typeof(Color), \"PowderBlue\")]\n        [Description(\"Color of bookmarks.\")]\n        public Color BookmarkColor { get; set; }\n\n        /// <summary>\n        /// Bookmarks\n        /// </summary>\n        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),\n         EditorBrowsable(EditorBrowsableState.Never)]\n        public BaseBookmarks Bookmarks\n        {\n            get { return bookmarks; }\n            set { bookmarks = value; }\n        }\n\n        /// <summary>\n        /// Enables virtual spaces\n        /// </summary>\n        [DefaultValue(false)]\n        [Description(\"Enables virtual spaces.\")]\n        public bool VirtualSpace { get; set; }\n\n        /// <summary>\n        /// Strategy of search of end of folding block\n        /// </summary>\n        [DefaultValue(FindEndOfFoldingBlockStrategy.Strategy1)]\n        [Description(\"Strategy of search of end of folding block.\")]\n        public FindEndOfFoldingBlockStrategy FindEndOfFoldingBlockStrategy { get; set; }\n\n        /// <summary>\n        /// Indicates if tab characters are accepted as input\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Indicates if tab characters are accepted as input.\")]\n        public bool AcceptsTab { get; set; }\n\n        /// <summary>\n        /// Indicates if return characters are accepted as input\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Indicates if return characters are accepted as input.\")]\n        public bool AcceptsReturn { get; set; }\n\n        /// <summary>\n        /// Shows or hides the caret\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Shows or hides the caret\")]\n        public bool CaretVisible\n        {\n            get { return caretVisible; }\n            set\n            {\n                caretVisible = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Enables caret blinking\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Enables caret blinking\")]\n        public bool CaretBlinking { get; set; }\n\n        /// <summary>\n        /// Draw caret when the control is not focused\n        /// </summary>\n        [DefaultValue(true)]\n        public bool ShowCaretWhenInactive { get; set; }\n\n\n        Color textAreaBorderColor;\n\n        /// <summary>\n        /// Color of border of text area\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Black\")]\n        [Description(\"Color of border of text area\")]\n        public Color TextAreaBorderColor\n        {\n            get { return textAreaBorderColor; }\n            set\n            {\n                textAreaBorderColor = value;\n                Invalidate();\n            }\n        }\n\n        TextAreaBorderType textAreaBorder;\n\n        /// <summary>\n        /// Type of border of text area\n        /// </summary>\n        [DefaultValue(typeof(TextAreaBorderType), \"None\")]\n        [Description(\"Type of border of text area\")]\n        public TextAreaBorderType TextAreaBorder\n        {\n            get { return textAreaBorder; }\n            set\n            {\n                textAreaBorder = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Background color for current line\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Transparent\")]\n        [Description(\"Background color for current line. Set to Color.Transparent to hide current line highlighting\")]\n        public Color CurrentLineColor\n        {\n            get { return currentLineColor; }\n            set\n            {\n                currentLineColor = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Background color for highlighting of changed lines\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Transparent\")]\n        [Description(\n            \"Background color for highlighting of changed lines. Set to Color.Transparent to hide changed line highlighting\")]\n        public Color ChangedLineColor\n        {\n            get { return changedLineColor; }\n            set\n            {\n                changedLineColor = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Fore color (default style color)\n        /// </summary>\n        public override Color ForeColor\n        {\n            get { return base.ForeColor; }\n            set\n            {\n                base.ForeColor = value;\n                lines.InitDefaultStyle();\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Height of char in pixels (includes LineInterval)\n        /// </summary>\n        [Browsable(false)]\n        public int CharHeight\n        {\n            get { return charHeight; }\n            set\n            {\n                charHeight = value;\n                NeedRecalc();\n                OnCharSizeChanged();\n            }\n        }\n\n        /// <summary>\n        /// Interval between lines (in pixels)\n        /// </summary>\n        [Description(\"Interval between lines in pixels\")]\n        [DefaultValue(0)]\n        public int LineInterval\n        {\n            get { return lineInterval; }\n            set\n            {\n                lineInterval = value;\n                SetFont(Font);\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Width of char in pixels\n        /// </summary>\n        [Browsable(false)]\n        public int CharWidth { get; set; }\n\n        /// <summary>\n        /// Spaces count for tab\n        /// </summary>\n        [DefaultValue(4)]\n        [Description(\"Spaces count for tab\")]\n        public int TabLength { get; set; }\n\n        /// <summary>\n        /// Text was changed\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public bool IsChanged\n        {\n            get { return isChanged; }\n            set\n            {\n                if (!value)\n                    //clear line's IsChanged property\n                    lines.ClearIsChanged();\n\n                isChanged = value;\n            }\n        }\n\n        /// <summary>\n        /// Text version\n        /// </summary>\n        /// <remarks>This counter is incremented each time changes the text</remarks>\n        [Browsable(false)]\n        public int TextVersion { get; private set; }\n\n        /// <summary>\n        /// Read only\n        /// </summary>\n        [DefaultValue(false)]\n        public bool ReadOnly { get; set; }\n\n        /// <summary>\n        /// Shows line numbers.\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Shows line numbers.\")]\n        public bool ShowLineNumbers\n        {\n            get { return showLineNumbers; }\n            set\n            {\n                showLineNumbers = value;\n                NeedRecalc();\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Shows vertical lines between folding start line and folding end line.\n        /// </summary>\n        [DefaultValue(false)]\n        [Description(\"Shows vertical lines between folding start line and folding end line.\")]\n        public bool ShowFoldingLines\n        {\n            get { return showFoldingLines; }\n            set\n            {\n                showFoldingLines = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Rectangle where located text\n        /// </summary>\n        [Browsable(false)]\n        public Rectangle TextAreaRect\n        {\n            get\n            {\n                int rightPaddingStartX = LeftIndent + maxLineLength * CharWidth + Paddings.Left + 1;\n                rightPaddingStartX = Math.Max(ClientSize.Width - Paddings.Right, rightPaddingStartX);\n                int bottomPaddingStartY = TextHeight + Paddings.Top;\n                bottomPaddingStartY = Math.Max(ClientSize.Height - Paddings.Bottom, bottomPaddingStartY);\n                var top = Math.Max(0, Paddings.Top - 1) - VerticalScroll.Value;\n                var left = LeftIndent - HorizontalScroll.Value - 2 + Math.Max(0, Paddings.Left - 1);\n                var rect = Rectangle.FromLTRB(left, top, rightPaddingStartX - HorizontalScroll.Value,\n                    bottomPaddingStartY - VerticalScroll.Value);\n                return rect;\n            }\n        }\n\n        /// <summary>\n        /// Color of line numbers.\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Teal\")]\n        [Description(\"Color of line numbers.\")]\n        public Color LineNumberColor\n        {\n            get { return lineNumberColor; }\n            set\n            {\n                lineNumberColor = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Start value of first line number.\n        /// </summary>\n        [DefaultValue(typeof(uint), \"1\")]\n        [Description(\"Start value of first line number.\")]\n        public uint LineNumberStartValue\n        {\n            get { return lineNumberStartValue; }\n            set\n            {\n                lineNumberStartValue = value;\n                needRecalc = true;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Background color of indent area\n        /// </summary>\n        [DefaultValue(typeof(Color), \"WhiteSmoke\")]\n        [Description(\"Background color of indent area\")]\n        public Color IndentBackColor\n        {\n            get { return indentBackColor; }\n            set\n            {\n                indentBackColor = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Background color of padding area\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Transparent\")]\n        [Description(\"Background color of padding area\")]\n        public Color PaddingBackColor\n        {\n            get { return paddingBackColor; }\n            set\n            {\n                paddingBackColor = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Color of disabled component\n        /// </summary>\n        [DefaultValue(typeof(Color), \"100;180;180;180\")]\n        [Description(\"Color of disabled component\")]\n        public Color DisabledColor { get; set; }\n\n        /// <summary>\n        /// Color of caret\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Black\")]\n        [Description(\"Color of caret.\")]\n        public Color CaretColor { get; set; }\n\n        /// <summary>\n        /// Wide caret\n        /// </summary>\n        [DefaultValue(false)]\n        [Description(\"Wide caret.\")]\n        public bool WideCaret { get; set; }\n\n        /// <summary>\n        /// Color of service lines (folding lines, borders of blocks etc.)\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Silver\")]\n        [Description(\"Color of service lines (folding lines, borders of blocks etc.)\")]\n        public Color ServiceLinesColor\n        {\n            get { return serviceLinesColor; }\n            set\n            {\n                serviceLinesColor = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Padings of text area\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Paddings of text area.\")]\n        public Padding Paddings { get; set; }\n\n        /// <summary>\n        /// --Do not use this property--\n        /// </summary>\n        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),\n         EditorBrowsable(EditorBrowsableState.Never)]\n        public new Padding Padding\n        {\n            get { throw new NotImplementedException(); }\n            set { throw new NotImplementedException(); }\n        }\n\n        //hide RTL\n        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),\n         EditorBrowsable(EditorBrowsableState.Never)]\n        public new bool RightToLeft\n        {\n            get { throw new NotImplementedException(); }\n            set { throw new NotImplementedException(); }\n        }\n\n        /// <summary>\n        /// Color of folding area indicator\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Green\")]\n        [Description(\"Color of folding area indicator.\")]\n        public Color FoldingIndicatorColor\n        {\n            get { return foldingIndicatorColor; }\n            set\n            {\n                foldingIndicatorColor = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Enables folding indicator (left vertical line between folding bounds)\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Enables folding indicator (left vertical line between folding bounds)\")]\n        public bool HighlightFoldingIndicator\n        {\n            get { return highlightFoldingIndicator; }\n            set\n            {\n                highlightFoldingIndicator = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Left distance to text beginning\n        /// </summary>\n        [Browsable(false)]\n        [Description(\"Left distance to text beginning.\")]\n        public int LeftIndent { get; private set; }\n\n        /// <summary>\n        /// Left padding in pixels\n        /// </summary>\n        [DefaultValue(0)]\n        [Description(\"Width of left service area (in pixels)\")]\n        public int LeftPadding\n        {\n            get { return leftPadding; }\n            set\n            {\n                leftPadding = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// This property draws vertical line after defined char position.\n        /// Set to 0 for disable drawing of vertical line.\n        /// </summary>\n        [DefaultValue(0)]\n        [Description(\n            \"This property draws vertical line after defined char position. Set to 0 for disable drawing of vertical line.\")]\n        public int PreferredLineWidth\n        {\n            get { return preferredLineWidth; }\n            set\n            {\n                preferredLineWidth = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Styles\n        /// </summary>\n        [Browsable(false)]\n        public Style[] Styles\n        {\n            get { return lines.Styles; }\n        }\n\n        /// <summary>\n        /// Hotkeys. Do not use this property in your code, use HotkeysMapping property.\n        /// </summary>\n        [Description(\"Here you can change hotkeys for FastColoredTextBox.\")]\n        [Editor(typeof(HotkeysEditor), typeof(UITypeEditor))]\n        [DefaultValue(\n            \"Tab=IndentIncrease, Escape=ClearHints, PgUp=GoPageUp, PgDn=GoPageDown, End=GoEnd, Home=GoHome, Left=GoLeft, Up=GoUp, Right=GoRight, Down=GoDown, Ins=ReplaceMode, Del=DeleteCharRight, F3=FindNext, Shift+Tab=IndentDecrease, Shift+PgUp=GoPageUpWithSelection, Shift+PgDn=GoPageDownWithSelection, Shift+End=GoEndWithSelection, Shift+Home=GoHomeWithSelection, Shift+Left=GoLeftWithSelection, Shift+Up=GoUpWithSelection, Shift+Right=GoRightWithSelection, Shift+Down=GoDownWithSelection, Shift+Ins=Paste, Shift+Del=Cut, Ctrl+Back=ClearWordLeft, Ctrl+Space=AutocompleteMenu, Ctrl+End=GoLastLine, Ctrl+Home=GoFirstLine, Ctrl+Left=GoWordLeft, Ctrl+Up=ScrollUp, Ctrl+Right=GoWordRight, Ctrl+Down=ScrollDown, Ctrl+Ins=Copy, Ctrl+Del=ClearWordRight, Ctrl+0=ZoomNormal, Ctrl+A=SelectAll, Ctrl+B=BookmarkLine, Ctrl+C=Copy, Ctrl+E=MacroExecute, Ctrl+F=FindDialog, Ctrl+G=GoToDialog, Ctrl+H=ReplaceDialog, Ctrl+I=AutoIndentChars, Ctrl+M=MacroRecord, Ctrl+N=GoNextBookmark, Ctrl+R=Redo, Ctrl+U=UpperCase, Ctrl+V=Paste, Ctrl+X=Cut, Ctrl+Z=Undo, Ctrl+Add=ZoomIn, Ctrl+Subtract=ZoomOut, Ctrl+OemMinus=NavigateBackward, Ctrl+Shift+End=GoLastLineWithSelection, Ctrl+Shift+Home=GoFirstLineWithSelection, Ctrl+Shift+Left=GoWordLeftWithSelection, Ctrl+Shift+Right=GoWordRightWithSelection, Ctrl+Shift+B=UnbookmarkLine, Ctrl+Shift+C=CommentSelected, Ctrl+Shift+N=GoPrevBookmark, Ctrl+Shift+U=LowerCase, Ctrl+Shift+OemMinus=NavigateForward, Alt+Back=Undo, Alt+Up=MoveSelectedLinesUp, Alt+Down=MoveSelectedLinesDown, Alt+F=FindChar, Alt+Shift+Left=GoLeft_ColumnSelectionMode, Alt+Shift+Up=GoUp_ColumnSelectionMode, Alt+Shift+Right=GoRight_ColumnSelectionMode, Alt+Shift+Down=GoDown_ColumnSelectionMode\")]\n        public string Hotkeys\n        {\n            get { return HotkeysMapping.ToString(); }\n            set { HotkeysMapping = HotkeysMapping.Parse(value); }\n        }\n\n        /// <summary>\n        /// Hotkeys mapping\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public HotkeysMapping HotkeysMapping { get; set; }\n\n        /// <summary>\n        /// Default text style\n        /// This style is using when no one other TextStyle is not defined in Char.style\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public TextStyle DefaultStyle\n        {\n            get { return lines.DefaultStyle; }\n            set { lines.DefaultStyle = value; }\n        }\n\n        /// <summary>\n        /// Style for rendering Selection area\n        /// </summary>\n        [Browsable(false)]\n        public SelectionStyle SelectionStyle { get; set; }\n\n        /// <summary>\n        /// Style for folded block rendering\n        /// </summary>\n        [Browsable(false)]\n        public TextStyle FoldedBlockStyle { get; set; }\n\n        /// <summary>\n        /// Style for brackets highlighting\n        /// </summary>\n        [Browsable(false)]\n        public MarkerStyle BracketsStyle { get; set; }\n\n        /// <summary>\n        /// Style for alternative brackets highlighting\n        /// </summary>\n        [Browsable(false)]\n        public MarkerStyle BracketsStyle2 { get; set; }\n\n        /// <summary>\n        /// Opening bracket for brackets highlighting.\n        /// Set to '\\x0' for disable brackets highlighting.\n        /// </summary>\n        [DefaultValue('\\x0')]\n        [Description(\"Opening bracket for brackets highlighting. Set to '\\\\x0' for disable brackets highlighting.\")]\n        public char LeftBracket { get; set; }\n\n        /// <summary>\n        /// Closing bracket for brackets highlighting.\n        /// Set to '\\x0' for disable brackets highlighting.\n        /// </summary>\n        [DefaultValue('\\x0')]\n        [Description(\"Closing bracket for brackets highlighting. Set to '\\\\x0' for disable brackets highlighting.\")]\n        public char RightBracket { get; set; }\n\n        /// <summary>\n        /// Alternative opening bracket for brackets highlighting.\n        /// Set to '\\x0' for disable brackets highlighting.\n        /// </summary>\n        [DefaultValue('\\x0')]\n        [Description(\n            \"Alternative opening bracket for brackets highlighting. Set to '\\\\x0' for disable brackets highlighting.\")]\n        public char LeftBracket2 { get; set; }\n\n        /// <summary>\n        /// Alternative closing bracket for brackets highlighting.\n        /// Set to '\\x0' for disable brackets highlighting.\n        /// </summary>\n        [DefaultValue('\\x0')]\n        [Description(\n            \"Alternative closing bracket for brackets highlighting. Set to '\\\\x0' for disable brackets highlighting.\")]\n        public char RightBracket2 { get; set; }\n\n        /// <summary>\n        /// Comment line prefix.\n        /// </summary>\n        [DefaultValue(\"//\")]\n        [Description(\"Comment line prefix.\")]\n        public string CommentPrefix { get; set; }\n\n        /// <summary>\n        /// This property specifies which part of the text will be highlighted as you type (by built-in highlighter).\n        /// </summary>\n        /// <remarks>When a user enters text, a component refreshes highlighting (because the text was changed).\n        /// This property specifies exactly which section of the text will be re-highlighted.\n        /// This can be useful to highlight multi-line comments, for example.</remarks>\n        [DefaultValue(typeof(HighlightingRangeType), \"ChangedRange\")]\n        [Description(\"This property specifies which part of the text will be highlighted as you type.\")]\n        public HighlightingRangeType HighlightingRangeType { get; set; }\n\n        /// <summary>\n        /// Is keyboard in replace mode (wide caret) ?\n        /// </summary>\n        [Browsable(false)]\n        public bool IsReplaceMode\n        {\n            get\n            {\n                return isReplaceMode &&\n                       Selection.IsEmpty &&\n                       (!Selection.ColumnSelectionMode) &&\n                       Selection.Start.iChar < lines[Selection.Start.iLine].Count;\n            }\n            set { isReplaceMode = value; }\n        }\n\n        /// <summary>\n        /// Allows text rendering several styles same time.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(false)]\n        [Description(\"Allows text rendering several styles same time.\")]\n        public bool AllowSeveralTextStyleDrawing { get; set; }\n\n        /// <summary>\n        /// Allows to record macros.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(true)]\n        [Description(\"Allows to record macros.\")]\n        public bool AllowMacroRecording\n        {\n            get { return macrosManager.AllowMacroRecordingByUser; }\n            set { macrosManager.AllowMacroRecordingByUser = value; }\n        }\n\n        /// <summary>\n        /// Allows AutoIndent. Inserts spaces before new line.\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Allows auto indent. Inserts spaces before line chars.\")]\n        public bool AutoIndent { get; set; }\n\n        /// <summary>\n        /// Does autoindenting in existing lines. It works only if AutoIndent is True.\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"Does autoindenting in existing lines. It works only if AutoIndent is True.\")]\n        public bool AutoIndentExistingLines { get; set; }\n\n        /// <summary>\n        /// Minimal delay(ms) for delayed events (except TextChangedDelayed).\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(100)]\n        [Description(\"Minimal delay(ms) for delayed events (except TextChangedDelayed).\")]\n        public int DelayedEventsInterval\n        {\n            get { return timer.Interval; }\n            set { timer.Interval = value; }\n        }\n\n        /// <summary>\n        /// Minimal delay(ms) for TextChangedDelayed event.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(100)]\n        [Description(\"Minimal delay(ms) for TextChangedDelayed event.\")]\n        public int DelayedTextChangedInterval\n        {\n            get { return timer2.Interval; }\n            set { timer2.Interval = value; }\n        }\n\n        /// <summary>\n        /// Language for highlighting by built-in highlighter.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(typeof(Language), \"Razor\")]\n        [Description(\"Language for highlighting by built-in highlighter.\")]\n        public Language Language\n        {\n            get { return language; }\n            set\n            {\n                language = value;\n                if (SyntaxHighlighter != null)\n                    SyntaxHighlighter.InitStyleSchema(language);\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Syntax Highlighter\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public SyntaxHighlighter SyntaxHighlighter { get; set; }\n\n        /// <summary>\n        /// XML file with description of syntax highlighting.\n        /// This property works only with Language == Language.Custom.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(null)]\n        [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]\n        [Description(\n            \"XML file with description of syntax highlighting. This property works only with Language == Language.Custom.\"\n        )]\n        public string DescriptionFile\n        {\n            get { return descriptionFile; }\n            set\n            {\n                descriptionFile = value;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Position of left highlighted bracket.\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public Range LeftBracketPosition\n        {\n            get { return leftBracketPosition; }\n        }\n\n        /// <summary>\n        /// Position of right highlighted bracket.\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public Range RightBracketPosition\n        {\n            get { return rightBracketPosition; }\n        }\n\n        /// <summary>\n        /// Position of left highlighted alternative bracket.\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public Range LeftBracketPosition2\n        {\n            get { return leftBracketPosition2; }\n        }\n\n        /// <summary>\n        /// Position of right highlighted alternative bracket.\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public Range RightBracketPosition2\n        {\n            get { return rightBracketPosition2; }\n        }\n\n        /// <summary>\n        /// Start line index of current highlighted folding area. Return -1 if start of area is not found.\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public int StartFoldingLine\n        {\n            get { return startFoldingLine; }\n        }\n\n        /// <summary>\n        /// End line index of current highlighted folding area. Return -1 if end of area is not found.\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public int EndFoldingLine\n        {\n            get { return endFoldingLine; }\n        }\n\n        /// <summary>\n        /// TextSource\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public TextSource TextSource\n        {\n            get { return lines; }\n            set { InitTextSource(value); }\n        }\n\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public bool HasSourceTextBox\n        {\n            get { return SourceTextBox != null; }\n        }\n\n        /// <summary>\n        /// The source of the text.\n        /// Allows to get text from other FastColoredTextBox.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(null)]\n        [Description(\"Allows to get text from other FastColoredTextBox.\")]\n        //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public FastColoredTextBox SourceTextBox\n        {\n            get { return sourceTextBox; }\n            set\n            {\n                if (value == sourceTextBox)\n                    return;\n\n                sourceTextBox = value;\n\n                if (sourceTextBox == null)\n                {\n                    InitTextSource(CreateTextSource());\n                    lines.InsertLine(0, TextSource.CreateLine());\n                    IsChanged = false;\n                }\n                else\n                {\n                    InitTextSource(SourceTextBox.TextSource);\n                    isChanged = false;\n                }\n\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Returns current visible range of text\n        /// </summary>\n        [Browsable(false)]\n        public Range VisibleRange\n        {\n            get\n            {\n                if (visibleRange != null)\n                    return visibleRange;\n                return GetRange(\n                    PointToPlace(new Point(LeftIndent, 0)),\n                    PointToPlace(new Point(ClientSize.Width, ClientSize.Height))\n                );\n            }\n        }\n\n        /// <summary>\n        /// Current selection range\n        /// </summary>\n        [Browsable(false)]\n        public Range Selection\n        {\n            get { return selection; }\n            set\n            {\n                if (value == selection)\n                    return;\n\n                selection.BeginUpdate();\n                selection.Start = value.Start;\n                selection.End = value.End;\n                selection.EndUpdate();\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Background color.\n        /// It is used if BackBrush is null.\n        /// </summary>\n        [DefaultValue(typeof(Color), \"White\")]\n        [Description(\"Background color.\")]\n        public override Color BackColor\n        {\n            get { return base.BackColor; }\n            set { base.BackColor = value; }\n        }\n\n        /// <summary>\n        /// Background brush.\n        /// If Null then BackColor is used.\n        /// </summary>\n        [Browsable(false)]\n        public Brush BackBrush\n        {\n            get { return backBrush; }\n            set\n            {\n                backBrush = value;\n                Invalidate();\n            }\n        }\n\n        [Browsable(true)]\n        [DefaultValue(true)]\n        [Description(\"Scollbars visibility.\")]\n        public bool ShowScrollBars\n        {\n            get { return scrollBars; }\n            set\n            {\n                if (value == scrollBars) return;\n                scrollBars = value;\n                needRecalc = true;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Multiline\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(true)]\n        [Description(\"Multiline mode.\")]\n        public bool Multiline\n        {\n            get { return multiline; }\n            set\n            {\n                if (multiline == value) return;\n                multiline = value;\n                needRecalc = true;\n                if (multiline)\n                {\n                    base.AutoScroll = true;\n                    ShowScrollBars = true;\n                }\n                else\n                {\n                    base.AutoScroll = false;\n                    ShowScrollBars = false;\n                    if (lines.Count > 1)\n                        lines.RemoveLine(1, lines.Count - 1);\n                    lines.Manager.ClearHistory();\n                }\n\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// WordWrap.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(false)]\n        [Description(\"WordWrap.\")]\n        public bool WordWrap\n        {\n            get { return wordWrap; }\n            set\n            {\n                if (wordWrap == value) return;\n                wordWrap = value;\n                if (wordWrap)\n                    Selection.ColumnSelectionMode = false;\n                NeedRecalc(false, true);\n                //RecalcWordWrap(0, LinesCount - 1);\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// WordWrap mode.\n        /// </summary>\n        [Browsable(true)]\n        [DefaultValue(typeof(WordWrapMode), \"WordWrapControlWidth\")]\n        [Description(\"WordWrap mode.\")]\n        public WordWrapMode WordWrapMode\n        {\n            get { return wordWrapMode; }\n            set\n            {\n                if (wordWrapMode == value) return;\n                wordWrapMode = value;\n                NeedRecalc(false, true);\n                //RecalcWordWrap(0, LinesCount - 1);\n                Invalidate();\n            }\n        }\n\n        private bool selectionHighlightingForLineBreaksEnabled;\n\n        /// <summary>\n        /// If <c>true</c> then line breaks included into the selection will be selected too.\n        /// Then line breaks will be shown as selected blank character.\n        /// </summary>\n        [DefaultValue(true)]\n        [Description(\"If enabled then line ends included into the selection will be selected too. \" +\n                     \"Then line ends will be shown as selected blank character.\")]\n        public bool SelectionHighlightingForLineBreaksEnabled\n        {\n            get { return selectionHighlightingForLineBreaksEnabled; }\n            set\n            {\n                selectionHighlightingForLineBreaksEnabled = value;\n                Invalidate();\n            }\n        }\n\n\n        [Browsable(false)] public FindForm findForm { get; private set; }\n\n        [Browsable(false)] public ReplaceForm replaceForm { get; private set; }\n\n        /// <summary>\n        /// Do not change this property\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public override bool AutoScroll\n        {\n            get { return base.AutoScroll; }\n            set { ; }\n        }\n\n        /// <summary>\n        /// Count of lines\n        /// </summary>\n        [Browsable(false)]\n        public int LinesCount\n        {\n            get { return lines.Count; }\n        }\n\n        /// <summary>\n        /// Gets or sets char and styleId for given place\n        /// This property does not fire OnTextChanged event\n        /// </summary>\n        public Char this[Place place]\n        {\n            get { return lines[place.iLine][place.iChar]; }\n            set { lines[place.iLine][place.iChar] = value; }\n        }\n\n        /// <summary>\n        /// Gets Line\n        /// </summary>\n        public Line this[int iLine]\n        {\n            get { return lines[iLine]; }\n        }\n\n        /// <summary>\n        /// Text of control\n        /// </summary>\n        [Browsable(true)]\n        [Localizable(true)]\n        [Editor(\n            \"System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\"\n            , typeof(UITypeEditor))]\n        [SettingsBindable(true)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]\n        [Description(\"Text of the control.\")]\n        [Bindable(true)]\n        public override string Text\n        {\n            get\n            {\n                if (LinesCount == 0)\n                    return \"\";\n                var sel = new Range(this);\n                sel.SelectAll();\n                return sel.Text;\n            }\n\n            set\n            {\n                if (value == Text && value != \"\")\n                    return;\n\n                SetAsCurrentTB();\n\n                Selection.ColumnSelectionMode = false;\n\n                Selection.BeginUpdate();\n                try\n                {\n                    Selection.SelectAll();\n                    InsertText(value);\n                    GoHome();\n                }\n                finally\n                {\n                    Selection.EndUpdate();\n                }\n            }\n        }\n\n        public int TextLength\n        {\n            get\n            {\n                if (LinesCount == 0)\n                    return 0;\n                var sel = new Range(this);\n                sel.SelectAll();\n                return sel.Length;\n            }\n        }\n\n        /// <summary>\n        /// Text lines\n        /// </summary>\n        [Browsable(false)]\n        public IList<string> Lines\n        {\n            get { return lines.GetLines(); }\n        }\n\n        /// <summary>\n        /// Gets colored text as HTML\n        /// </summary>\n        /// <remarks>For more flexibility you can use ExportToHTML class also</remarks>\n        [Browsable(false)]\n        public string Html\n        {\n            get\n            {\n                var exporter = new ExportToHTML();\n                exporter.UseNbsp = false;\n                exporter.UseStyleTag = false;\n                exporter.UseBr = false;\n                return \"<pre>\" + exporter.GetHtml(this) + \"</pre>\";\n            }\n        }\n\n        /// <summary>\n        /// Gets colored text as RTF\n        /// </summary>\n        /// <remarks>For more flexibility you can use ExportToRTF class also</remarks>\n        [Browsable(false)]\n        public string Rtf\n        {\n            get\n            {\n                var exporter = new ExportToRTF();\n                return exporter.GetRtf(this);\n            }\n        }\n\n        /// <summary>\n        /// Text of current selection\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public string SelectedText\n        {\n            get { return Selection.Text; }\n            set { InsertText(value); }\n        }\n\n        /// <summary>\n        /// Start position of selection\n        /// </summary>\n        [Browsable(false)]\n        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n        public int SelectionStart\n        {\n            get { return Math.Min(PlaceToPosition(Selection.Start), PlaceToPosition(Selection.End)); }\n            set { Selection.Start = PositionToPlace(value); }\n        }\n\n        /// <summary>\n        /// Length of selected text\n        /// </summary>\n        [Browsable(false)]\n        [DefaultValue(0)]\n        public int SelectionLength\n        {\n            get { return Selection.Length; }\n            set\n            {\n                if (value > 0)\n                    Selection.End = PositionToPlace(SelectionStart + value);\n            }\n        }\n\n        /// <summary>\n        /// Font\n        /// </summary>\n        /// <remarks>Use only monospaced font</remarks>\n        [DefaultValue(typeof(Font), \"Courier New, 9.75\")]\n        public override Font Font\n        {\n            get { return BaseFont; }\n            set\n            {\n                originalFont = (Font) value.Clone();\n                SetFont(value);\n            }\n        }\n\n\n        Font baseFont;\n\n        /// <summary>\n        /// Font\n        /// </summary>\n        /// <remarks>Use only monospaced font</remarks>\n        [DefaultValue(typeof(Font), \"Courier New, 9.75\")]\n        private Font BaseFont\n        {\n            get { return baseFont; }\n            set { baseFont = value; }\n        }\n\n        private void SetFont(Font newFont)\n        {\n            BaseFont = newFont;\n            //check monospace font\n            SizeF sizeM = GetCharSize(BaseFont, 'M');\n            SizeF sizeDot = GetCharSize(BaseFont, '.');\n            if (sizeM != sizeDot)\n                BaseFont = new Font(\"Courier New\", BaseFont.SizeInPoints, FontStyle.Regular, GraphicsUnit.Point);\n            //clac size\n            SizeF size = GetCharSize(BaseFont, 'M');\n            CharWidth = (int) Math.Round(size.Width * 1f /*0.85*/) - 1 /*0*/;\n            CharHeight = lineInterval + (int) Math.Round(size.Height * 1f /*0.9*/) - 1 /*0*/;\n            //\n            //if (wordWrap)\n            //    RecalcWordWrap(0, Lines.Count - 1);\n            NeedRecalc(false, wordWrap);\n            //\n            Invalidate();\n        }\n\n        public new Size AutoScrollMinSize\n        {\n            set\n            {\n                if (scrollBars)\n                {\n                    if (!base.AutoScroll)\n                        base.AutoScroll = true;\n                    Size newSize = value;\n                    if (WordWrap && WordWrapMode != FastColoredTextBoxNS.WordWrapMode.Custom)\n                    {\n                        int maxWidth = GetMaxLineWordWrapedWidth();\n                        newSize = new Size(Math.Min(newSize.Width, maxWidth), newSize.Height);\n                    }\n\n                    base.AutoScrollMinSize = newSize;\n                }\n                else\n                {\n                    if (base.AutoScroll)\n                        base.AutoScroll = false;\n                    base.AutoScrollMinSize = new Size(0, 0);\n                    VerticalScroll.Visible = false;\n                    HorizontalScroll.Visible = false;\n                    VerticalScroll.Maximum = Math.Max(0, value.Height - ClientSize.Height);\n                    HorizontalScroll.Maximum = Math.Max(0, value.Width - ClientSize.Width);\n                    localAutoScrollMinSize = value;\n                }\n            }\n\n            get\n            {\n                if (scrollBars)\n                    return base.AutoScrollMinSize;\n                else\n                    //return new Size(HorizontalScroll.Maximum, VerticalScroll.Maximum);\n                    return localAutoScrollMinSize;\n            }\n        }\n\n        /// <summary>\n        /// Indicates that IME is allowed (for CJK language entering)\n        /// </summary>\n        [Browsable(false)]\n        public bool ImeAllowed\n        {\n            get\n            {\n                return ImeMode != ImeMode.Disable &&\n                       ImeMode != ImeMode.Off &&\n                       ImeMode != ImeMode.NoControl;\n            }\n        }\n\n        /// <summary>\n        /// Is undo enabled?\n        /// </summary>\n        [Browsable(false)]\n        public bool UndoEnabled\n        {\n            get { return lines.Manager.UndoEnabled; }\n        }\n\n        /// <summary>\n        /// Is redo enabled?\n        /// </summary>\n        [Browsable(false)]\n        public bool RedoEnabled\n        {\n            get { return lines.Manager.RedoEnabled; }\n        }\n\n        private int LeftIndentLine\n        {\n            get { return LeftIndent - minLeftIndent / 2 - 3; }\n        }\n\n        /// <summary>\n        /// Range of all text\n        /// </summary>\n        [Browsable(false)]\n        public Range Range\n        {\n            get { return new Range(this, new Place(0, 0), new Place(lines[lines.Count - 1].Count, lines.Count - 1)); }\n        }\n\n        /// <summary>\n        /// Color of selected area\n        /// </summary>\n        [DefaultValue(typeof(Color), \"Blue\")]\n        [Description(\"Color of selected area.\")]\n        public virtual Color SelectionColor\n        {\n            get { return selectionColor; }\n            set\n            {\n                selectionColor = value;\n                if (selectionColor.A == 255)\n                    selectionColor = Color.FromArgb(60, selectionColor);\n                SelectionStyle = new SelectionStyle(new SolidBrush(selectionColor));\n                Invalidate();\n            }\n        }\n\n        public override Cursor Cursor\n        {\n            get { return base.Cursor; }\n            set\n            {\n                defaultCursor = value;\n                base.Cursor = value;\n            }\n        }\n\n        /// <summary>\n        /// Reserved space for line number characters.\n        /// If smaller than needed (e. g. line count >= 10 and this value set to 1) this value will have no impact.\n        /// If you want to reserve space, e. g. for line numbers >= 10 or >= 100 than you can set this value to 2 or 3 or higher.\n        /// </summary>\n        [DefaultValue(1)]\n        [Description(\n            \"Reserved space for line number characters. If smaller than needed (e. g. line count >= 10 and \" +\n            \"this value set to 1) this value will have no impact. If you want to reserve space, e. g. for line \" +\n            \"numbers >= 10 or >= 100, than you can set this value to 2 or 3 or higher.\")]\n        public int ReservedCountOfLineNumberChars\n        {\n            get { return reservedCountOfLineNumberChars; }\n            set\n            {\n                reservedCountOfLineNumberChars = value;\n                NeedRecalc();\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Occurs when mouse is moving over text and tooltip is needed\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Occurs when mouse is moving over text and tooltip is needed.\")]\n        public event EventHandler<ToolTipNeededEventArgs> ToolTipNeeded;\n\n        /// <summary>\n        /// Removes all hints\n        /// </summary>\n        public void ClearHints()\n        {\n            if (Hints != null)\n                Hints.Clear();\n        }\n\n        /// <summary>\n        /// Add and shows the hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"innerControl\">Inner control</param>\n        /// <param name=\"scrollToHint\">Scrolls textbox to the hint</param>\n        /// <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n        /// <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        public virtual Hint AddHint(Range range, Control innerControl, bool scrollToHint, bool inline, bool dock)\n        {\n            var hint = new Hint(range, innerControl, inline, dock);\n            Hints.Add(hint);\n            if (scrollToHint)\n                hint.DoVisible();\n\n            return hint;\n        }\n\n        /// <summary>\n        /// Add and shows the hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"innerControl\">Inner control</param>\n        public Hint AddHint(Range range, Control innerControl)\n        {\n            return AddHint(range, innerControl, true, true, true);\n        }\n\n        /// <summary>\n        /// Add and shows simple text hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"text\">Text of simple hint</param>\n        /// <param name=\"scrollToHint\">Scrolls textbox to the hint</param>\n        /// <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n        /// <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        public virtual Hint AddHint(Range range, string text, bool scrollToHint, bool inline, bool dock)\n        {\n            var hint = new Hint(range, text, inline, dock);\n            Hints.Add(hint);\n            if (scrollToHint)\n                hint.DoVisible();\n\n            return hint;\n        }\n\n        /// <summary>\n        /// Add and shows simple text hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"text\">Text of simple hint</param>\n        public Hint AddHint(Range range, string text)\n        {\n            return AddHint(range, text, true, true, true);\n        }\n\n        /// <summary>\n        /// Occurs when user click on the hint\n        /// </summary>\n        /// <param name=\"hint\"></param>\n        public virtual void OnHintClick(Hint hint)\n        {\n            if (HintClick != null)\n                HintClick(this, new HintClickEventArgs(hint));\n        }\n\n        private void timer3_Tick(object sender, EventArgs e)\n        {\n            timer3.Stop();\n            OnToolTip();\n        }\n\n        protected virtual void OnToolTip()\n        {\n            if (ToolTip == null)\n                return;\n            if (ToolTipNeeded == null)\n                return;\n\n            //get place under mouse\n            Place place = PointToPlace(lastMouseCoord);\n\n            //check distance\n            Point p = PlaceToPoint(place);\n            if (Math.Abs(p.X - lastMouseCoord.X) > CharWidth * 2 ||\n                Math.Abs(p.Y - lastMouseCoord.Y) > CharHeight * 2)\n                return;\n            //get word under mouse\n            var r = new Range(this, place, place);\n            string hoveredWord = r.GetFragment(\"[a-zA-Z]\").Text;\n            //event handler\n            var ea = new ToolTipNeededEventArgs(place, hoveredWord);\n            ToolTipNeeded(this, ea);\n\n            if (ea.ToolTipText != null)\n            {\n                //show tooltip\n                ToolTip.ToolTipTitle = ea.ToolTipTitle;\n                ToolTip.ToolTipIcon = ea.ToolTipIcon;\n                //ToolTip.SetToolTip(this, ea.ToolTipText);\n                ToolTip.Show(ea.ToolTipText, this, new Point(lastMouseCoord.X, lastMouseCoord.Y + CharHeight));\n            }\n        }\n\n        /// <summary>\n        /// Occurs when VisibleRange is changed\n        /// </summary>\n        public virtual void OnVisibleRangeChanged()\n        {\n            needRecalcFoldingLines = true;\n\n            needRiseVisibleRangeChangedDelayed = true;\n            ResetTimer(timer);\n            if (VisibleRangeChanged != null)\n                VisibleRangeChanged(this, new EventArgs());\n        }\n\n        /// <summary>\n        /// Invalidates the entire surface of the control and causes the control to be redrawn.\n        /// This method is thread safe and does not require Invoke.\n        /// </summary>\n        public new void Invalidate()\n        {\n            if (InvokeRequired)\n                BeginInvoke(new MethodInvoker(Invalidate));\n            else\n                base.Invalidate();\n        }\n\n        protected virtual void OnCharSizeChanged()\n        {\n            VerticalScroll.SmallChange = charHeight;\n            VerticalScroll.LargeChange = 10 * charHeight;\n            HorizontalScroll.SmallChange = CharWidth;\n        }\n\n        /// <summary>\n        /// HintClick event.\n        /// It occurs if user click on the hint.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs if user click on the hint.\")]\n        public event EventHandler<HintClickEventArgs> HintClick;\n\n        /// <summary>\n        /// TextChanged event.\n        /// It occurs after insert, delete, clear, undo and redo operations.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs after insert, delete, clear, undo and redo operations.\")]\n        public new event EventHandler<TextChangedEventArgs> TextChanged;\n\n        /// <summary>\n        /// Fake event for correct data binding\n        /// </summary>\n        [Browsable(false)]\n        internal event EventHandler BindingTextChanged;\n\n        /// <summary>\n        /// Occurs when user paste text from clipboard\n        /// </summary>\n        [Description(\"Occurs when user paste text from clipboard\")]\n        public event EventHandler<TextChangingEventArgs> Pasting;\n\n        /// <summary>\n        /// TextChanging event.\n        /// It occurs before insert, delete, clear, undo and redo operations.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs before insert, delete, clear, undo and redo operations.\")]\n        public event EventHandler<TextChangingEventArgs> TextChanging;\n\n        /// <summary>\n        /// SelectionChanged event.\n        /// It occurs after changing of selection.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs after changing of selection.\")]\n        public event EventHandler SelectionChanged;\n\n        /// <summary>\n        /// VisibleRangeChanged event.\n        /// It occurs after changing of visible range.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs after changing of visible range.\")]\n        public event EventHandler VisibleRangeChanged;\n\n        /// <summary>\n        /// TextChangedDelayed event. \n        /// It occurs after insert, delete, clear, undo and redo operations. \n        /// This event occurs with a delay relative to TextChanged, and fires only once.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\n            \"It occurs after insert, delete, clear, undo and redo operations. This event occurs with a delay relative to TextChanged, and fires only once.\"\n        )]\n        public event EventHandler<TextChangedEventArgs> TextChangedDelayed;\n\n        /// <summary>\n        /// SelectionChangedDelayed event.\n        /// It occurs after changing of selection.\n        /// This event occurs with a delay relative to SelectionChanged, and fires only once.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\n            \"It occurs after changing of selection. This event occurs with a delay relative to SelectionChanged, and fires only once.\"\n        )]\n        public event EventHandler SelectionChangedDelayed;\n\n        /// <summary>\n        /// VisibleRangeChangedDelayed event.\n        /// It occurs after changing of visible range.\n        /// This event occurs with a delay relative to VisibleRangeChanged, and fires only once.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\n            \"It occurs after changing of visible range. This event occurs with a delay relative to VisibleRangeChanged, and fires only once.\"\n        )]\n        public event EventHandler VisibleRangeChangedDelayed;\n\n        /// <summary>\n        /// It occurs when user click on VisualMarker.\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs when user click on VisualMarker.\")]\n        public event EventHandler<VisualMarkerEventArgs> VisualMarkerClick;\n\n        /// <summary>\n        /// It occurs when visible char is enetering (alphabetic, digit, punctuation, DEL, BACKSPACE)\n        /// </summary>\n        /// <remarks>Set Handle to True for cancel key</remarks>\n        [Browsable(true)]\n        [Description(\"It occurs when visible char is enetering (alphabetic, digit, punctuation, DEL, BACKSPACE).\")]\n        public event KeyPressEventHandler KeyPressing;\n\n        /// <summary>\n        /// It occurs when visible char is enetered (alphabetic, digit, punctuation, DEL, BACKSPACE)\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs when visible char is enetered (alphabetic, digit, punctuation, DEL, BACKSPACE).\")]\n        public event KeyPressEventHandler KeyPressed;\n\n        /// <summary>\n        /// It occurs when calculates AutoIndent for new line\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs when calculates AutoIndent for new line.\")]\n        public event EventHandler<AutoIndentEventArgs> AutoIndentNeeded;\n\n        /// <summary>\n        /// It occurs when line background is painting\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"It occurs when line background is painting.\")]\n        public event EventHandler<PaintLineEventArgs> PaintLine;\n\n        /// <summary>\n        /// Occurs when line was inserted/added\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Occurs when line was inserted/added.\")]\n        public event EventHandler<LineInsertedEventArgs> LineInserted;\n\n        /// <summary>\n        /// Occurs when line was removed\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Occurs when line was removed.\")]\n        public event EventHandler<LineRemovedEventArgs> LineRemoved;\n\n        /// <summary>\n        /// Occurs when current highlighted folding area is changed.\n        /// Current folding area see in StartFoldingLine and EndFoldingLine.\n        /// </summary>\n        /// <remarks></remarks>\n        [Browsable(true)]\n        [Description(\"Occurs when current highlighted folding area is changed.\")]\n        public event EventHandler<EventArgs> FoldingHighlightChanged;\n\n        /// <summary>\n        /// Occurs when undo/redo stack is changed\n        /// </summary>\n        /// <remarks></remarks>\n        [Browsable(true)]\n        [Description(\"Occurs when undo/redo stack is changed.\")]\n        public event EventHandler<EventArgs> UndoRedoStateChanged;\n\n        /// <summary>\n        /// Occurs when component was zoomed\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Occurs when component was zoomed.\")]\n        public event EventHandler ZoomChanged;\n\n\n        /// <summary>\n        /// Occurs when user pressed key, that specified as CustomAction\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Occurs when user pressed key, that specified as CustomAction.\")]\n        public event EventHandler<CustomActionEventArgs> CustomAction;\n\n        /// <summary>\n        /// Occurs when scroolbars are updated\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Occurs when scroolbars are updated.\")]\n        public event EventHandler ScrollbarsUpdated;\n\n        /// <summary>\n        /// Occurs when custom wordwrap is needed\n        /// </summary>\n        [Browsable(true)]\n        [Description(\"Occurs when custom wordwrap is needed.\")]\n        public event EventHandler<WordWrapNeededEventArgs> WordWrapNeeded;\n\n\n        /// <summary>\n        /// Returns list of styles of given place\n        /// </summary>\n        public List<Style> GetStylesOfChar(Place place)\n        {\n            var result = new List<Style>();\n            if (place.iLine < LinesCount && place.iChar < this[place.iLine].Count)\n            {\n#if Styles32\n                var s = (uint) this[place].style;\n                for (int i = 0; i < 32; i++)\n                    if ((s & ((uint) 1) << i) != 0)\n                        result.Add(Styles[i]);\n#else\n                var s = (ushort) this[place].style;\n                for (int i = 0; i < 16; i++)\n                    if ((s & ((ushort) 1) << i) != 0)\n                        result.Add(Styles[i]);\n#endif\n            }\n\n            return result;\n        }\n\n        protected virtual TextSource CreateTextSource()\n        {\n            return new TextSource(this);\n        }\n\n        private void SetAsCurrentTB()\n        {\n            TextSource.CurrentTB = this;\n        }\n\n        protected virtual void InitTextSource(TextSource ts)\n        {\n            if (lines != null)\n            {\n                lines.LineInserted -= ts_LineInserted;\n                lines.LineRemoved -= ts_LineRemoved;\n                lines.TextChanged -= ts_TextChanged;\n                lines.RecalcNeeded -= ts_RecalcNeeded;\n                lines.RecalcWordWrap -= ts_RecalcWordWrap;\n                lines.TextChanging -= ts_TextChanging;\n\n                lines.Dispose();\n            }\n\n            LineInfos.Clear();\n            ClearHints();\n            if (Bookmarks != null)\n                Bookmarks.Clear();\n\n            lines = ts;\n\n            if (ts != null)\n            {\n                ts.LineInserted += ts_LineInserted;\n                ts.LineRemoved += ts_LineRemoved;\n                ts.TextChanged += ts_TextChanged;\n                ts.RecalcNeeded += ts_RecalcNeeded;\n                ts.RecalcWordWrap += ts_RecalcWordWrap;\n                ts.TextChanging += ts_TextChanging;\n\n                while (LineInfos.Count < ts.Count)\n                    LineInfos.Add(new LineInfo(-1));\n            }\n\n            isChanged = false;\n            needRecalc = true;\n        }\n\n        private void ts_RecalcWordWrap(object sender, TextSource.TextChangedEventArgs e)\n        {\n            RecalcWordWrap(e.iFromLine, e.iToLine);\n        }\n\n        private void ts_TextChanging(object sender, TextChangingEventArgs e)\n        {\n            if (TextSource.CurrentTB == this)\n            {\n                string text = e.InsertingText;\n                OnTextChanging(ref text);\n                e.InsertingText = text;\n            }\n        }\n\n        private void ts_RecalcNeeded(object sender, TextSource.TextChangedEventArgs e)\n        {\n            if (e.iFromLine == e.iToLine && !WordWrap && lines.Count > minLinesForAccuracy)\n                RecalcScrollByOneLine(e.iFromLine);\n            else\n            {\n                NeedRecalc(false, WordWrap);\n                //needRecalc = true;\n            }\n        }\n\n        /// <summary>\n        /// Call this method if the recalc of the position of lines is needed.\n        /// </summary>\n        public void NeedRecalc()\n        {\n            NeedRecalc(false);\n        }\n\n        /// <summary>\n        /// Call this method if the recalc of the position of lines is needed.\n        /// </summary>\n        public void NeedRecalc(bool forced)\n        {\n            NeedRecalc(forced, false);\n        }\n\n        /// <summary>\n        /// Call this method if the recalc of the position of lines is needed.\n        /// </summary>\n        public void NeedRecalc(bool forced, bool wordWrapRecalc)\n        {\n            needRecalc = true;\n\n            if (wordWrapRecalc)\n            {\n                needRecalcWordWrapInterval = new Point(0, LinesCount - 1);\n                needRecalcWordWrap = true;\n            }\n\n            if (forced)\n                Recalc();\n        }\n\n        private void ts_TextChanged(object sender, TextSource.TextChangedEventArgs e)\n        {\n            if (e.iFromLine == e.iToLine && !WordWrap)\n                RecalcScrollByOneLine(e.iFromLine);\n            else\n                needRecalc = true;\n\n            Invalidate();\n            if (TextSource.CurrentTB == this)\n                OnTextChanged(e.iFromLine, e.iToLine);\n        }\n\n        private void ts_LineRemoved(object sender, LineRemovedEventArgs e)\n        {\n            LineInfos.RemoveRange(e.Index, e.Count);\n            OnLineRemoved(e.Index, e.Count, e.RemovedLineUniqueIds);\n        }\n\n        private void ts_LineInserted(object sender, LineInsertedEventArgs e)\n        {\n            VisibleState newState = VisibleState.Visible;\n            if (e.Index >= 0 && e.Index < LineInfos.Count && LineInfos[e.Index].VisibleState == VisibleState.Hidden)\n                newState = VisibleState.Hidden;\n\n            if (e.Count > 100000)\n                LineInfos.Capacity = LineInfos.Count + e.Count + 1000;\n\n            var temp = new LineInfo[e.Count];\n            for (int i = 0; i < e.Count; i++)\n            {\n                temp[i].startY = -1;\n                temp[i].VisibleState = newState;\n            }\n\n            LineInfos.InsertRange(e.Index, temp);\n\n            /* \n            for (int i = 0; i < e.Count; i++)\n            {\n                LineInfos.Add(new LineInfo(-1) { VisibleState = newState });//<---- needed Insert\n                if(i % 1000000 == 0 && i > 0)\n                    GC.Collect();\n            }*/\n\n            if (e.Count > 1000000)\n                GC.Collect();\n\n            OnLineInserted(e.Index, e.Count);\n        }\n\n        /// <summary>\n        /// Navigates forward (by Line.LastVisit property)\n        /// </summary>\n        public bool NavigateForward()\n        {\n            DateTime min = DateTime.Now;\n            int iLine = -1;\n            for (int i = 0; i < LinesCount; i++)\n                if (lines.IsLineLoaded(i))\n                    if (lines[i].LastVisit > lastNavigatedDateTime && lines[i].LastVisit < min)\n                    {\n                        min = lines[i].LastVisit;\n                        iLine = i;\n                    }\n\n            if (iLine >= 0)\n            {\n                Navigate(iLine);\n                return true;\n            }\n            else\n                return false;\n        }\n\n        /// <summary>\n        /// Navigates backward (by Line.LastVisit property)\n        /// </summary>\n        public bool NavigateBackward()\n        {\n            var max = new DateTime();\n            int iLine = -1;\n            for (int i = 0; i < LinesCount; i++)\n                if (lines.IsLineLoaded(i))\n                    if (lines[i].LastVisit < lastNavigatedDateTime && lines[i].LastVisit > max)\n                    {\n                        max = lines[i].LastVisit;\n                        iLine = i;\n                    }\n\n            if (iLine >= 0)\n            {\n                Navigate(iLine);\n                return true;\n            }\n            else\n                return false;\n        }\n\n        /// <summary>\n        /// Navigates to defined line, without Line.LastVisit reseting\n        /// </summary>\n        public void Navigate(int iLine)\n        {\n            if (iLine >= LinesCount) return;\n            lastNavigatedDateTime = lines[iLine].LastVisit;\n            Selection.Start = new Place(0, iLine);\n            DoSelectionVisible();\n        }\n\n        protected override void OnLoad(EventArgs e)\n        {\n            base.OnLoad(e);\n            m_hImc = NativeMethodWrapper.ImmGetContext(Handle);\n        }\n\n        private void timer2_Tick(object sender, EventArgs e)\n        {\n            timer2.Enabled = false;\n            if (needRiseTextChangedDelayed)\n            {\n                needRiseTextChangedDelayed = false;\n                if (delayedTextChangedRange == null)\n                    return;\n                delayedTextChangedRange = Range.GetIntersectionWith(delayedTextChangedRange);\n                delayedTextChangedRange.Expand();\n                OnTextChangedDelayed(delayedTextChangedRange);\n                delayedTextChangedRange = null;\n            }\n        }\n\n        public void AddVisualMarker(VisualMarker marker)\n        {\n            visibleMarkers.Add(marker);\n        }\n\n        private void timer_Tick(object sender, EventArgs e)\n        {\n            timer.Enabled = false;\n            if (needRiseSelectionChangedDelayed)\n            {\n                needRiseSelectionChangedDelayed = false;\n                OnSelectionChangedDelayed();\n            }\n\n            if (needRiseVisibleRangeChangedDelayed)\n            {\n                needRiseVisibleRangeChangedDelayed = false;\n                OnVisibleRangeChangedDelayed();\n            }\n        }\n\n        public virtual void OnTextChangedDelayed(Range changedRange)\n        {\n            if (TextChangedDelayed != null)\n                TextChangedDelayed(this, new TextChangedEventArgs(changedRange));\n        }\n\n        public virtual void OnSelectionChangedDelayed()\n        {\n            RecalcScrollByOneLine(Selection.Start.iLine);\n            //highlight brackets\n            ClearBracketsPositions();\n            if (LeftBracket != '\\x0' && RightBracket != '\\x0')\n                HighlightBrackets(LeftBracket, RightBracket, ref leftBracketPosition, ref rightBracketPosition);\n            if (LeftBracket2 != '\\x0' && RightBracket2 != '\\x0')\n                HighlightBrackets(LeftBracket2, RightBracket2, ref leftBracketPosition2, ref rightBracketPosition2);\n            //remember last visit time\n            if (Selection.IsEmpty && Selection.Start.iLine < LinesCount)\n            {\n                if (lastNavigatedDateTime != lines[Selection.Start.iLine].LastVisit)\n                {\n                    lines[Selection.Start.iLine].LastVisit = DateTime.Now;\n                    lastNavigatedDateTime = lines[Selection.Start.iLine].LastVisit;\n                }\n            }\n\n            if (SelectionChangedDelayed != null)\n                SelectionChangedDelayed(this, new EventArgs());\n        }\n\n        public virtual void OnVisibleRangeChangedDelayed()\n        {\n            if (VisibleRangeChangedDelayed != null)\n                VisibleRangeChangedDelayed(this, new EventArgs());\n        }\n\n        Dictionary<Timer, Timer> timersToReset = new Dictionary<Timer, Timer>();\n\n        private void ResetTimer(Timer timer)\n        {\n            if (InvokeRequired)\n            {\n                BeginInvoke(new MethodInvoker(() => ResetTimer(timer)));\n                return;\n            }\n\n            timer.Stop();\n            if (IsHandleCreated)\n                timer.Start();\n            else\n                timersToReset[timer] = timer;\n        }\n\n        protected override void OnHandleCreated(EventArgs e)\n        {\n            base.OnHandleCreated(e);\n            foreach (var timer in new List<Timer>(timersToReset.Keys))\n                ResetTimer(timer);\n            timersToReset.Clear();\n\n            OnScrollbarsUpdated();\n        }\n\n        /// <summary>\n        /// Add new style\n        /// </summary>\n        /// <returns>Layer index of this style</returns>\n        public int AddStyle(Style style)\n        {\n            if (style == null) return -1;\n\n            int i = GetStyleIndex(style);\n            if (i >= 0)\n                return i;\n\n            i = CheckStylesBufferSize();\n            Styles[i] = style;\n            return i;\n        }\n\n        /// <summary>\n        /// Checks if the styles buffer has enough space to add one \n        /// more element. If not, an exception is thrown. Otherwise, \n        /// the index of a free slot is returned. \n        /// </summary>\n        /// <returns>Index of free styles buffer slot</returns>\n        /// <exception cref=\"Exception\">If maximum count of styles is exceeded</exception>\n        public int CheckStylesBufferSize()\n        {\n            int i;\n            for (i = Styles.Length - 1; i >= 0; i--)\n                if (Styles[i] != null)\n                    break;\n\n            i++;\n            if (i >= Styles.Length)\n                throw new Exception(\"Maximum count of Styles is exceeded.\");\n\n            return i;\n        }\n\n        /// <summary>\n        /// Shows find dialog\n        /// </summary>\n        public virtual void ShowFindDialog()\n        {\n            ShowFindDialog(null);\n        }\n\n        /// <summary>\n        /// Shows find dialog\n        /// </summary>\n        public virtual void ShowFindDialog(string findText)\n        {\n            if (findForm == null)\n                findForm = new FindForm(this);\n\n            if (findText != null)\n                findForm.tbFind.Text = findText;\n            else if (!Selection.IsEmpty && Selection.Start.iLine == Selection.End.iLine)\n                findForm.tbFind.Text = Selection.Text;\n\n            findForm.tbFind.SelectAll();\n            findForm.Show();\n            findForm.Focus();\n        }\n\n        /// <summary>\n        /// Shows replace dialog\n        /// </summary>\n        public virtual void ShowReplaceDialog()\n        {\n            ShowReplaceDialog(null);\n        }\n\n        /// <summary>\n        /// Shows replace dialog\n        /// </summary>\n        public virtual void ShowReplaceDialog(string findText)\n        {\n            if (ReadOnly)\n                return;\n            if (replaceForm == null)\n                replaceForm = new ReplaceForm(this);\n\n            if (findText != null)\n                replaceForm.tbFind.Text = findText;\n            else if (!Selection.IsEmpty && Selection.Start.iLine == Selection.End.iLine)\n                replaceForm.tbFind.Text = Selection.Text;\n\n            replaceForm.tbFind.SelectAll();\n            replaceForm.Show();\n            replaceForm.Focus();\n        }\n\n        /// <summary>\n        /// Gets length of given line\n        /// </summary>\n        /// <param name=\"iLine\">Line index</param>\n        /// <returns>Length of line</returns>\n        public int GetLineLength(int iLine)\n        {\n            if (iLine < 0 || iLine >= lines.Count)\n                throw new ArgumentOutOfRangeException(\"Line index out of range\");\n\n            return lines[iLine].Count;\n        }\n\n        /// <summary>\n        /// Get range of line\n        /// </summary>\n        /// <param name=\"iLine\">Line index</param>\n        public Range GetLine(int iLine)\n        {\n            if (iLine < 0 || iLine >= lines.Count)\n                throw new ArgumentOutOfRangeException(\"Line index out of range\");\n\n            var sel = new Range(this);\n            sel.Start = new Place(0, iLine);\n            sel.End = new Place(lines[iLine].Count, iLine);\n            return sel;\n        }\n\n        /// <summary>\n        /// Copy selected text into Clipboard\n        /// </summary>\n        public virtual void Copy()\n        {\n            if (Selection.IsEmpty)\n                Selection.Expand();\n            if (!Selection.IsEmpty)\n            {\n                var data = new DataObject();\n                OnCreateClipboardData(data);\n                //\n                var thread = new Thread(() => SetClipboard(data));\n                thread.SetApartmentState(ApartmentState.STA);\n                thread.Start();\n                thread.Join();\n            }\n        }\n\n        protected virtual void OnCreateClipboardData(DataObject data)\n        {\n            var exp = new ExportToHTML();\n            exp.UseBr = false;\n            exp.UseNbsp = false;\n            exp.UseStyleTag = true;\n            string html = \"<pre>\" + exp.GetHtml(Selection.Clone()) + \"</pre>\";\n\n            data.SetData(DataFormats.UnicodeText, true, Selection.Text);\n            data.SetData(DataFormats.Html, PrepareHtmlForClipboard(html));\n            data.SetData(DataFormats.Rtf, new ExportToRTF().GetRtf(Selection.Clone()));\n        }\n\n      \n\n        protected void SetClipboard(DataObject data)\n        {\n            try\n            {\n                /*\n                while (GetOpenClipboardWindow() != IntPtr.Zero)\n                    Thread.Sleep(0);*/\n                NativeMethodWrapper.CloseClipboard();\n                Clipboard.SetDataObject(data, true, 5, 100);\n            }\n            catch (ExternalException)\n            {\n                //occurs if some other process holds open clipboard\n            }\n        }\n\n        public static MemoryStream PrepareHtmlForClipboard(string html)\n        {\n            Encoding enc = Encoding.UTF8;\n\n            string begin = \"Version:0.9\\r\\nStartHTML:{0:000000}\\r\\nEndHTML:{1:000000}\"\n                           + \"\\r\\nStartFragment:{2:000000}\\r\\nEndFragment:{3:000000}\\r\\n\";\n\n            string html_begin = \"<html>\\r\\n<head>\\r\\n\"\n                                + \"<meta http-equiv=\\\"Content-Type\\\"\"\n                                + \" content=\\\"text/html; charset=\" + enc.WebName + \"\\\">\\r\\n\"\n                                + \"<title>HTML clipboard</title>\\r\\n</head>\\r\\n<body>\\r\\n\"\n                                + \"<!--StartFragment-->\";\n\n            string html_end = \"<!--EndFragment-->\\r\\n</body>\\r\\n</html>\\r\\n\";\n\n            string begin_sample = String.Format(begin, 0, 0, 0, 0);\n\n            int count_begin = enc.GetByteCount(begin_sample);\n            int count_html_begin = enc.GetByteCount(html_begin);\n            int count_html = enc.GetByteCount(html);\n            int count_html_end = enc.GetByteCount(html_end);\n\n            string html_total = String.Format(\n                                    begin\n                                    , count_begin\n                                    , count_begin + count_html_begin + count_html + count_html_end\n                                    , count_begin + count_html_begin\n                                    , count_begin + count_html_begin + count_html\n                                ) + html_begin + html + html_end;\n\n            return new MemoryStream(enc.GetBytes(html_total));\n        }\n\n\n        /// <summary>\n        /// Cut selected text into Clipboard\n        /// </summary>\n        public virtual void Cut()\n        {\n            if (!Selection.IsEmpty)\n            {\n                Copy();\n                ClearSelected();\n            }\n            else if (LinesCount == 1)\n            {\n                Selection.SelectAll();\n                Copy();\n                ClearSelected();\n            }\n            else\n            {\n                //copy\n                var data = new DataObject();\n                OnCreateClipboardData(data);\n                //\n                var thread = new Thread(() => SetClipboard(data));\n                thread.SetApartmentState(ApartmentState.STA);\n                thread.Start();\n                thread.Join();\n\n                //remove current line\n                if (Selection.Start.iLine >= 0 && Selection.Start.iLine < LinesCount)\n                {\n                    int iLine = Selection.Start.iLine;\n                    RemoveLines(new List<int> {iLine});\n                    Selection.Start = new Place(0, Math.Max(0, Math.Min(iLine, LinesCount - 1)));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Paste text from clipboard into selected position\n        /// </summary>\n        public virtual void Paste()\n        {\n            string text = null;\n            var thread = new Thread(() =>\n            {\n                if (Clipboard.ContainsText())\n                    text = Clipboard.GetText();\n            });\n            thread.SetApartmentState(ApartmentState.STA);\n            thread.Start();\n            thread.Join();\n\n            if (Pasting != null)\n            {\n                var args = new TextChangingEventArgs\n                {\n                    Cancel = false,\n                    InsertingText = text\n                };\n\n                Pasting(this, args);\n\n                if (args.Cancel)\n                    text = string.Empty;\n                else\n                    text = args.InsertingText;\n            }\n\n            if (!string.IsNullOrEmpty(text))\n                InsertText(text);\n        }\n\n        /// <summary>\n        /// Select all chars of text\n        /// </summary>\n        public void SelectAll()\n        {\n            Selection.SelectAll();\n        }\n\n        /// <summary>\n        /// Move caret to end of text\n        /// </summary>\n        public void GoEnd()\n        {\n            if (lines.Count > 0)\n                Selection.Start = new Place(lines[lines.Count - 1].Count, lines.Count - 1);\n            else\n                Selection.Start = new Place(0, 0);\n\n            DoCaretVisible();\n        }\n\n        /// <summary>\n        /// Move caret to first position\n        /// </summary>\n        public void GoHome()\n        {\n            Selection.Start = new Place(0, 0);\n\n            DoCaretVisible();\n            //VerticalScroll.Value = 0;\n            //HorizontalScroll.Value = 0;\n        }\n\n        /// <summary>\n        /// Clear text, styles, history, caches\n        /// </summary>\n        public virtual void Clear()\n        {\n            Selection.BeginUpdate();\n            try\n            {\n                Selection.SelectAll();\n                ClearSelected();\n                lines.Manager.ClearHistory();\n                Invalidate();\n            }\n            finally\n            {\n                Selection.EndUpdate();\n            }\n        }\n\n        /// <summary>\n        /// Clear buffer of styles\n        /// </summary>\n        public void ClearStylesBuffer()\n        {\n            for (int i = 0; i < Styles.Length; i++)\n                Styles[i] = null;\n        }\n\n        /// <summary>\n        /// Clear style of all text\n        /// </summary>\n        public void ClearStyle(StyleIndex styleIndex)\n        {\n            foreach (Line line in lines)\n                line.ClearStyle(styleIndex);\n\n            for (int i = 0; i < LineInfos.Count; i++)\n                SetVisibleState(i, VisibleState.Visible);\n\n            Invalidate();\n        }\n\n\n        /// <summary>\n        /// Clears undo and redo stacks\n        /// </summary>\n        public void ClearUndo()\n        {\n            lines.Manager.ClearHistory();\n        }\n\n        /// <summary>\n        /// Insert text into current selected position\n        /// </summary>\n        public virtual void InsertText(string text)\n        {\n            InsertText(text, true);\n        }\n\n        /// <summary>\n        /// Insert text into current selected position\n        /// </summary>\n        /// <param name=\"text\"></param>\n        public virtual void InsertText(string text, bool jumpToCaret)\n        {\n            if (text == null)\n                return;\n            if (text == \"\\r\")\n                text = \"\\n\";\n\n            lines.Manager.BeginAutoUndoCommands();\n            try\n            {\n                if (!Selection.IsEmpty)\n                    lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));\n\n                //insert virtual spaces\n                if (this.TextSource.Count > 0)\n                    if (Selection.IsEmpty && Selection.Start.iChar > GetLineLength(Selection.Start.iLine) &&\n                        VirtualSpace)\n                        InsertVirtualSpaces();\n\n                lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, text));\n                if (updating <= 0 && jumpToCaret)\n                    DoCaretVisible();\n            }\n            finally\n            {\n                lines.Manager.EndAutoUndoCommands();\n            }\n\n            //\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Insert text into current selection position (with predefined style)\n        /// </summary>\n        /// <param name=\"text\"></param>\n        public virtual Range InsertText(string text, Style style)\n        {\n            return InsertText(text, style, true);\n        }\n\n        /// <summary>\n        /// Insert text into current selection position (with predefined style)\n        /// </summary>\n        public virtual Range InsertText(string text, Style style, bool jumpToCaret)\n        {\n            if (text == null)\n                return null;\n\n            //remember last caret position\n            Place last = Selection.Start > Selection.End ? Selection.End : Selection.Start;\n            //insert text\n            InsertText(text, jumpToCaret);\n            //get range\n            var range = new Range(this, last, Selection.Start) {ColumnSelectionMode = Selection.ColumnSelectionMode};\n            range = range.GetIntersectionWith(Range);\n            //set style for range\n            range.SetStyle(style);\n\n            return range;\n        }\n\n        /// <summary>\n        /// Insert text into replaceRange and restore previous selection\n        /// </summary>\n        public virtual Range InsertTextAndRestoreSelection(Range replaceRange, string text, Style style)\n        {\n            if (text == null)\n                return null;\n\n            var oldStart = PlaceToPosition(Selection.Start);\n            var oldEnd = PlaceToPosition(Selection.End);\n            var count = replaceRange.Text.Length;\n            var pos = PlaceToPosition(replaceRange.Start);\n            //\n            Selection.BeginUpdate();\n            Selection = replaceRange;\n            var range = InsertText(text, style);\n            //\n            count = range.Text.Length - count;\n            Selection.Start = PositionToPlace(oldStart + (oldStart >= pos ? count : 0));\n            Selection.End = PositionToPlace(oldEnd + (oldEnd >= pos ? count : 0));\n            Selection.EndUpdate();\n\n            return range;\n        }\n\n        /// <summary>\n        /// Append string to end of the Text\n        /// </summary>\n        public virtual void AppendText(string text)\n        {\n            AppendText(text, null);\n        }\n\n        /// <summary>\n        /// Append string to end of the Text\n        /// </summary>\n        public virtual void AppendText(string text, Style style)\n        {\n            if (text == null)\n                return;\n\n            Selection.ColumnSelectionMode = false;\n\n            Place oldStart = Selection.Start;\n            Place oldEnd = Selection.End;\n\n            Selection.BeginUpdate();\n            lines.Manager.BeginAutoUndoCommands();\n            try\n            {\n                if (lines.Count > 0)\n                    Selection.Start = new Place(lines[lines.Count - 1].Count, lines.Count - 1);\n                else\n                    Selection.Start = new Place(0, 0);\n\n                //remember last caret position\n                Place last = Selection.Start;\n\n                lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, text));\n\n                if (style != null)\n                    new Range(this, last, Selection.Start).SetStyle(style);\n            }\n            finally\n            {\n                lines.Manager.EndAutoUndoCommands();\n                Selection.Start = oldStart;\n                Selection.End = oldEnd;\n                Selection.EndUpdate();\n            }\n\n            //\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Returns index of the style in Styles\n        /// -1 otherwise\n        /// </summary>\n        /// <param name=\"style\"></param>\n        /// <returns>Index of the style in Styles</returns>\n        public int GetStyleIndex(Style style)\n        {\n            return Array.IndexOf(Styles, style);\n        }\n\n        /// <summary>\n        /// Returns StyleIndex mask of given styles\n        /// </summary>\n        /// <param name=\"styles\"></param>\n        /// <returns>StyleIndex mask of given styles</returns>\n        public StyleIndex GetStyleIndexMask(Style[] styles)\n        {\n            StyleIndex mask = StyleIndex.None;\n            foreach (Style style in styles)\n            {\n                int i = GetStyleIndex(style);\n                if (i >= 0)\n                    mask |= Range.ToStyleIndex(i);\n            }\n\n            return mask;\n        }\n\n        internal int GetOrSetStyleLayerIndex(Style style)\n        {\n            int i = GetStyleIndex(style);\n            if (i < 0)\n                i = AddStyle(style);\n            return i;\n        }\n\n        public static SizeF GetCharSize(Font font, char c)\n        {\n            Size sz2 = TextRenderer.MeasureText(\"<\" + c.ToString() + \">\", font);\n            Size sz3 = TextRenderer.MeasureText(\"<>\", font);\n\n            return new SizeF(sz2.Width - sz3.Width + 1, /*sz2.Height*/font.Height);\n        }\n\n      \n\n        protected override void WndProc(ref Message m)\n        {\n            if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL)\n                if (m.WParam.ToInt32() != SB_ENDSCROLL)\n                    Invalidate();\n\n            base.WndProc(ref m);\n\n            if (ImeAllowed)\n                if (m.Msg == WM_IME_SETCONTEXT && m.WParam.ToInt32() == 1)\n                {\n                    NativeMethodWrapper.ImmAssociateContext(Handle, m_hImc);\n                }\n        }\n\n        List<Control> tempHintsList = new List<Control>();\n\n        void HideHints()\n        {\n            //temporarly remove hints\n            if (!ShowScrollBars && Hints.Count > 0)\n            {\n                (this as Control).SuspendLayout();\n\n                foreach (Control c in Controls)\n                    tempHintsList.Add(c);\n\n                Controls.Clear();\n            }\n        }\n\n        void RestoreHints()\n        {\n            //restore hints\n            if (!ShowScrollBars && Hints.Count > 0)\n            {\n                foreach (var c in tempHintsList)\n                    Controls.Add(c);\n\n                tempHintsList.Clear();\n\n                (this as Control).ResumeLayout(false);\n\n                if (!Focused)\n                    Focus();\n            }\n        }\n\n        public void OnScroll(ScrollEventArgs se, bool alignByLines)\n        {\n            HideHints();\n\n            if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)\n            {\n                //align by line height\n                int newValue = se.NewValue;\n                if (alignByLines)\n                    newValue = (int) (Math.Ceiling(1d * newValue / CharHeight) * CharHeight);\n                //\n                VerticalScroll.Value = Math.Max(VerticalScroll.Minimum, Math.Min(VerticalScroll.Maximum, newValue));\n            }\n\n            if (se.ScrollOrientation == ScrollOrientation.HorizontalScroll)\n                HorizontalScroll.Value =\n                    Math.Max(HorizontalScroll.Minimum, Math.Min(HorizontalScroll.Maximum, se.NewValue));\n\n            UpdateScrollbars();\n\n            RestoreHints();\n\n            Invalidate();\n            //\n            base.OnScroll(se);\n            OnVisibleRangeChanged();\n        }\n\n        protected override void OnScroll(ScrollEventArgs se)\n        {\n            OnScroll(se, true);\n        }\n\n        protected virtual void InsertChar(char c)\n        {\n            lines.Manager.BeginAutoUndoCommands();\n            try\n            {\n                if (!Selection.IsEmpty)\n                    lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));\n\n                //insert virtual spaces\n                if (Selection.IsEmpty && Selection.Start.iChar > GetLineLength(Selection.Start.iLine) && VirtualSpace)\n                    InsertVirtualSpaces();\n\n                //insert char\n                lines.Manager.ExecuteCommand(new InsertCharCommand(TextSource, c));\n            }\n            finally\n            {\n                lines.Manager.EndAutoUndoCommands();\n            }\n\n            Invalidate();\n        }\n\n        private void InsertVirtualSpaces()\n        {\n            int lineLength = GetLineLength(Selection.Start.iLine);\n            int count = Selection.Start.iChar - lineLength;\n            Selection.BeginUpdate();\n            try\n            {\n                Selection.Start = new Place(lineLength, Selection.Start.iLine);\n                lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, new string(' ', count)));\n            }\n            finally\n            {\n                Selection.EndUpdate();\n            }\n        }\n\n        /// <summary>\n        /// Deletes selected chars\n        /// </summary>\n        public virtual void ClearSelected()\n        {\n            if (!Selection.IsEmpty)\n            {\n                lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Deletes current line(s)\n        /// </summary>\n        public void ClearCurrentLine()\n        {\n            Selection.Expand();\n\n            lines.Manager.ExecuteCommand(new ClearSelectedCommand(TextSource));\n            if (Selection.Start.iLine == 0)\n                if (!Selection.GoRightThroughFolded())\n                    return;\n            if (Selection.Start.iLine > 0)\n                lines.Manager.ExecuteCommand(new InsertCharCommand(TextSource, '\\b')); //backspace\n            Invalidate();\n        }\n\n        private void Recalc()\n        {\n            if (!needRecalc)\n                return;\n\n#if debug\n            var sw = Stopwatch.StartNew();\n#endif\n\n            needRecalc = false;\n            //calc min left indent\n            LeftIndent = LeftPadding;\n            long maxLineNumber = LinesCount + lineNumberStartValue - 1;\n            int charsForLineNumber = 2 + (maxLineNumber > 0 ? (int) Math.Log10(maxLineNumber) : 0);\n\n            // If there are reserved character for line numbers: correct this\n            if (this.ReservedCountOfLineNumberChars + 1 > charsForLineNumber)\n                charsForLineNumber = this.ReservedCountOfLineNumberChars + 1;\n\n            if (Created)\n            {\n                if (ShowLineNumbers)\n                    LeftIndent += charsForLineNumber * CharWidth + minLeftIndent + 1;\n\n                //calc wordwrapping\n                if (needRecalcWordWrap)\n                {\n                    RecalcWordWrap(needRecalcWordWrapInterval.X, needRecalcWordWrapInterval.Y);\n                    needRecalcWordWrap = false;\n                }\n            }\n            else\n                needRecalc = true;\n\n            //calc max line length and count of wordWrapLines\n            TextHeight = 0;\n\n            maxLineLength = RecalcMaxLineLength();\n\n            //adjust AutoScrollMinSize\n            int minWidth;\n            CalcMinAutosizeWidth(out minWidth, ref maxLineLength);\n\n            AutoScrollMinSize = new Size(minWidth, TextHeight + Paddings.Top + Paddings.Bottom);\n            UpdateScrollbars();\n#if debug\n            sw.Stop();\n            Console.WriteLine(\"Recalc: \" + sw.ElapsedMilliseconds);\n#endif\n        }\n\n        private void CalcMinAutosizeWidth(out int minWidth, ref int maxLineLength)\n        {\n            //adjust AutoScrollMinSize\n            minWidth = LeftIndent + (maxLineLength) * CharWidth + 2 + Paddings.Left + Paddings.Right;\n            if (wordWrap)\n                switch (WordWrapMode)\n                {\n                    case WordWrapMode.WordWrapControlWidth:\n                    case WordWrapMode.CharWrapControlWidth:\n                        maxLineLength = Math.Min(maxLineLength,\n                            (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right) /\n                            CharWidth);\n                        minWidth = 0;\n                        break;\n                    case WordWrapMode.WordWrapPreferredWidth:\n                    case WordWrapMode.CharWrapPreferredWidth:\n                        maxLineLength = Math.Min(maxLineLength, PreferredLineWidth);\n                        minWidth = LeftIndent + PreferredLineWidth * CharWidth + 2 + Paddings.Left + Paddings.Right;\n                        break;\n                }\n        }\n\n        private void RecalcScrollByOneLine(int iLine)\n        {\n            if (iLine >= lines.Count)\n                return;\n\n            int maxLineLength = lines[iLine].Count;\n            if (this.maxLineLength < maxLineLength && !WordWrap)\n                this.maxLineLength = maxLineLength;\n\n            int minWidth;\n            CalcMinAutosizeWidth(out minWidth, ref maxLineLength);\n\n            if (AutoScrollMinSize.Width < minWidth)\n                AutoScrollMinSize = new Size(minWidth, AutoScrollMinSize.Height);\n        }\n\n        private int RecalcMaxLineLength()\n        {\n            int maxLineLength = 0;\n            TextSource lines = this.lines;\n            int count = lines.Count;\n            int charHeight = CharHeight;\n            int topIndent = Paddings.Top;\n            TextHeight = topIndent;\n\n            for (int i = 0; i < count; i++)\n            {\n                int lineLength = lines.GetLineLength(i);\n                LineInfo lineInfo = LineInfos[i];\n                if (lineLength > maxLineLength && lineInfo.VisibleState == VisibleState.Visible)\n                    maxLineLength = lineLength;\n                lineInfo.startY = TextHeight;\n                TextHeight += lineInfo.WordWrapStringsCount * charHeight + lineInfo.bottomPadding;\n                LineInfos[i] = lineInfo;\n            }\n\n            TextHeight -= topIndent;\n\n            return maxLineLength;\n        }\n\n        private int GetMaxLineWordWrapedWidth()\n        {\n            if (wordWrap)\n                switch (wordWrapMode)\n                {\n                    case WordWrapMode.WordWrapControlWidth:\n                    case WordWrapMode.CharWrapControlWidth:\n                        return ClientSize.Width;\n                    case WordWrapMode.WordWrapPreferredWidth:\n                    case WordWrapMode.CharWrapPreferredWidth:\n                        return LeftIndent + PreferredLineWidth * CharWidth + 2 + Paddings.Left + Paddings.Right;\n                }\n\n            return int.MaxValue;\n        }\n\n        private void RecalcWordWrap(int fromLine, int toLine)\n        {\n            int maxCharsPerLine = 0;\n            bool charWrap = false;\n\n            toLine = Math.Min(LinesCount - 1, toLine);\n\n            switch (WordWrapMode)\n            {\n                case WordWrapMode.WordWrapControlWidth:\n                    maxCharsPerLine = (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right) / CharWidth;\n                    break;\n                case WordWrapMode.CharWrapControlWidth:\n                    maxCharsPerLine = (ClientSize.Width - LeftIndent - Paddings.Left - Paddings.Right) / CharWidth;\n                    charWrap = true;\n                    break;\n                case WordWrapMode.WordWrapPreferredWidth:\n                    maxCharsPerLine = PreferredLineWidth;\n                    break;\n                case WordWrapMode.CharWrapPreferredWidth:\n                    maxCharsPerLine = PreferredLineWidth;\n                    charWrap = true;\n                    break;\n            }\n\n            for (int iLine = fromLine; iLine <= toLine; iLine++)\n                if (lines.IsLineLoaded(iLine))\n                {\n                    if (!wordWrap)\n                        LineInfos[iLine].CutOffPositions.Clear();\n                    else\n                    {\n                        LineInfo li = LineInfos[iLine];\n\n                        li.wordWrapIndent = WordWrapAutoIndent\n                            ? lines[iLine].StartSpacesCount + WordWrapIndent\n                            : WordWrapIndent;\n\n                        if (WordWrapMode == WordWrapMode.Custom)\n                        {\n                            if (WordWrapNeeded != null)\n                                WordWrapNeeded(this,\n                                    new WordWrapNeededEventArgs(li.CutOffPositions, ImeAllowed, lines[iLine]));\n                        }\n                        else\n                            CalcCutOffs(li.CutOffPositions, maxCharsPerLine, maxCharsPerLine - li.wordWrapIndent,\n                                ImeAllowed, charWrap, lines[iLine]);\n\n                        LineInfos[iLine] = li;\n                    }\n                }\n\n            needRecalc = true;\n        }\n\n        /// <summary>\n        /// Calculates wordwrap cutoffs\n        /// </summary>\n        public static void CalcCutOffs(List<int> cutOffPositions, int maxCharsPerLine, int maxCharsPerSecondaryLine,\n            bool allowIME, bool charWrap, Line line)\n        {\n            if (maxCharsPerSecondaryLine < 1) maxCharsPerSecondaryLine = 1;\n            if (maxCharsPerLine < 1) maxCharsPerLine = 1;\n\n            int segmentLength = 0;\n            int cutOff = 0;\n            cutOffPositions.Clear();\n\n            for (int i = 0; i < line.Count - 1; i++)\n            {\n                char c = line[i].c;\n                if (charWrap)\n                {\n                    //char wrapping\n                    cutOff = i + 1;\n                }\n                else\n                {\n                    //word wrapping\n                    if (allowIME && IsCJKLetter(c)) //in CJK languages cutoff can be in any letter\n                    {\n                        cutOff = i;\n                    }\n                    else if (!char.IsLetterOrDigit(c) && c != '_' && c != '\\'' && c != '\\xa0'\n                             && ((c != '.' && c != ',') || !char.IsDigit(line[i + 1].c))) //dot before digit\n                        cutOff = Math.Min(i + 1, line.Count - 1);\n                }\n\n                segmentLength++;\n\n                if (segmentLength == maxCharsPerLine)\n                {\n                    if (cutOff == 0 || (cutOffPositions.Count > 0 &&\n                                        cutOff == cutOffPositions[cutOffPositions.Count - 1]))\n                        cutOff = i + 1;\n                    cutOffPositions.Add(cutOff);\n                    segmentLength = 1 + i - cutOff;\n                    maxCharsPerLine = maxCharsPerSecondaryLine;\n                }\n            }\n        }\n\n        public static bool IsCJKLetter(char c)\n        {\n            int code = Convert.ToInt32(c);\n            return\n                (code >= 0x3300 && code <= 0x33FF) ||\n                (code >= 0xFE30 && code <= 0xFE4F) ||\n                (code >= 0xF900 && code <= 0xFAFF) ||\n                (code >= 0x2E80 && code <= 0x2EFF) ||\n                (code >= 0x31C0 && code <= 0x31EF) ||\n                (code >= 0x4E00 && code <= 0x9FFF) ||\n                (code >= 0x3400 && code <= 0x4DBF) ||\n                (code >= 0x3200 && code <= 0x32FF) ||\n                (code >= 0x2460 && code <= 0x24FF) ||\n                (code >= 0x3040 && code <= 0x309F) ||\n                (code >= 0x2F00 && code <= 0x2FDF) ||\n                (code >= 0x31A0 && code <= 0x31BF) ||\n                (code >= 0x4DC0 && code <= 0x4DFF) ||\n                (code >= 0x3100 && code <= 0x312F) ||\n                (code >= 0x30A0 && code <= 0x30FF) ||\n                (code >= 0x31F0 && code <= 0x31FF) ||\n                (code >= 0x2FF0 && code <= 0x2FFF) ||\n                (code >= 0x1100 && code <= 0x11FF) ||\n                (code >= 0xA960 && code <= 0xA97F) ||\n                (code >= 0xD7B0 && code <= 0xD7FF) ||\n                (code >= 0x3130 && code <= 0x318F) ||\n                (code >= 0xAC00 && code <= 0xD7AF);\n        }\n\n        protected override void OnClientSizeChanged(EventArgs e)\n        {\n            base.OnClientSizeChanged(e);\n            if (WordWrap)\n            {\n                //RecalcWordWrap(0, lines.Count - 1);\n                NeedRecalc(false, true);\n                Invalidate();\n            }\n\n            OnVisibleRangeChanged();\n            UpdateScrollbars();\n        }\n\n        /// <summary>\n        /// Scroll control for display defined rectangle\n        /// </summary>\n        /// <param name=\"rect\"></param>\n        internal void DoVisibleRectangle(Rectangle rect)\n        {\n            HideHints();\n\n            int oldV = VerticalScroll.Value;\n            int v = VerticalScroll.Value;\n            int h = HorizontalScroll.Value;\n\n            if (rect.Bottom > ClientRectangle.Height)\n                v += rect.Bottom - ClientRectangle.Height;\n            else if (rect.Top < 0)\n                v += rect.Top;\n\n            if (rect.Right > ClientRectangle.Width)\n                h += rect.Right - ClientRectangle.Width;\n            else if (rect.Left < LeftIndent)\n                h += rect.Left - LeftIndent;\n            //\n            if (!Multiline)\n                v = 0;\n            //\n            v = Math.Max(VerticalScroll.Minimum, v); // was 0\n            h = Math.Max(HorizontalScroll.Minimum, h); // was 0\n            //\n            try\n            {\n                if (VerticalScroll.Visible || !ShowScrollBars)\n                    VerticalScroll.Value = Math.Min(v, VerticalScroll.Maximum);\n                if (HorizontalScroll.Visible || !ShowScrollBars)\n                    HorizontalScroll.Value = Math.Min(h, HorizontalScroll.Maximum);\n            }\n            catch (ArgumentOutOfRangeException)\n            {\n                ;\n            }\n\n            UpdateScrollbars();\n            //\n            RestoreHints();\n            //\n            if (oldV != VerticalScroll.Value)\n                OnVisibleRangeChanged();\n        }\n\n        /// <summary>\n        /// Updates scrollbar position after Value changed\n        /// </summary>\n        public void UpdateScrollbars()\n        {\n            if (ShowScrollBars)\n            {\n                //some magic for update scrolls\n                base.AutoScrollMinSize -= new Size(1, 0);\n                base.AutoScrollMinSize += new Size(1, 0);\n            }\n            else\n                PerformLayout();\n\n            if (IsHandleCreated)\n                BeginInvoke((MethodInvoker) OnScrollbarsUpdated);\n        }\n\n        protected virtual void OnScrollbarsUpdated()\n        {\n            if (ScrollbarsUpdated != null)\n                ScrollbarsUpdated(this, EventArgs.Empty);\n        }\n\n        /// <summary>\n        /// Scroll control for display caret\n        /// </summary>\n        public void DoCaretVisible()\n        {\n            Invalidate();\n            Recalc();\n            Point car = PlaceToPoint(Selection.Start);\n            car.Offset(-CharWidth, 0);\n            DoVisibleRectangle(new Rectangle(car, new Size(2 * CharWidth, 2 * CharHeight)));\n        }\n\n        /// <summary>\n        /// Scroll control left\n        /// </summary>\n        public void ScrollLeft()\n        {\n            Invalidate();\n            HorizontalScroll.Value = 0;\n            AutoScrollMinSize -= new Size(1, 0);\n            AutoScrollMinSize += new Size(1, 0);\n        }\n\n        /// <summary>\n        /// Scroll control for display selection area\n        /// </summary>\n        public void DoSelectionVisible()\n        {\n            if (LineInfos[Selection.End.iLine].VisibleState != VisibleState.Visible)\n                ExpandBlock(Selection.End.iLine);\n\n            if (LineInfos[Selection.Start.iLine].VisibleState != VisibleState.Visible)\n                ExpandBlock(Selection.Start.iLine);\n\n            Recalc();\n            DoVisibleRectangle(new Rectangle(PlaceToPoint(new Place(0, Selection.End.iLine)),\n                new Size(2 * CharWidth, 2 * CharHeight)));\n\n            Point car = PlaceToPoint(Selection.Start);\n            Point car2 = PlaceToPoint(Selection.End);\n            car.Offset(-CharWidth, -ClientSize.Height / 2);\n            DoVisibleRectangle(new Rectangle(car, new Size(Math.Abs(car2.X - car.X), ClientSize.Height)));\n            //Math.Abs(car2.Y-car.Y) + 2 * CharHeight\n\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Scroll control for display given range\n        /// </summary>\n        public void DoRangeVisible(Range range)\n        {\n            DoRangeVisible(range, false);\n        }\n\n        /// <summary>\n        /// Scroll control for display given range\n        /// </summary>\n        public void DoRangeVisible(Range range, bool tryToCentre)\n        {\n            range = range.Clone();\n            range.Normalize();\n            range.End = new Place(range.End.iChar,\n                Math.Min(range.End.iLine, range.Start.iLine + ClientSize.Height / CharHeight));\n\n            if (LineInfos[range.End.iLine].VisibleState != VisibleState.Visible)\n                ExpandBlock(range.End.iLine);\n\n            if (LineInfos[range.Start.iLine].VisibleState != VisibleState.Visible)\n                ExpandBlock(range.Start.iLine);\n\n            Recalc();\n            int h = (1 + range.End.iLine - range.Start.iLine) * CharHeight;\n            Point p = PlaceToPoint(new Place(0, range.Start.iLine));\n            if (tryToCentre)\n            {\n                p.Offset(0, -ClientSize.Height / 2);\n                h = ClientSize.Height;\n            }\n\n            DoVisibleRectangle(new Rectangle(p, new Size(2 * CharWidth, h)));\n\n            Invalidate();\n        }\n\n\n        protected override void OnKeyUp(KeyEventArgs e)\n        {\n            base.OnKeyUp(e);\n\n            if (e.KeyCode == Keys.ShiftKey)\n                lastModifiers &= ~Keys.Shift;\n            if (e.KeyCode == Keys.Alt)\n                lastModifiers &= ~Keys.Alt;\n            if (e.KeyCode == Keys.ControlKey)\n                lastModifiers &= ~Keys.Control;\n        }\n\n\n        bool findCharMode;\n\n        protected override void OnKeyDown(KeyEventArgs e)\n        {\n            if (middleClickScrollingActivated)\n                return;\n\n            base.OnKeyDown(e);\n\n            if (Focused) //??? \n                lastModifiers = e.Modifiers;\n\n            handledChar = false;\n\n            if (e.Handled)\n            {\n                handledChar = true;\n                return;\n            }\n\n            if (ProcessKey(e.KeyData))\n                return;\n\n            e.Handled = true;\n\n            DoCaretVisible();\n            Invalidate();\n        }\n\n        protected override bool ProcessDialogKey(Keys keyData)\n        {\n            if ((keyData & Keys.Alt) > 0)\n            {\n                if (HotkeysMapping.ContainsKey(keyData))\n                {\n                    ProcessKey(keyData);\n                    return true;\n                }\n            }\n\n            return base.ProcessDialogKey(keyData);\n        }\n\n        static Dictionary<FCTBAction, bool> scrollActions = new Dictionary<FCTBAction, bool>()\n        {\n            {FCTBAction.ScrollDown, true}, {FCTBAction.ScrollUp, true}, {FCTBAction.ZoomOut, true},\n            {FCTBAction.ZoomIn, true}, {FCTBAction.ZoomNormal, true}\n        };\n\n        /// <summary>\n        /// Process control keys\n        /// </summary>\n        public virtual bool ProcessKey(Keys keyData)\n        {\n            KeyEventArgs a = new KeyEventArgs(keyData);\n\n            if (a.KeyCode == Keys.Tab && !AcceptsTab)\n                return false;\n\n\n            if (macrosManager != null)\n                if (!HotkeysMapping.ContainsKey(keyData) ||\n                    (HotkeysMapping[keyData] != FCTBAction.MacroExecute &&\n                     HotkeysMapping[keyData] != FCTBAction.MacroRecord))\n                    macrosManager.ProcessKey(keyData);\n\n            if (HotkeysMapping.ContainsKey(keyData))\n            {\n                var act = HotkeysMapping[keyData];\n                DoAction(act);\n                if (scrollActions.ContainsKey(act))\n                    return true;\n                if (keyData == Keys.Tab || keyData == (Keys.Tab | Keys.Shift))\n                {\n                    handledChar = true;\n                    return true;\n                }\n            }\n            else\n            {\n                //\n                if (a.KeyCode == Keys.Alt)\n                    return true;\n\n                if ((a.Modifiers & Keys.Control) != 0)\n                    return true;\n\n                if ((a.Modifiers & Keys.Alt) != 0)\n                {\n                    if ((MouseButtons & MouseButtons.Left) != 0)\n                        CheckAndChangeSelectionType();\n                    return true;\n                }\n\n                if (a.KeyCode == Keys.ShiftKey)\n                    return true;\n            }\n\n            return false;\n        }\n\n        private void DoAction(FCTBAction action)\n        {\n            switch (action)\n            {\n                case FCTBAction.ZoomIn:\n                    ChangeFontSize(2);\n                    break;\n                case FCTBAction.ZoomOut:\n                    ChangeFontSize(-2);\n                    break;\n                case FCTBAction.ZoomNormal:\n                    RestoreFontSize();\n                    break;\n                case FCTBAction.ScrollDown:\n                    DoScrollVertical(1, -1);\n                    break;\n\n                case FCTBAction.ScrollUp:\n                    DoScrollVertical(1, 1);\n                    break;\n\n                case FCTBAction.GoToDialog:\n                    ShowGoToDialog();\n                    break;\n\n                case FCTBAction.FindDialog:\n                    ShowFindDialog();\n                    break;\n\n                case FCTBAction.FindChar:\n                    findCharMode = true;\n                    break;\n\n                case FCTBAction.FindNext:\n                    if (findForm == null || findForm.tbFind.Text == \"\")\n                        ShowFindDialog();\n                    else\n                        findForm.FindNext(findForm.tbFind.Text);\n                    break;\n\n                case FCTBAction.ReplaceDialog:\n                    ShowReplaceDialog();\n                    break;\n\n                case FCTBAction.Copy:\n                    Copy();\n                    break;\n\n                case FCTBAction.CommentSelected:\n                    CommentSelected();\n                    break;\n\n                case FCTBAction.Cut:\n                    if (!Selection.ReadOnly)\n                        Cut();\n                    break;\n\n                case FCTBAction.Paste:\n                    if (!Selection.ReadOnly)\n                        Paste();\n                    break;\n\n                case FCTBAction.SelectAll:\n                    Selection.SelectAll();\n                    break;\n\n                case FCTBAction.Undo:\n                    if (!ReadOnly)\n                        Undo();\n                    break;\n\n                case FCTBAction.Redo:\n                    if (!ReadOnly)\n                        Redo();\n                    break;\n\n                case FCTBAction.LowerCase:\n                    if (!Selection.ReadOnly)\n                        LowerCase();\n                    break;\n\n                case FCTBAction.UpperCase:\n                    if (!Selection.ReadOnly)\n                        UpperCase();\n                    break;\n\n                case FCTBAction.IndentDecrease:\n                    if (!Selection.ReadOnly)\n                    {\n                        var sel = Selection.Clone();\n                        if (sel.Start.iLine == sel.End.iLine)\n                        {\n                            var line = this[sel.Start.iLine];\n                            if (sel.Start.iChar == 0 && sel.End.iChar == line.Count)\n                                Selection = new Range(this, line.StartSpacesCount, sel.Start.iLine, line.Count,\n                                    sel.Start.iLine);\n                            else if (sel.Start.iChar == line.Count && sel.End.iChar == 0)\n                                Selection = new Range(this, line.Count, sel.Start.iLine, line.StartSpacesCount,\n                                    sel.Start.iLine);\n                        }\n\n\n                        DecreaseIndent();\n                    }\n\n                    break;\n\n                case FCTBAction.IndentIncrease:\n                    if (!Selection.ReadOnly)\n                    {\n                        var sel = Selection.Clone();\n                        var inverted = sel.Start > sel.End;\n                        sel.Normalize();\n                        var spaces = this[sel.Start.iLine].StartSpacesCount;\n                        if (sel.Start.iLine != sel.End.iLine || //selected several lines\n                            (sel.Start.iChar <= spaces &&\n                             sel.End.iChar == this[sel.Start.iLine].Count) || //selected whole line\n                            sel.End.iChar <= spaces) //selected space prefix\n                        {\n                            IncreaseIndent();\n                            if (sel.Start.iLine == sel.End.iLine && !sel.IsEmpty)\n                            {\n                                Selection = new Range(this, this[sel.Start.iLine].StartSpacesCount, sel.End.iLine,\n                                    this[sel.Start.iLine].Count, sel.End.iLine); //select whole line\n                                if (inverted)\n                                    Selection.Inverse();\n                            }\n                        }\n                        else\n                            ProcessKey('\\t', Keys.None);\n                    }\n\n                    break;\n\n                case FCTBAction.AutoIndentChars:\n                    if (!Selection.ReadOnly)\n                        DoAutoIndentChars(Selection.Start.iLine);\n                    break;\n\n                case FCTBAction.NavigateBackward:\n                    NavigateBackward();\n                    break;\n\n                case FCTBAction.NavigateForward:\n                    NavigateForward();\n                    break;\n\n                case FCTBAction.UnbookmarkLine:\n                    UnbookmarkLine(Selection.Start.iLine);\n                    break;\n\n                case FCTBAction.BookmarkLine:\n                    BookmarkLine(Selection.Start.iLine);\n                    break;\n\n                case FCTBAction.GoNextBookmark:\n                    GotoNextBookmark(Selection.Start.iLine);\n                    break;\n\n                case FCTBAction.GoPrevBookmark:\n                    GotoPrevBookmark(Selection.Start.iLine);\n                    break;\n\n                case FCTBAction.ClearWordLeft:\n                    if (OnKeyPressing('\\b')) //KeyPress event processed key\n                        break;\n                    if (!Selection.ReadOnly)\n                    {\n                        if (!Selection.IsEmpty)\n                            ClearSelected();\n                        Selection.GoWordLeft(true);\n                        if (!Selection.ReadOnly)\n                            ClearSelected();\n                    }\n\n                    OnKeyPressed('\\b');\n                    break;\n\n                case FCTBAction.ReplaceMode:\n                    if (!ReadOnly)\n                        isReplaceMode = !isReplaceMode;\n                    break;\n\n                case FCTBAction.DeleteCharRight:\n                    if (!Selection.ReadOnly)\n                    {\n                        if (OnKeyPressing((char) 0xff)) //KeyPress event processed key\n                            break;\n                        if (!Selection.IsEmpty)\n                            ClearSelected();\n                        else\n                        {\n                            //if line contains only spaces then delete line\n                            if (this[Selection.Start.iLine].StartSpacesCount == this[Selection.Start.iLine].Count)\n                                RemoveSpacesAfterCaret();\n\n                            if (!Selection.IsReadOnlyRightChar())\n                                if (Selection.GoRightThroughFolded())\n                                {\n                                    int iLine = Selection.Start.iLine;\n\n                                    InsertChar('\\b');\n\n                                    //if removed \\n then trim spaces\n                                    if (iLine != Selection.Start.iLine && AutoIndent)\n                                        if (Selection.Start.iChar > 0)\n                                            RemoveSpacesAfterCaret();\n                                }\n                        }\n\n                        if (AutoIndentChars)\n                            DoAutoIndentChars(Selection.Start.iLine);\n\n                        OnKeyPressed((char) 0xff);\n                    }\n\n                    break;\n\n                case FCTBAction.ClearWordRight:\n                    if (OnKeyPressing((char) 0xff)) //KeyPress event processed key\n                        break;\n                    if (!Selection.ReadOnly)\n                    {\n                        if (!Selection.IsEmpty)\n                            ClearSelected();\n                        Selection.GoWordRight(true);\n                        if (!Selection.ReadOnly)\n                            ClearSelected();\n                    }\n\n                    OnKeyPressed((char) 0xff);\n                    break;\n\n                case FCTBAction.GoWordLeft:\n                    Selection.GoWordLeft(false);\n                    break;\n\n                case FCTBAction.GoWordLeftWithSelection:\n                    Selection.GoWordLeft(true);\n                    break;\n\n                case FCTBAction.GoLeft:\n                    Selection.GoLeft(false);\n                    break;\n\n                case FCTBAction.GoLeftWithSelection:\n                    Selection.GoLeft(true);\n                    break;\n\n                case FCTBAction.GoLeft_ColumnSelectionMode:\n                    CheckAndChangeSelectionType();\n                    if (Selection.ColumnSelectionMode)\n                        Selection.GoLeft_ColumnSelectionMode();\n                    Invalidate();\n                    break;\n\n                case FCTBAction.GoWordRight:\n                    Selection.GoWordRight(false, true);\n                    break;\n\n                case FCTBAction.GoWordRightWithSelection:\n                    Selection.GoWordRight(true, true);\n                    break;\n\n                case FCTBAction.GoRight:\n                    Selection.GoRight(false);\n                    break;\n\n                case FCTBAction.GoRightWithSelection:\n                    Selection.GoRight(true);\n                    break;\n\n                case FCTBAction.GoRight_ColumnSelectionMode:\n                    CheckAndChangeSelectionType();\n                    if (Selection.ColumnSelectionMode)\n                        Selection.GoRight_ColumnSelectionMode();\n                    Invalidate();\n                    break;\n\n                case FCTBAction.GoUp:\n                    Selection.GoUp(false);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoUpWithSelection:\n                    Selection.GoUp(true);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoUp_ColumnSelectionMode:\n                    CheckAndChangeSelectionType();\n                    if (Selection.ColumnSelectionMode)\n                        Selection.GoUp_ColumnSelectionMode();\n                    Invalidate();\n                    break;\n\n                case FCTBAction.MoveSelectedLinesUp:\n                    if (!Selection.ColumnSelectionMode)\n                        MoveSelectedLinesUp();\n                    break;\n\n                case FCTBAction.GoDown:\n                    Selection.GoDown(false);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoDownWithSelection:\n                    Selection.GoDown(true);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoDown_ColumnSelectionMode:\n                    CheckAndChangeSelectionType();\n                    if (Selection.ColumnSelectionMode)\n                        Selection.GoDown_ColumnSelectionMode();\n                    Invalidate();\n                    break;\n\n                case FCTBAction.MoveSelectedLinesDown:\n                    if (!Selection.ColumnSelectionMode)\n                        MoveSelectedLinesDown();\n                    break;\n                case FCTBAction.GoPageUp:\n                    Selection.GoPageUp(false);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoPageUpWithSelection:\n                    Selection.GoPageUp(true);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoPageDown:\n                    Selection.GoPageDown(false);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoPageDownWithSelection:\n                    Selection.GoPageDown(true);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoFirstLine:\n                    Selection.GoFirst(false);\n                    break;\n\n                case FCTBAction.GoFirstLineWithSelection:\n                    Selection.GoFirst(true);\n                    break;\n\n                case FCTBAction.GoHome:\n                    GoHome(false);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoHomeWithSelection:\n                    GoHome(true);\n                    ScrollLeft();\n                    break;\n\n                case FCTBAction.GoLastLine:\n                    Selection.GoLast(false);\n                    break;\n\n                case FCTBAction.GoLastLineWithSelection:\n                    Selection.GoLast(true);\n                    break;\n\n                case FCTBAction.GoEnd:\n                    Selection.GoEnd(false);\n                    break;\n\n                case FCTBAction.GoEndWithSelection:\n                    Selection.GoEnd(true);\n                    break;\n\n                case FCTBAction.ClearHints:\n                    ClearHints();\n                    if (MacrosManager != null)\n                        MacrosManager.IsRecording = false;\n                    break;\n\n                case FCTBAction.MacroRecord:\n                    if (MacrosManager != null)\n                    {\n                        if (MacrosManager.AllowMacroRecordingByUser)\n                            MacrosManager.IsRecording = !MacrosManager.IsRecording;\n                        if (MacrosManager.IsRecording)\n                            MacrosManager.ClearMacros();\n                    }\n\n                    break;\n\n                case FCTBAction.MacroExecute:\n                    if (MacrosManager != null)\n                    {\n                        MacrosManager.IsRecording = false;\n                        MacrosManager.ExecuteMacros();\n                    }\n\n                    break;\n                case FCTBAction.CustomAction1:\n                case FCTBAction.CustomAction2:\n                case FCTBAction.CustomAction3:\n                case FCTBAction.CustomAction4:\n                case FCTBAction.CustomAction5:\n                case FCTBAction.CustomAction6:\n                case FCTBAction.CustomAction7:\n                case FCTBAction.CustomAction8:\n                case FCTBAction.CustomAction9:\n                case FCTBAction.CustomAction10:\n                case FCTBAction.CustomAction11:\n                case FCTBAction.CustomAction12:\n                case FCTBAction.CustomAction13:\n                case FCTBAction.CustomAction14:\n                case FCTBAction.CustomAction15:\n                case FCTBAction.CustomAction16:\n                case FCTBAction.CustomAction17:\n                case FCTBAction.CustomAction18:\n                case FCTBAction.CustomAction19:\n                case FCTBAction.CustomAction20:\n                    OnCustomAction(new CustomActionEventArgs(action));\n                    break;\n            }\n        }\n\n        protected virtual void OnCustomAction(CustomActionEventArgs e)\n        {\n            if (CustomAction != null)\n                CustomAction(this, e);\n        }\n\n        Font originalFont;\n\n        private void RestoreFontSize()\n        {\n            Zoom = 100;\n        }\n\n        /// <summary>\n        /// Scrolls to nearest bookmark or to first bookmark\n        /// </summary>\n        /// <param name=\"iLine\">Current bookmark line index</param>\n        public bool GotoNextBookmark(int iLine)\n        {\n            Bookmark nearestBookmark = null;\n            int minNextLineIndex = int.MaxValue;\n            Bookmark minBookmark = null;\n            int minLineIndex = int.MaxValue;\n            foreach (Bookmark bookmark in bookmarks)\n            {\n                if (bookmark.LineIndex < minLineIndex)\n                {\n                    minLineIndex = bookmark.LineIndex;\n                    minBookmark = bookmark;\n                }\n\n                if (bookmark.LineIndex > iLine && bookmark.LineIndex < minNextLineIndex)\n                {\n                    minNextLineIndex = bookmark.LineIndex;\n                    nearestBookmark = bookmark;\n                }\n            }\n\n            if (nearestBookmark != null)\n            {\n                nearestBookmark.DoVisible();\n                return true;\n            }\n            else if (minBookmark != null)\n            {\n                minBookmark.DoVisible();\n                return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Scrolls to nearest previous bookmark or to last bookmark\n        /// </summary>\n        /// <param name=\"iLine\">Current bookmark line index</param>\n        public bool GotoPrevBookmark(int iLine)\n        {\n            Bookmark nearestBookmark = null;\n            int maxPrevLineIndex = -1;\n            Bookmark maxBookmark = null;\n            int maxLineIndex = -1;\n            foreach (Bookmark bookmark in bookmarks)\n            {\n                if (bookmark.LineIndex > maxLineIndex)\n                {\n                    maxLineIndex = bookmark.LineIndex;\n                    maxBookmark = bookmark;\n                }\n\n                if (bookmark.LineIndex < iLine && bookmark.LineIndex > maxPrevLineIndex)\n                {\n                    maxPrevLineIndex = bookmark.LineIndex;\n                    nearestBookmark = bookmark;\n                }\n            }\n\n            if (nearestBookmark != null)\n            {\n                nearestBookmark.DoVisible();\n                return true;\n            }\n            else if (maxBookmark != null)\n            {\n                maxBookmark.DoVisible();\n                return true;\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Bookmarks line\n        /// </summary>\n        public virtual void BookmarkLine(int iLine)\n        {\n            if (!bookmarks.Contains(iLine))\n                bookmarks.Add(iLine);\n        }\n\n        /// <summary>\n        /// Unbookmarks current line\n        /// </summary>\n        public virtual void UnbookmarkLine(int iLine)\n        {\n            bookmarks.Remove(iLine);\n        }\n\n        /// <summary>\n        /// Moves selected lines down\n        /// </summary>\n        public virtual void MoveSelectedLinesDown()\n        {\n            Range prevSelection = Selection.Clone();\n            Selection.Expand();\n            if (!Selection.ReadOnly)\n            {\n                int iLine = Selection.Start.iLine;\n                if (Selection.End.iLine >= LinesCount - 1)\n                {\n                    Selection = prevSelection;\n                    return;\n                }\n\n                string text = SelectedText;\n                var temp = new List<int>();\n                for (int i = Selection.Start.iLine; i <= Selection.End.iLine; i++)\n                    temp.Add(i);\n                RemoveLines(temp);\n                Selection.Start = new Place(GetLineLength(iLine), iLine);\n                SelectedText = \"\\n\" + text;\n                Selection.Start = new Place(prevSelection.Start.iChar, prevSelection.Start.iLine + 1);\n                Selection.End = new Place(prevSelection.End.iChar, prevSelection.End.iLine + 1);\n            }\n            else\n                Selection = prevSelection;\n        }\n\n        /// <summary>\n        /// Moves selected lines up\n        /// </summary>\n        public virtual void MoveSelectedLinesUp()\n        {\n            Range prevSelection = Selection.Clone();\n            Selection.Expand();\n            if (!Selection.ReadOnly)\n            {\n                int iLine = Selection.Start.iLine;\n                if (iLine == 0)\n                {\n                    Selection = prevSelection;\n                    return;\n                }\n\n                string text = SelectedText;\n                var temp = new List<int>();\n                for (int i = Selection.Start.iLine; i <= Selection.End.iLine; i++)\n                    temp.Add(i);\n                RemoveLines(temp);\n                Selection.Start = new Place(0, iLine - 1);\n                SelectedText = text + \"\\n\";\n                Selection.Start = new Place(prevSelection.Start.iChar, prevSelection.Start.iLine - 1);\n                Selection.End = new Place(prevSelection.End.iChar, prevSelection.End.iLine - 1);\n            }\n            else\n                Selection = prevSelection;\n        }\n\n        private void GoHome(bool shift)\n        {\n            Selection.BeginUpdate();\n            try\n            {\n                int iLine = Selection.Start.iLine;\n                int spaces = this[iLine].StartSpacesCount;\n                if (Selection.Start.iChar <= spaces)\n                    Selection.GoHome(shift);\n                else\n                {\n                    Selection.GoHome(shift);\n                    for (int i = 0; i < spaces; i++)\n                        Selection.GoRight(shift);\n                }\n            }\n            finally\n            {\n                Selection.EndUpdate();\n            }\n        }\n\n        /// <summary>\n        /// Convert selected text to upper case\n        /// </summary>\n        public virtual void UpperCase()\n        {\n            Range old = Selection.Clone();\n            SelectedText = SelectedText.ToUpper();\n            Selection.Start = old.Start;\n            Selection.End = old.End;\n        }\n\n        /// <summary>\n        /// Convert selected text to lower case\n        /// </summary>\n        public virtual void LowerCase()\n        {\n            Range old = Selection.Clone();\n            SelectedText = SelectedText.ToLower();\n            Selection.Start = old.Start;\n            Selection.End = old.End;\n        }\n\n        /// <summary>\n        /// Convert selected text to title case\n        /// </summary>\n        public virtual void TitleCase()\n        {\n            Range old = Selection.Clone();\n            SelectedText = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(SelectedText.ToLower());\n            Selection.Start = old.Start;\n            Selection.End = old.End;\n        }\n\n        /// <summary>\n        /// Convert selected text to sentence case\n        /// </summary>\n        public virtual void SentenceCase()\n        {\n            Range old = Selection.Clone();\n            var lowerCase = SelectedText.ToLower();\n            var r = new Regex(@\"(^\\S)|[\\.\\?!:]\\s+(\\S)\", RegexOptions.ExplicitCapture);\n            SelectedText = r.Replace(lowerCase, s => s.Value.ToUpper());\n            Selection.Start = old.Start;\n            Selection.End = old.End;\n        }\n\n        /// <summary>\n        /// Insert/remove comment prefix into selected lines\n        /// </summary>\n        public void CommentSelected()\n        {\n            CommentSelected(CommentPrefix);\n        }\n\n        /// <summary>\n        /// Insert/remove comment prefix into selected lines\n        /// </summary>\n        public virtual void CommentSelected(string commentPrefix)\n        {\n            if (string.IsNullOrEmpty(commentPrefix))\n                return;\n            Selection.Normalize();\n            bool isCommented = lines[Selection.Start.iLine].Text.TrimStart().StartsWith(commentPrefix);\n            if (isCommented)\n                RemoveLinePrefix(commentPrefix);\n            else\n                InsertLinePrefix(commentPrefix);\n        }\n\n        public void OnKeyPressing(KeyPressEventArgs args)\n        {\n            if (KeyPressing != null)\n                KeyPressing(this, args);\n        }\n\n        private bool OnKeyPressing(char c)\n        {\n            if (findCharMode)\n            {\n                findCharMode = false;\n                FindChar(c);\n                return true;\n            }\n\n            var args = new KeyPressEventArgs(c);\n            OnKeyPressing(args);\n            return args.Handled;\n        }\n\n        public void OnKeyPressed(char c)\n        {\n            var args = new KeyPressEventArgs(c);\n            if (KeyPressed != null)\n                KeyPressed(this, args);\n        }\n\n        protected override bool ProcessMnemonic(char charCode)\n        {\n            if (middleClickScrollingActivated)\n                return false;\n\n            if (Focused)\n                return ProcessKey(charCode, lastModifiers) || base.ProcessMnemonic(charCode);\n            else\n                return false;\n        }\n\n        const int WM_CHAR = 0x102;\n\n        protected override bool ProcessKeyMessage(ref Message m)\n        {\n            if (m.Msg == WM_CHAR)\n                ProcessMnemonic(Convert.ToChar(m.WParam.ToInt32()));\n\n            return base.ProcessKeyMessage(ref m);\n        }\n\n        /// <summary>\n        /// Process \"real\" keys (no control)\n        /// </summary>\n        public virtual bool ProcessKey(char c, Keys modifiers)\n        {\n            if (handledChar)\n                return true;\n\n            if (macrosManager != null)\n                macrosManager.ProcessKey(c, modifiers);\n            /*  !!!!\n            if (c == ' ')\n                return true;*/\n\n            //backspace\n            if (c == '\\b' && (modifiers == Keys.None || modifiers == Keys.Shift || (modifiers & Keys.Alt) != 0))\n            {\n                if (ReadOnly || !Enabled)\n                    return false;\n\n                if (OnKeyPressing(c))\n                    return true;\n\n                if (Selection.ReadOnly)\n                    return false;\n\n                if (!Selection.IsEmpty)\n                    ClearSelected();\n                else if (!Selection.IsReadOnlyLeftChar()) //is not left char readonly?\n                    InsertChar('\\b');\n\n                if (AutoIndentChars)\n                    DoAutoIndentChars(Selection.Start.iLine);\n\n                OnKeyPressed('\\b');\n                return true;\n            }\n\n            /* !!!!\n            if (c == '\\b' && (modifiers & Keys.Alt) != 0)\n                return true;*/\n\n            if (char.IsControl(c) && c != '\\r' && c != '\\t')\n                return false;\n\n            if (ReadOnly || !Enabled)\n                return false;\n\n\n            if (modifiers != Keys.None &&\n                modifiers != Keys.Shift &&\n                modifiers != (Keys.Control | Keys.Alt) && //ALT+CTRL is special chars (AltGr)\n                modifiers != (Keys.Shift | Keys.Control | Keys.Alt) && //SHIFT + ALT + CTRL is special chars (AltGr)\n                (modifiers != (Keys.Alt) || char.IsLetterOrDigit(c)) //may be ALT+LetterOrDigit is mnemonic code\n            )\n                return false; //do not process Ctrl+? and Alt+? keys\n\n            char sourceC = c;\n            if (OnKeyPressing(sourceC)) //KeyPress event processed key\n                return true;\n\n            //\n            if (Selection.ReadOnly)\n                return false;\n            //\n            if (c == '\\r' && !AcceptsReturn)\n                return false;\n\n            //replace \\r on \\n\n            if (c == '\\r')\n                c = '\\n';\n            //replace mode? select forward char\n            if (IsReplaceMode)\n            {\n                Selection.GoRight(true);\n                Selection.Inverse();\n            }\n\n            //insert char\n            if (!Selection.ReadOnly)\n            {\n                if (!DoAutocompleteBrackets(c))\n                    InsertChar(c);\n            }\n\n            //do autoindent\n            if (c == '\\n' || AutoIndentExistingLines)\n                DoAutoIndentIfNeed();\n\n            if (AutoIndentChars)\n                DoAutoIndentChars(Selection.Start.iLine);\n\n            DoCaretVisible();\n            Invalidate();\n\n            OnKeyPressed(sourceC);\n\n            return true;\n        }\n\n        #region AutoIndentChars\n\n        /// <summary>\n        /// Enables AutoIndentChars mode\n        /// </summary>\n        [Description(\"Enables AutoIndentChars mode\")]\n        [DefaultValue(true)]\n        public bool AutoIndentChars { get; set; }\n\n        /// <summary>\n        /// Regex patterns for AutoIndentChars (one regex per line)\n        /// </summary>\n        [Description(\"Regex patterns for AutoIndentChars (one regex per line)\")]\n        [Editor(\n            \"System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\",\n            typeof(UITypeEditor))]\n        [DefaultValue(@\"^\\s*[\\w\\.]+\\s*(?<range>=)\\s*(?<range>[^;]+);\")]\n        public string AutoIndentCharsPatterns { get; set; }\n\n        /// <summary>\n        /// Do AutoIndentChars\n        /// </summary>\n        public void DoAutoIndentChars(int iLine)\n        {\n            var patterns =\n                AutoIndentCharsPatterns.Split(new char[] {'\\r', '\\n'}, StringSplitOptions.RemoveEmptyEntries);\n\n            foreach (var pattern in patterns)\n            {\n                var m = Regex.Match(this[iLine].Text, pattern);\n                if (m.Success)\n                {\n                    DoAutoIndentChars(iLine, new Regex(pattern));\n                    break;\n                }\n            }\n        }\n\n        protected void DoAutoIndentChars(int iLine, Regex regex)\n        {\n            var oldSel = Selection.Clone();\n\n            var captures = new SortedDictionary<int, CaptureCollection>();\n            var texts = new SortedDictionary<int, string>();\n            var maxCapturesCount = 0;\n\n            var spaces = this[iLine].StartSpacesCount;\n\n            for (var i = iLine; i >= 0; i--)\n            {\n                if (spaces != this[i].StartSpacesCount)\n                    break;\n\n                var text = this[i].Text;\n                var m = regex.Match(text);\n                if (m.Success)\n                {\n                    captures[i] = m.Groups[\"range\"].Captures;\n                    texts[i] = text;\n\n                    if (captures[i].Count > maxCapturesCount)\n                        maxCapturesCount = captures[i].Count;\n                }\n                else\n                    break;\n            }\n\n            for (var i = iLine + 1; i < LinesCount; i++)\n            {\n                if (spaces != this[i].StartSpacesCount)\n                    break;\n\n                var text = this[i].Text;\n                var m = regex.Match(text);\n                if (m.Success)\n                {\n                    captures[i] = m.Groups[\"range\"].Captures;\n                    texts[i] = text;\n\n                    if (captures[i].Count > maxCapturesCount)\n                        maxCapturesCount = captures[i].Count;\n                }\n                else\n                    break;\n            }\n\n            var changed = new Dictionary<int, bool>();\n            var was = false;\n\n            for (int iCapture = maxCapturesCount - 1; iCapture >= 0; iCapture--)\n            {\n                //find max dist\n                var maxDist = 0;\n                foreach (var i in captures.Keys)\n                {\n                    var caps = captures[i];\n                    if (caps.Count <= iCapture)\n                        continue;\n                    var dist = 0;\n                    var cap = caps[iCapture];\n\n                    var index = cap.Index;\n\n                    var text = texts[i];\n                    while (index > 0 && text[index - 1] == ' ') index--;\n\n                    if (iCapture == 0)\n                        dist = index;\n                    else\n                        dist = index - caps[iCapture - 1].Index - 1;\n\n                    if (dist > maxDist)\n                        maxDist = dist;\n                }\n\n                //insert whitespaces\n                foreach (var i in new List<int>(texts.Keys))\n                {\n                    if (captures[i].Count <= iCapture)\n                        continue;\n\n                    var dist = 0;\n                    var cap = captures[i][iCapture];\n\n                    if (iCapture == 0)\n                        dist = cap.Index;\n                    else\n                        dist = cap.Index - captures[i][iCapture - 1].Index - 1;\n\n                    var addSpaces = maxDist - dist + 1; //+1 because min space count is 1\n\n                    if (addSpaces == 0)\n                        continue;\n\n                    if (oldSel.Start.iLine == i && oldSel.Start.iChar > cap.Index)\n                        oldSel.Start = new Place(oldSel.Start.iChar + addSpaces, i);\n\n                    if (addSpaces > 0)\n                        texts[i] = texts[i].Insert(cap.Index, new string(' ', addSpaces));\n                    else\n                        texts[i] = texts[i].Remove(cap.Index + addSpaces, -addSpaces);\n\n                    changed[i] = true;\n                    was = true;\n                }\n            }\n\n            //insert text\n            if (was)\n            {\n                Selection.BeginUpdate();\n                BeginAutoUndo();\n                BeginUpdate();\n\n                TextSource.Manager.ExecuteCommand(new SelectCommand(TextSource));\n\n                foreach (var i in texts.Keys)\n                    if (changed.ContainsKey(i))\n                    {\n                        Selection = new Range(this, 0, i, this[i].Count, i);\n                        if (!Selection.ReadOnly)\n                            InsertText(texts[i]);\n                    }\n\n                Selection = oldSel;\n\n                EndUpdate();\n                EndAutoUndo();\n                Selection.EndUpdate();\n            }\n        }\n\n        #endregion\n\n        private bool DoAutocompleteBrackets(char c)\n        {\n            if (AutoCompleteBrackets)\n            {\n                if (!Selection.ColumnSelectionMode)\n                    for (int i = 1; i < autoCompleteBracketsList.Length; i += 2)\n                        if (c == autoCompleteBracketsList[i] && c == Selection.CharAfterStart)\n                        {\n                            Selection.GoRight();\n                            return true;\n                        }\n\n                for (int i = 0; i < autoCompleteBracketsList.Length; i += 2)\n                    if (c == autoCompleteBracketsList[i])\n                    {\n                        InsertBrackets(autoCompleteBracketsList[i], autoCompleteBracketsList[i + 1]);\n                        return true;\n                    }\n            }\n\n            return false;\n        }\n\n        private bool InsertBrackets(char left, char right)\n        {\n            if (Selection.ColumnSelectionMode)\n            {\n                var range = Selection.Clone();\n                range.Normalize();\n                Selection.BeginUpdate();\n                BeginAutoUndo();\n                Selection = new Range(this, range.Start.iChar, range.Start.iLine, range.Start.iChar, range.End.iLine)\n                    {ColumnSelectionMode = true};\n                InsertChar(left);\n                Selection = new Range(this, range.End.iChar + 1, range.Start.iLine, range.End.iChar + 1,\n                    range.End.iLine) {ColumnSelectionMode = true};\n                InsertChar(right);\n                if (range.IsEmpty)\n                    Selection = new Range(this, range.End.iChar + 1, range.Start.iLine, range.End.iChar + 1,\n                        range.End.iLine) {ColumnSelectionMode = true};\n                EndAutoUndo();\n                Selection.EndUpdate();\n            }\n            else if (Selection.IsEmpty)\n            {\n                InsertText(left + \"\" + right);\n                Selection.GoLeft();\n            }\n            else\n                InsertText(left + SelectedText + right);\n\n            return true;\n        }\n\n        /// <summary>\n        /// Finds given char after current caret position, moves the caret to found pos.\n        /// </summary>\n        /// <param name=\"c\"></param>\n        protected virtual void FindChar(char c)\n        {\n            if (c == '\\r')\n                c = '\\n';\n\n            var r = Selection.Clone();\n            while (r.GoRight())\n            {\n                if (r.CharBeforeStart == c)\n                {\n                    Selection = r;\n                    DoCaretVisible();\n                    return;\n                }\n            }\n        }\n\n        public virtual void DoAutoIndentIfNeed()\n        {\n            if (Selection.ColumnSelectionMode)\n                return;\n            if (AutoIndent)\n            {\n                DoCaretVisible();\n                int needSpaces = CalcAutoIndent(Selection.Start.iLine);\n                if (this[Selection.Start.iLine].AutoIndentSpacesNeededCount != needSpaces)\n                {\n                    DoAutoIndent(Selection.Start.iLine);\n                    this[Selection.Start.iLine].AutoIndentSpacesNeededCount = needSpaces;\n                }\n            }\n        }\n\n        private void RemoveSpacesAfterCaret()\n        {\n            if (!Selection.IsEmpty)\n                return;\n            Place end = Selection.Start;\n            while (Selection.CharAfterStart == ' ')\n                Selection.GoRight(true);\n            ClearSelected();\n        }\n\n        /// <summary>\n        /// Inserts autoindent's spaces in the line\n        /// </summary>\n        public virtual void DoAutoIndent(int iLine)\n        {\n            if (Selection.ColumnSelectionMode)\n                return;\n            Place oldStart = Selection.Start;\n            //\n            int needSpaces = CalcAutoIndent(iLine);\n            //\n            int spaces = lines[iLine].StartSpacesCount;\n            int needToInsert = needSpaces - spaces;\n            if (needToInsert < 0)\n                needToInsert = -Math.Min(-needToInsert, spaces);\n            //insert start spaces\n            if (needToInsert == 0)\n                return;\n            Selection.Start = new Place(0, iLine);\n            if (needToInsert > 0)\n                InsertText(new String(' ', needToInsert));\n            else\n            {\n                Selection.Start = new Place(0, iLine);\n                Selection.End = new Place(-needToInsert, iLine);\n                ClearSelected();\n            }\n\n            Selection.Start = new Place(Math.Min(lines[iLine].Count, Math.Max(0, oldStart.iChar + needToInsert)),\n                iLine);\n        }\n\n        /// <summary>\n        /// Returns needed start space count for the line\n        /// </summary>\n        public virtual int CalcAutoIndent(int iLine)\n        {\n            if (iLine < 0 || iLine >= LinesCount) return 0;\n\n\n            EventHandler<AutoIndentEventArgs> calculator = AutoIndentNeeded;\n            if (calculator == null)\n                if (SyntaxHighlighter != null)\n                    calculator = SyntaxHighlighter.AutoIndentNeeded;\n                else\n                    calculator = CalcAutoIndentShiftByCodeFolding;\n\n            int needSpaces = 0;\n\n            var stack = new Stack<AutoIndentEventArgs>();\n            //calc indent for previous lines, find stable line\n            int i;\n            for (i = iLine - 1; i >= 0; i--)\n            {\n                var args = new AutoIndentEventArgs(i, lines[i].Text, i > 0 ? lines[i - 1].Text : \"\", TabLength, 0);\n                calculator(this, args);\n                stack.Push(args);\n                if (args.Shift == 0 && args.AbsoluteIndentation == 0 && args.LineText.Trim() != \"\")\n                    break;\n            }\n\n            int indent = lines[i >= 0 ? i : 0].StartSpacesCount;\n            while (stack.Count != 0)\n            {\n                var arg = stack.Pop();\n                if (arg.AbsoluteIndentation != 0)\n                    indent = arg.AbsoluteIndentation + arg.ShiftNextLines;\n                else\n                    indent += arg.ShiftNextLines;\n            }\n\n            //clalc shift for current line\n            var a = new AutoIndentEventArgs(iLine, lines[iLine].Text, iLine > 0 ? lines[iLine - 1].Text : \"\", TabLength,\n                indent);\n            calculator(this, a);\n            needSpaces = a.AbsoluteIndentation + a.Shift;\n\n            return needSpaces;\n        }\n\n        internal virtual void CalcAutoIndentShiftByCodeFolding(object sender, AutoIndentEventArgs args)\n        {\n            //inset TAB after start folding marker\n            if (string.IsNullOrEmpty(lines[args.iLine].FoldingEndMarker) &&\n                !string.IsNullOrEmpty(lines[args.iLine].FoldingStartMarker))\n            {\n                args.ShiftNextLines = TabLength;\n                return;\n            }\n\n            //remove TAB before end folding marker\n            if (!string.IsNullOrEmpty(lines[args.iLine].FoldingEndMarker) &&\n                string.IsNullOrEmpty(lines[args.iLine].FoldingStartMarker))\n            {\n                args.Shift = -TabLength;\n                args.ShiftNextLines = -TabLength;\n                return;\n            }\n        }\n\n\n        protected int GetMinStartSpacesCount(int fromLine, int toLine)\n        {\n            if (fromLine > toLine)\n                return 0;\n\n            int result = int.MaxValue;\n            for (int i = fromLine; i <= toLine; i++)\n            {\n                int count = lines[i].StartSpacesCount;\n                if (count < result)\n                    result = count;\n            }\n\n            return result;\n        }\n\n        protected int GetMaxStartSpacesCount(int fromLine, int toLine)\n        {\n            if (fromLine > toLine)\n                return 0;\n\n            int result = 0;\n            for (int i = fromLine; i <= toLine; i++)\n            {\n                int count = lines[i].StartSpacesCount;\n                if (count > result)\n                    result = count;\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Undo last operation\n        /// </summary>\n        public virtual void Undo()\n        {\n            lines.Manager.Undo();\n            DoCaretVisible();\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Redo\n        /// </summary>\n        public virtual void Redo()\n        {\n            lines.Manager.Redo();\n            DoCaretVisible();\n            Invalidate();\n        }\n\n        protected override bool IsInputKey(Keys keyData)\n        {\n            if (keyData == Keys.Tab && !AcceptsTab)\n                return false;\n            if (keyData == Keys.Enter && !AcceptsReturn)\n                return false;\n\n            if ((keyData & Keys.Alt) == Keys.None)\n            {\n                Keys keys = keyData & Keys.KeyCode;\n                if (keys == Keys.Return)\n                    return true;\n            }\n\n            if ((keyData & Keys.Alt) != Keys.Alt)\n            {\n                switch ((keyData & Keys.KeyCode))\n                {\n                    case Keys.Prior:\n                    case Keys.Next:\n                    case Keys.End:\n                    case Keys.Home:\n                    case Keys.Left:\n                    case Keys.Right:\n                    case Keys.Up:\n                    case Keys.Down:\n                        return true;\n\n                    case Keys.Escape:\n                        return false;\n\n                    case Keys.Tab:\n                        return (keyData & Keys.Control) == Keys.None;\n                }\n            }\n\n            return base.IsInputKey(keyData);\n        }\n\n     \n\n        protected override void OnPaintBackground(PaintEventArgs e)\n        {\n            if (BackBrush == null)\n                base.OnPaintBackground(e);\n            else\n                e.Graphics.FillRectangle(BackBrush, ClientRectangle);\n        }\n\n        /// <summary>\n        /// Draws text to given Graphics\n        /// </summary>\n        /// <param name=\"gr\"></param>\n        /// <param name=\"start\">Start place of drawing text</param>\n        /// <param name=\"size\">Size of drawing</param>\n        public void DrawText(Graphics gr, Place start, Size size)\n        {\n            if (needRecalc)\n                Recalc();\n\n            if (needRecalcFoldingLines)\n                RecalcFoldingLines();\n\n            var startPoint = PlaceToPoint(start);\n            var startY = startPoint.Y + VerticalScroll.Value;\n            var startX = startPoint.X + HorizontalScroll.Value - LeftIndent - Paddings.Left;\n            int firstChar = start.iChar;\n            int lastChar = (startX + size.Width) / CharWidth;\n\n            var startLine = start.iLine;\n            //draw text\n            for (int iLine = startLine; iLine < lines.Count; iLine++)\n            {\n                Line line = lines[iLine];\n                LineInfo lineInfo = LineInfos[iLine];\n                //\n                if (lineInfo.startY > startY + size.Height)\n                    break;\n                if (lineInfo.startY + lineInfo.WordWrapStringsCount * CharHeight < startY)\n                    continue;\n                if (lineInfo.VisibleState == VisibleState.Hidden)\n                    continue;\n\n                int y = lineInfo.startY - startY;\n                //\n                gr.SmoothingMode = SmoothingMode.None;\n                //draw line background\n                if (lineInfo.VisibleState == VisibleState.Visible)\n                    if (line.BackgroundBrush != null)\n                        gr.FillRectangle(line.BackgroundBrush,\n                            new Rectangle(0, y, size.Width, CharHeight * lineInfo.WordWrapStringsCount));\n                //\n                gr.SmoothingMode = SmoothingMode.AntiAlias;\n\n                //draw wordwrap strings of line\n                for (int iWordWrapLine = 0; iWordWrapLine < lineInfo.WordWrapStringsCount; iWordWrapLine++)\n                {\n                    y = lineInfo.startY + iWordWrapLine * CharHeight - startY;\n                    //indent \n                    var indent = iWordWrapLine == 0 ? 0 : lineInfo.wordWrapIndent * CharWidth;\n                    //draw chars\n                    DrawLineChars(gr, firstChar, lastChar, iLine, iWordWrapLine, -startX + indent, y);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Draw control\n        /// </summary>\n        protected override void OnPaint(PaintEventArgs e)\n        {\n            if (needRecalc)\n                Recalc();\n\n            if (needRecalcFoldingLines)\n                RecalcFoldingLines();\n#if debug\n            var sw = Stopwatch.StartNew();\n#endif\n            visibleMarkers.Clear();\n            e.Graphics.SmoothingMode = SmoothingMode.None;\n            //\n            var servicePen = new Pen(ServiceLinesColor);\n            Brush changedLineBrush = new SolidBrush(ChangedLineColor);\n            Brush indentBrush = new SolidBrush(IndentBackColor);\n            Brush paddingBrush = new SolidBrush(PaddingBackColor);\n            Brush currentLineBrush =\n                new SolidBrush(Color.FromArgb(CurrentLineColor.A == 255 ? 50 : CurrentLineColor.A, CurrentLineColor));\n            //draw padding area\n            var textAreaRect = TextAreaRect;\n            //top\n            e.Graphics.FillRectangle(paddingBrush, 0, -VerticalScroll.Value, ClientSize.Width,\n                Math.Max(0, Paddings.Top - 1));\n            //bottom\n            e.Graphics.FillRectangle(paddingBrush, 0, textAreaRect.Bottom, ClientSize.Width, ClientSize.Height);\n            //right\n            e.Graphics.FillRectangle(paddingBrush, textAreaRect.Right, 0, ClientSize.Width, ClientSize.Height);\n            //left\n            e.Graphics.FillRectangle(paddingBrush, LeftIndentLine, 0, LeftIndent - LeftIndentLine - 1,\n                ClientSize.Height);\n            if (HorizontalScroll.Value <= Paddings.Left)\n                e.Graphics.FillRectangle(paddingBrush, LeftIndent - HorizontalScroll.Value - 2, 0,\n                    Math.Max(0, Paddings.Left - 1), ClientSize.Height);\n            //\n            int leftTextIndent = Math.Max(LeftIndent, LeftIndent + Paddings.Left - HorizontalScroll.Value);\n            int textWidth = textAreaRect.Width;\n            //draw indent area\n            e.Graphics.FillRectangle(indentBrush, 0, 0, LeftIndentLine, ClientSize.Height);\n            if (LeftIndent > minLeftIndent)\n                e.Graphics.DrawLine(servicePen, LeftIndentLine, 0, LeftIndentLine, ClientSize.Height);\n            //draw preferred line width\n            if (PreferredLineWidth > 0)\n                e.Graphics.DrawLine(servicePen,\n                    new Point(\n                        LeftIndent + Paddings.Left + PreferredLineWidth * CharWidth -\n                        HorizontalScroll.Value + 1, textAreaRect.Top + 1),\n                    new Point(\n                        LeftIndent + Paddings.Left + PreferredLineWidth * CharWidth -\n                        HorizontalScroll.Value + 1, textAreaRect.Bottom - 1));\n\n            //draw text area border\n            DrawTextAreaBorder(e.Graphics);\n            //\n            int firstChar = (Math.Max(0, HorizontalScroll.Value - Paddings.Left)) / CharWidth;\n            int lastChar = (HorizontalScroll.Value + ClientSize.Width) / CharWidth;\n            //\n            var x = LeftIndent + Paddings.Left - HorizontalScroll.Value;\n            if (x < LeftIndent)\n                firstChar++;\n            //create dictionary of bookmarks\n            var bookmarksByLineIndex = new Dictionary<int, Bookmark>();\n            foreach (Bookmark item in bookmarks)\n                bookmarksByLineIndex[item.LineIndex] = item;\n            //\n            int startLine = YtoLineIndex(VerticalScroll.Value);\n            int iLine;\n\n            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;\n\n            //draw text\n            for (iLine = startLine; iLine < lines.Count; iLine++)\n            {\n                Line line = lines[iLine];\n                LineInfo lineInfo = LineInfos[iLine];\n                //\n                if (lineInfo.startY > VerticalScroll.Value + ClientSize.Height)\n                    break;\n                if (lineInfo.startY + lineInfo.WordWrapStringsCount * CharHeight < VerticalScroll.Value)\n                    continue;\n                if (lineInfo.VisibleState == VisibleState.Hidden)\n                    continue;\n\n                int y = lineInfo.startY - VerticalScroll.Value;\n                //\n                e.Graphics.SmoothingMode = SmoothingMode.None;\n                //draw line background\n                if (lineInfo.VisibleState == VisibleState.Visible)\n                    if (line.BackgroundBrush != null)\n                        e.Graphics.FillRectangle(line.BackgroundBrush,\n                            new Rectangle(textAreaRect.Left, y, textAreaRect.Width,\n                                CharHeight * lineInfo.WordWrapStringsCount));\n                //draw current line background\n                if (CurrentLineColor != Color.Transparent && iLine == Selection.Start.iLine)\n                    if (Selection.IsEmpty)\n                        e.Graphics.FillRectangle(currentLineBrush,\n                            new Rectangle(textAreaRect.Left, y, textAreaRect.Width, CharHeight));\n                //draw changed line marker\n                if (ChangedLineColor != Color.Transparent && line.IsChanged)\n                    e.Graphics.FillRectangle(changedLineBrush,\n                        new RectangleF(-10, y, LeftIndent - minLeftIndent - 2 + 10, CharHeight + 1));\n                //\n                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;\n                //\n                //draw bookmark\n                if (bookmarksByLineIndex.ContainsKey(iLine))\n                    bookmarksByLineIndex[iLine].Paint(e.Graphics,\n                        new Rectangle(LeftIndent, y, Width,\n                            CharHeight * lineInfo.WordWrapStringsCount));\n                //OnPaintLine event\n                if (lineInfo.VisibleState == VisibleState.Visible)\n                    OnPaintLine(new PaintLineEventArgs(iLine,\n                        new Rectangle(LeftIndent, y, Width,\n                            CharHeight * lineInfo.WordWrapStringsCount),\n                        e.Graphics, e.ClipRectangle));\n                //draw line number\n                if (ShowLineNumbers)\n                    using (var lineNumberBrush = new SolidBrush(LineNumberColor))\n                        e.Graphics.DrawString((iLine + lineNumberStartValue).ToString(), Font, lineNumberBrush,\n                            new RectangleF(-10, y, LeftIndent - minLeftIndent - 2 + 10, CharHeight),\n                            new StringFormat(StringFormatFlags.DirectionRightToLeft));\n                //create markers\n                if (lineInfo.VisibleState == VisibleState.StartOfHiddenBlock)\n                    visibleMarkers.Add(new ExpandFoldingMarker(iLine,\n                        new Rectangle(LeftIndentLine - 4, y + CharHeight / 2 - 3, 8, 8)));\n\n                if (!string.IsNullOrEmpty(line.FoldingStartMarker) && lineInfo.VisibleState == VisibleState.Visible &&\n                    string.IsNullOrEmpty(line.FoldingEndMarker))\n                    visibleMarkers.Add(new CollapseFoldingMarker(iLine,\n                        new Rectangle(LeftIndentLine - 4, y + CharHeight / 2 - 3, 8, 8)));\n\n                if (lineInfo.VisibleState == VisibleState.Visible && !string.IsNullOrEmpty(line.FoldingEndMarker) &&\n                    string.IsNullOrEmpty(line.FoldingStartMarker))\n                    e.Graphics.DrawLine(servicePen, LeftIndentLine, y + CharHeight * lineInfo.WordWrapStringsCount - 1,\n                        LeftIndentLine + 4, y + CharHeight * lineInfo.WordWrapStringsCount - 1);\n                //draw wordwrap strings of line\n                for (int iWordWrapLine = 0; iWordWrapLine < lineInfo.WordWrapStringsCount; iWordWrapLine++)\n                {\n                    y = lineInfo.startY + iWordWrapLine * CharHeight - VerticalScroll.Value;\n                    //indent\n                    var indent = iWordWrapLine == 0 ? 0 : lineInfo.wordWrapIndent * CharWidth;\n                    //draw chars\n                    DrawLineChars(e.Graphics, firstChar, lastChar, iLine, iWordWrapLine, x + indent, y);\n                }\n            }\n\n            int endLine = iLine - 1;\n\n            //draw folding lines\n            if (ShowFoldingLines)\n                DrawFoldingLines(e, startLine, endLine);\n\n            //draw column selection\n            if (Selection.ColumnSelectionMode)\n                if (SelectionStyle.BackgroundBrush is SolidBrush)\n                {\n                    Color color = ((SolidBrush) SelectionStyle.BackgroundBrush).Color;\n                    Point p1 = PlaceToPoint(Selection.Start);\n                    Point p2 = PlaceToPoint(Selection.End);\n                    using (var pen = new Pen(color))\n                        e.Graphics.DrawRectangle(pen,\n                            Rectangle.FromLTRB(Math.Min(p1.X, p2.X) - 1, Math.Min(p1.Y, p2.Y),\n                                Math.Max(p1.X, p2.X),\n                                Math.Max(p1.Y, p2.Y) + CharHeight));\n                }\n\n            //draw brackets highlighting\n            if (BracketsStyle != null && leftBracketPosition != null && rightBracketPosition != null)\n            {\n                BracketsStyle.Draw(e.Graphics, PlaceToPoint(leftBracketPosition.Start), leftBracketPosition);\n                BracketsStyle.Draw(e.Graphics, PlaceToPoint(rightBracketPosition.Start), rightBracketPosition);\n            }\n\n            if (BracketsStyle2 != null && leftBracketPosition2 != null && rightBracketPosition2 != null)\n            {\n                BracketsStyle2.Draw(e.Graphics, PlaceToPoint(leftBracketPosition2.Start), leftBracketPosition2);\n                BracketsStyle2.Draw(e.Graphics, PlaceToPoint(rightBracketPosition2.Start), rightBracketPosition2);\n            }\n\n            //\n            e.Graphics.SmoothingMode = SmoothingMode.None;\n            //draw folding indicator\n            if ((startFoldingLine >= 0 || endFoldingLine >= 0) && Selection.Start == Selection.End)\n                if (endFoldingLine < LineInfos.Count)\n                {\n                    //folding indicator\n                    int startFoldingY = (startFoldingLine >= 0 ? LineInfos[startFoldingLine].startY : 0) -\n                                        VerticalScroll.Value + CharHeight / 2;\n                    int endFoldingY = (endFoldingLine >= 0\n                                          ? LineInfos[endFoldingLine].startY +\n                                            (LineInfos[endFoldingLine].WordWrapStringsCount - 1) * CharHeight\n                                          : TextHeight + CharHeight) - VerticalScroll.Value + CharHeight;\n\n                    using (var indicatorPen = new Pen(Color.FromArgb(100, FoldingIndicatorColor), 4))\n                        e.Graphics.DrawLine(indicatorPen, LeftIndent - 5, startFoldingY, LeftIndent - 5, endFoldingY);\n                }\n\n            //draw hint's brackets\n            PaintHintBrackets(e.Graphics);\n            //draw markers\n            DrawMarkers(e, servicePen);\n            //draw caret\n            Point car = PlaceToPoint(Selection.Start);\n            var caretHeight = CharHeight - lineInterval;\n            car.Offset(0, lineInterval / 2);\n\n            if ((Focused || IsDragDrop || ShowCaretWhenInactive) && car.X >= LeftIndent && CaretVisible)\n            {\n                int carWidth = (IsReplaceMode || WideCaret) ? CharWidth : 1;\n                if (WideCaret)\n                {\n                    using (var brush = new SolidBrush(CaretColor))\n                        e.Graphics.FillRectangle(brush, car.X, car.Y, carWidth, caretHeight + 1);\n                }\n                else\n                    using (var pen = new Pen(CaretColor))\n                        e.Graphics.DrawLine(pen, car.X, car.Y, car.X, car.Y + caretHeight);\n\n                var caretRect = new Rectangle(HorizontalScroll.Value + car.X, VerticalScroll.Value + car.Y, carWidth,\n                    caretHeight + 1);\n\n                if (CaretBlinking)\n                    if (prevCaretRect != caretRect || !ShowScrollBars)\n                    {\n                        NativeMethodWrapper.CreateCaret(Handle, 0, carWidth, caretHeight + 1);\n                        NativeMethodWrapper.SetCaretPos(car.X, car.Y);\n                        NativeMethodWrapper.ShowCaret(Handle);\n                    }\n\n                prevCaretRect = caretRect;\n            }\n            else\n            {\n                NativeMethodWrapper.HideCaret(Handle);\n                prevCaretRect = Rectangle.Empty;\n            }\n\n            //draw disabled mask\n            if (!Enabled)\n                using (var brush = new SolidBrush(DisabledColor))\n                    e.Graphics.FillRectangle(brush, ClientRectangle);\n\n            if (MacrosManager.IsRecording)\n                DrawRecordingHint(e.Graphics);\n\n            if (middleClickScrollingActivated)\n                DrawMiddleClickScrolling(e.Graphics);\n\n            //dispose resources\n            servicePen.Dispose();\n            changedLineBrush.Dispose();\n            indentBrush.Dispose();\n            currentLineBrush.Dispose();\n            paddingBrush.Dispose();\n            //\n#if debug\n            sw.Stop();\n            Console.WriteLine(\"OnPaint: \"+ sw.ElapsedMilliseconds);\n#endif\n            //\n            base.OnPaint(e);\n        }\n\n        private void DrawMarkers(PaintEventArgs e, Pen servicePen)\n        {\n            foreach (VisualMarker m in visibleMarkers)\n            {\n                if (m is CollapseFoldingMarker)\n                    using (var bk = new SolidBrush(ServiceColors.CollapseMarkerBackColor))\n                    using (var fore = new Pen(ServiceColors.CollapseMarkerForeColor))\n                    using (var border = new Pen(ServiceColors.CollapseMarkerBorderColor))\n                        (m as CollapseFoldingMarker).Draw(e.Graphics, border, bk, fore);\n                else if (m is ExpandFoldingMarker)\n                    using (var bk = new SolidBrush(ServiceColors.ExpandMarkerBackColor))\n                    using (var fore = new Pen(ServiceColors.ExpandMarkerForeColor))\n                    using (var border = new Pen(ServiceColors.ExpandMarkerBorderColor))\n                        (m as ExpandFoldingMarker).Draw(e.Graphics, border, bk, fore);\n                else\n                    m.Draw(e.Graphics, servicePen);\n            }\n        }\n\n        private Rectangle prevCaretRect;\n\n        private void DrawRecordingHint(Graphics graphics)\n        {\n            const int w = 75;\n            const int h = 13;\n            var rect = new Rectangle(ClientRectangle.Right - w, ClientRectangle.Bottom - h, w, h);\n            var iconRect = new Rectangle(-h / 2 + 3, -h / 2 + 3, h - 7, h - 7);\n            var state = graphics.Save();\n            graphics.SmoothingMode = SmoothingMode.HighQuality;\n            graphics.TranslateTransform(rect.Left + h / 2, rect.Top + h / 2);\n            var ts = new TimeSpan(DateTime.Now.Ticks);\n            graphics.RotateTransform(180 * (DateTime.Now.Millisecond / 1000f));\n            using (var pen = new Pen(Color.Red, 2))\n            {\n                graphics.DrawArc(pen, iconRect, 0, 90);\n                graphics.DrawArc(pen, iconRect, 180, 90);\n            }\n\n            graphics.DrawEllipse(Pens.Red, iconRect);\n            graphics.Restore(state);\n            using (var font = new Font(FontFamily.GenericSansSerif, 8f))\n                graphics.DrawString(\"Recording...\", font, Brushes.Red, new PointF(rect.Left + h, rect.Top));\n            System.Threading.Timer tm = null;\n            tm = new System.Threading.Timer(\n                (o) =>\n                {\n                    Invalidate(rect);\n                    tm.Dispose();\n                }, null, 200, System.Threading.Timeout.Infinite);\n        }\n\n        private void DrawTextAreaBorder(Graphics graphics)\n        {\n            if (TextAreaBorder == TextAreaBorderType.None)\n                return;\n\n            var rect = TextAreaRect;\n\n            if (TextAreaBorder == TextAreaBorderType.Shadow)\n            {\n                const int shadowSize = 4;\n                var rBottom = new Rectangle(rect.Left + shadowSize, rect.Bottom, rect.Width - shadowSize, shadowSize);\n                var rCorner = new Rectangle(rect.Right, rect.Bottom, shadowSize, shadowSize);\n                var rRight = new Rectangle(rect.Right, rect.Top + shadowSize, shadowSize, rect.Height - shadowSize);\n\n                using (var brush = new SolidBrush(Color.FromArgb(80, TextAreaBorderColor)))\n                {\n                    graphics.FillRectangle(brush, rBottom);\n                    graphics.FillRectangle(brush, rRight);\n                    graphics.FillRectangle(brush, rCorner);\n                }\n            }\n\n            using (Pen pen = new Pen(TextAreaBorderColor))\n                graphics.DrawRectangle(pen, rect);\n        }\n\n        private void PaintHintBrackets(Graphics gr)\n        {\n            foreach (Hint hint in hints)\n            {\n                Range r = hint.Range.Clone();\n                r.Normalize();\n                Point p1 = PlaceToPoint(r.Start);\n                Point p2 = PlaceToPoint(r.End);\n                if (GetVisibleState(r.Start.iLine) != VisibleState.Visible ||\n                    GetVisibleState(r.End.iLine) != VisibleState.Visible)\n                    continue;\n\n                using (var pen = new Pen(hint.BorderColor))\n                {\n                    pen.DashStyle = DashStyle.Dash;\n                    if (r.IsEmpty)\n                    {\n                        p1.Offset(1, -1);\n                        gr.DrawLines(pen, new[] {p1, new Point(p1.X, p1.Y + charHeight + 2)});\n                    }\n                    else\n                    {\n                        p1.Offset(-1, -1);\n                        p2.Offset(1, -1);\n                        gr.DrawLines(pen,\n                            new[]\n                            {\n                                new Point(p1.X + CharWidth / 2, p1.Y), p1,\n                                new Point(p1.X, p1.Y + charHeight + 2),\n                                new Point(p1.X + CharWidth / 2, p1.Y + charHeight + 2)\n                            });\n                        gr.DrawLines(pen,\n                            new[]\n                            {\n                                new Point(p2.X - CharWidth / 2, p2.Y), p2,\n                                new Point(p2.X, p2.Y + charHeight + 2),\n                                new Point(p2.X - CharWidth / 2, p2.Y + charHeight + 2)\n                            });\n                    }\n                }\n            }\n        }\n\n        protected virtual void DrawFoldingLines(PaintEventArgs e, int startLine, int endLine)\n        {\n            e.Graphics.SmoothingMode = SmoothingMode.None;\n            using (var pen = new Pen(Color.FromArgb(200, ServiceLinesColor)) {DashStyle = DashStyle.Dot})\n                foreach (var iLine in foldingPairs)\n                    if (iLine.Key < endLine && iLine.Value > startLine)\n                    {\n                        Line line = lines[iLine.Key];\n                        int y = LineInfos[iLine.Key].startY - VerticalScroll.Value + CharHeight;\n                        y += y % 2;\n\n                        int y2;\n\n                        if (iLine.Value >= LinesCount)\n                            y2 = LineInfos[LinesCount - 1].startY + CharHeight - VerticalScroll.Value;\n                        else if (LineInfos[iLine.Value].VisibleState == VisibleState.Visible)\n                        {\n                            int d = 0;\n                            int spaceCount = line.StartSpacesCount;\n                            if (lines[iLine.Value].Count <= spaceCount || lines[iLine.Value][spaceCount].c == ' ')\n                                d = CharHeight;\n                            y2 = LineInfos[iLine.Value].startY - VerticalScroll.Value + d;\n                        }\n                        else\n                            continue;\n\n                        int x = LeftIndent + Paddings.Left + line.StartSpacesCount * CharWidth - HorizontalScroll.Value;\n                        if (x >= LeftIndent + Paddings.Left)\n                            e.Graphics.DrawLine(pen, x, y >= 0 ? y : 0, x,\n                                y2 < ClientSize.Height ? y2 : ClientSize.Height);\n                    }\n        }\n\n        private void DrawLineChars(Graphics gr, int firstChar, int lastChar, int iLine, int iWordWrapLine, int startX,\n            int y)\n        {\n            Line line = lines[iLine];\n            LineInfo lineInfo = LineInfos[iLine];\n            int from = lineInfo.GetWordWrapStringStartPosition(iWordWrapLine);\n            int to = lineInfo.GetWordWrapStringFinishPosition(iWordWrapLine, line);\n\n            lastChar = Math.Min(to - from, lastChar);\n\n            gr.SmoothingMode = SmoothingMode.AntiAlias;\n\n            //folded block ?\n            if (lineInfo.VisibleState == VisibleState.StartOfHiddenBlock)\n            {\n                //rendering by FoldedBlockStyle\n                FoldedBlockStyle.Draw(gr, new Point(startX + firstChar * CharWidth, y),\n                    new Range(this, from + firstChar, iLine, from + lastChar + 1, iLine));\n            }\n            else\n            {\n                //render by custom styles\n                StyleIndex currentStyleIndex = StyleIndex.None;\n                int iLastFlushedChar = firstChar - 1;\n\n                for (int iChar = firstChar; iChar <= lastChar; iChar++)\n                {\n                    StyleIndex style = line[from + iChar].style;\n                    if (currentStyleIndex != style)\n                    {\n                        FlushRendering(gr, currentStyleIndex,\n                            new Point(startX + (iLastFlushedChar + 1) * CharWidth, y),\n                            new Range(this, from + iLastFlushedChar + 1, iLine, from + iChar, iLine));\n                        iLastFlushedChar = iChar - 1;\n                        currentStyleIndex = style;\n                    }\n                }\n\n                FlushRendering(gr, currentStyleIndex, new Point(startX + (iLastFlushedChar + 1) * CharWidth, y),\n                    new Range(this, from + iLastFlushedChar + 1, iLine, from + lastChar + 1, iLine));\n            }\n\n            //draw selection\n            if (SelectionHighlightingForLineBreaksEnabled && iWordWrapLine == lineInfo.WordWrapStringsCount - 1)\n                lastChar++; //draw selection for CR\n            if (!Selection.IsEmpty && lastChar >= firstChar)\n            {\n                gr.SmoothingMode = SmoothingMode.None;\n                var textRange = new Range(this, from + firstChar, iLine, from + lastChar + 1, iLine);\n                textRange = Selection.GetIntersectionWith(textRange);\n                if (textRange != null && SelectionStyle != null)\n                {\n                    SelectionStyle.Draw(gr, new Point(startX + (textRange.Start.iChar - from) * CharWidth, 1 + y),\n                        textRange);\n                }\n            }\n        }\n\n        private void FlushRendering(Graphics gr, StyleIndex styleIndex, Point pos, Range range)\n        {\n            if (range.End > range.Start)\n            {\n                int mask = 1;\n                bool hasTextStyle = false;\n                for (int i = 0; i < Styles.Length; i++)\n                {\n                    if (Styles[i] != null && ((int) styleIndex & mask) != 0)\n                    {\n                        Style style = Styles[i];\n                        bool isTextStyle = style is TextStyle;\n                        if (!hasTextStyle || !isTextStyle || AllowSeveralTextStyleDrawing)\n                            //cancelling secondary rendering by TextStyle\n                            style.Draw(gr, pos, range); //rendering\n                        hasTextStyle |= isTextStyle;\n                    }\n\n                    mask = mask << 1;\n                }\n\n                //draw by default renderer\n                if (!hasTextStyle)\n                    DefaultStyle.Draw(gr, pos, range);\n            }\n        }\n\n        protected override void OnEnter(EventArgs e)\n        {\n            base.OnEnter(e);\n            mouseIsDrag = false;\n            mouseIsDragDrop = false;\n            draggedRange = null;\n        }\n\n        protected override void OnMouseUp(MouseEventArgs e)\n        {\n            base.OnMouseUp(e);\n            isLineSelect = false;\n\n            if (e.Button == System.Windows.Forms.MouseButtons.Left)\n            {\n                if (mouseIsDragDrop)\n                    OnMouseClickText(e);\n            }\n        }\n\n        protected override void OnMouseDown(MouseEventArgs e)\n        {\n            base.OnMouseDown(e);\n\n            if (middleClickScrollingActivated)\n            {\n                DeactivateMiddleClickScrollingMode();\n                mouseIsDrag = false;\n                if (e.Button == System.Windows.Forms.MouseButtons.Middle)\n                    RestoreScrollsAfterMiddleClickScrollingMode();\n                return;\n            }\n\n            MacrosManager.IsRecording = false;\n\n            Select();\n            ActiveControl = null;\n\n            if (e.Button == MouseButtons.Left)\n            {\n                VisualMarker marker = FindVisualMarkerForPoint(e.Location);\n                //click on marker\n                if (marker != null)\n                {\n                    mouseIsDrag = false;\n                    mouseIsDragDrop = false;\n                    draggedRange = null;\n                    OnMarkerClick(e, marker);\n                    return;\n                }\n\n                mouseIsDrag = true;\n                mouseIsDragDrop = false;\n                draggedRange = null;\n                isLineSelect = (e.Location.X < LeftIndentLine);\n\n                if (!isLineSelect)\n                {\n                    var p = PointToPlace(e.Location);\n\n                    if (e.Clicks == 2)\n                    {\n                        mouseIsDrag = false;\n                        mouseIsDragDrop = false;\n                        draggedRange = null;\n\n                        SelectWord(p);\n                        return;\n                    }\n\n                    if (Selection.IsEmpty || !Selection.Contains(p) || this[p.iLine].Count <= p.iChar || ReadOnly)\n                        OnMouseClickText(e);\n                    else\n                    {\n                        mouseIsDragDrop = true;\n                        mouseIsDrag = false;\n                    }\n                }\n                else\n                {\n                    CheckAndChangeSelectionType();\n\n                    Selection.BeginUpdate();\n                    //select whole line\n                    int iLine = PointToPlaceSimple(e.Location).iLine;\n                    lineSelectFrom = iLine;\n                    Selection.Start = new Place(0, iLine);\n                    Selection.End = new Place(GetLineLength(iLine), iLine);\n                    Selection.EndUpdate();\n                    Invalidate();\n                }\n            }\n            else if (e.Button == MouseButtons.Middle)\n            {\n                ActivateMiddleClickScrollingMode(e);\n            }\n        }\n\n        private void OnMouseClickText(MouseEventArgs e)\n        {\n            //click on text\n            Place oldEnd = Selection.End;\n            Selection.BeginUpdate();\n\n            if (Selection.ColumnSelectionMode)\n            {\n                Selection.Start = PointToPlaceSimple(e.Location);\n                Selection.ColumnSelectionMode = true;\n            }\n            else\n            {\n                if (VirtualSpace)\n                    Selection.Start = PointToPlaceSimple(e.Location);\n                else\n                    Selection.Start = PointToPlace(e.Location);\n            }\n\n            if ((lastModifiers & Keys.Shift) != 0)\n                Selection.End = oldEnd;\n\n            CheckAndChangeSelectionType();\n\n            Selection.EndUpdate();\n            Invalidate();\n            return;\n        }\n\n        protected virtual void CheckAndChangeSelectionType()\n        {\n            //change selection type to ColumnSelectionMode\n            if ((ModifierKeys & Keys.Alt) != 0 && !WordWrap)\n            {\n                Selection.ColumnSelectionMode = true;\n            }\n            else\n                //change selection type to Range\n            {\n                Selection.ColumnSelectionMode = false;\n            }\n        }\n\n        protected override void OnMouseWheel(MouseEventArgs e)\n        {\n            Invalidate();\n\n            if (lastModifiers == Keys.Control)\n            {\n                ChangeFontSize(2 * Math.Sign(e.Delta));\n                ((HandledMouseEventArgs) e).Handled = true;\n            }\n            else if (VerticalScroll.Visible || !ShowScrollBars)\n            {\n                //base.OnMouseWheel(e);\n\n                // Determine scoll offset\n                int mouseWheelScrollLinesSetting = GetControlPanelWheelScrollLinesValue();\n\n                DoScrollVertical(mouseWheelScrollLinesSetting, e.Delta);\n\n                ((HandledMouseEventArgs) e).Handled = true;\n            }\n\n            DeactivateMiddleClickScrollingMode();\n        }\n\n        private void DoScrollVertical(int countLines, int direction)\n        {\n            if (VerticalScroll.Visible || !ShowScrollBars)\n            {\n                int numberOfVisibleLines = ClientSize.Height / CharHeight;\n\n                int offset;\n                if ((countLines == -1) || (countLines > numberOfVisibleLines))\n                    offset = CharHeight * numberOfVisibleLines;\n                else\n                    offset = CharHeight * countLines;\n\n                var newScrollPos = VerticalScroll.Value - Math.Sign(direction) * offset;\n\n                var ea =\n                    new ScrollEventArgs(direction > 0 ? ScrollEventType.SmallDecrement : ScrollEventType.SmallIncrement,\n                        VerticalScroll.Value,\n                        newScrollPos,\n                        ScrollOrientation.VerticalScroll);\n\n                OnScroll(ea);\n            }\n        }\n\n        /// <summary>\n        /// Gets the value for the system control panel mouse wheel scroll settings.\n        /// The value returns the number of lines that shall be scolled if the user turns the mouse wheet one step.\n        /// </summary>\n        /// <remarks>\n        /// This methods gets the \"WheelScrollLines\" value our from the registry key \"HKEY_CURRENT_USER\\Control Panel\\Desktop\".\n        /// If the value of this option is 0, the screen will not scroll when the mouse wheel is turned.\n        /// If the value of this option is -1 or is greater than the number of lines visible in the window,\n        /// the screen will scroll up or down by one page.\n        /// </remarks>\n        /// <returns>\n        /// Number of lines to scrol l when the mouse wheel is turned\n        /// </returns>\n        private static int GetControlPanelWheelScrollLinesValue()\n        {\n            try\n            {\n                using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@\"Control Panel\\Desktop\", false))\n                {\n                    return Convert.ToInt32(key.GetValue(\"WheelScrollLines\"));\n                }\n            }\n            catch\n            {\n                // Use default value\n                return 1;\n            }\n        }\n\n\n        public void ChangeFontSize(int step)\n        {\n            var points = Font.SizeInPoints;\n            using (var gr = Graphics.FromHwnd(Handle))\n            {\n                var dpi = gr.DpiY;\n                var newPoints = points + step * 72f / dpi;\n                if (newPoints < 1f) return;\n                var k = newPoints / originalFont.SizeInPoints;\n                Zoom = (int) (100 * k);\n            }\n        }\n\n        /// <summary>\n        /// Zooming (in percentages)\n        /// </summary>\n        [Browsable(false)]\n        public int Zoom\n        {\n            get { return zoom; }\n            set\n            {\n                zoom = value;\n                DoZoom(zoom / 100f);\n                OnZoomChanged();\n            }\n        }\n\n        protected virtual void OnZoomChanged()\n        {\n            if (ZoomChanged != null)\n                ZoomChanged(this, EventArgs.Empty);\n        }\n\n        private void DoZoom(float koeff)\n        {\n            //remmber first displayed line\n            var iLine = YtoLineIndex(VerticalScroll.Value);\n            //\n            var points = originalFont.SizeInPoints;\n            points *= koeff;\n\n            if (points < 1f || points > 300f) return;\n\n            var oldFont = Font;\n            SetFont(new Font(Font.FontFamily, points, Font.Style, GraphicsUnit.Point));\n            oldFont.Dispose();\n\n            NeedRecalc(true);\n\n            //restore first displayed line\n            if (iLine < LinesCount)\n                VerticalScroll.Value = Math.Min(VerticalScroll.Maximum, LineInfos[iLine].startY - Paddings.Top);\n            UpdateScrollbars();\n            //\n            Invalidate();\n            OnVisibleRangeChanged();\n        }\n\n        protected override void OnMouseLeave(EventArgs e)\n        {\n            base.OnMouseLeave(e);\n\n            CancelToolTip();\n        }\n\n        protected Range draggedRange;\n\n        protected override void OnMouseMove(MouseEventArgs e)\n        {\n            base.OnMouseMove(e);\n\n            if (middleClickScrollingActivated)\n                return;\n\n            if (lastMouseCoord != e.Location)\n            {\n                //restart tooltip timer\n                CancelToolTip();\n                timer3.Start();\n            }\n\n            lastMouseCoord = e.Location;\n\n            if (e.Button == MouseButtons.Left && mouseIsDragDrop)\n            {\n                draggedRange = Selection.Clone();\n                DoDragDrop(SelectedText, DragDropEffects.Copy);\n                draggedRange = null;\n                return;\n            }\n\n            if (e.Button == MouseButtons.Left && mouseIsDrag)\n            {\n                Place place;\n                if (Selection.ColumnSelectionMode || VirtualSpace)\n                    place = PointToPlaceSimple(e.Location);\n                else\n                    place = PointToPlace(e.Location);\n\n                if (isLineSelect)\n                {\n                    Selection.BeginUpdate();\n\n                    int iLine = place.iLine;\n                    if (iLine < lineSelectFrom)\n                    {\n                        Selection.Start = new Place(0, iLine);\n                        Selection.End = new Place(GetLineLength(lineSelectFrom), lineSelectFrom);\n                    }\n                    else\n                    {\n                        Selection.Start = new Place(GetLineLength(iLine), iLine);\n                        Selection.End = new Place(0, lineSelectFrom);\n                    }\n\n                    Selection.EndUpdate();\n                    DoCaretVisible();\n                    HorizontalScroll.Value = 0;\n                    UpdateScrollbars();\n                    Invalidate();\n                }\n                else if (place != Selection.Start)\n                {\n                    Place oldEnd = Selection.End;\n                    Selection.BeginUpdate();\n                    if (Selection.ColumnSelectionMode)\n                    {\n                        Selection.Start = place;\n                        Selection.ColumnSelectionMode = true;\n                    }\n                    else\n                        Selection.Start = place;\n\n                    Selection.End = oldEnd;\n                    Selection.EndUpdate();\n                    DoCaretVisible();\n                    Invalidate();\n                    return;\n                }\n            }\n\n            VisualMarker marker = FindVisualMarkerForPoint(e.Location);\n            if (marker != null)\n                base.Cursor = marker.Cursor;\n            else\n            {\n                if (e.Location.X < LeftIndentLine || isLineSelect)\n                    base.Cursor = Cursors.Arrow;\n                else\n                    base.Cursor = defaultCursor;\n            }\n        }\n\n        private void CancelToolTip()\n        {\n            timer3.Stop();\n            if (ToolTip != null && !string.IsNullOrEmpty(ToolTip.GetToolTip(this)))\n            {\n                ToolTip.Hide(this);\n                ToolTip.SetToolTip(this, null);\n            }\n        }\n\n        protected override void OnMouseDoubleClick(MouseEventArgs e)\n        {\n            base.OnMouseDoubleClick(e);\n\n            var m = FindVisualMarkerForPoint(e.Location);\n            if (m != null)\n                OnMarkerDoubleClick(m);\n        }\n\n        private void SelectWord(Place p)\n        {\n            int fromX = p.iChar;\n            int toX = p.iChar;\n\n            for (int i = p.iChar; i < lines[p.iLine].Count; i++)\n            {\n                char c = lines[p.iLine][i].c;\n                if (char.IsLetterOrDigit(c) || c == '_')\n                    toX = i + 1;\n                else\n                    break;\n            }\n\n            for (int i = p.iChar - 1; i >= 0; i--)\n            {\n                char c = lines[p.iLine][i].c;\n                if (char.IsLetterOrDigit(c) || c == '_')\n                    fromX = i;\n                else\n                    break;\n            }\n\n            Selection = new Range(this, toX, p.iLine, fromX, p.iLine);\n        }\n\n        private int YtoLineIndex(int y)\n        {\n            int i = LineInfos.BinarySearch(new LineInfo(-10), new LineYComparer(y));\n            i = i < 0 ? -i - 2 : i;\n            if (i < 0) return 0;\n            if (i > lines.Count - 1) return lines.Count - 1;\n            return i;\n        }\n\n        /// <summary>\n        /// Gets nearest line and char position from coordinates\n        /// </summary>\n        /// <param name=\"point\">Point</param>\n        /// <returns>Line and char position</returns>\n        public Place PointToPlace(Point point)\n        {\n#if debug\n            var sw = Stopwatch.StartNew();\n#endif\n            point.Offset(HorizontalScroll.Value, VerticalScroll.Value);\n            point.Offset(-LeftIndent - Paddings.Left, 0);\n            int iLine = YtoLineIndex(point.Y);\n            if (iLine < 0)\n                return Place.Empty;\n\n            int y = 0;\n\n            for (; iLine < lines.Count; iLine++)\n            {\n                y = LineInfos[iLine].startY + LineInfos[iLine].WordWrapStringsCount * CharHeight;\n                if (y > point.Y && LineInfos[iLine].VisibleState == VisibleState.Visible)\n                    break;\n            }\n\n            if (iLine >= lines.Count)\n                iLine = lines.Count - 1;\n            if (LineInfos[iLine].VisibleState != VisibleState.Visible)\n                iLine = FindPrevVisibleLine(iLine);\n            //\n            int iWordWrapLine = LineInfos[iLine].WordWrapStringsCount;\n            do\n            {\n                iWordWrapLine--;\n                y -= CharHeight;\n            } while (y > point.Y);\n\n            if (iWordWrapLine < 0) iWordWrapLine = 0;\n            //\n            int start = LineInfos[iLine].GetWordWrapStringStartPosition(iWordWrapLine);\n            int finish = LineInfos[iLine].GetWordWrapStringFinishPosition(iWordWrapLine, lines[iLine]);\n            var x = (int) Math.Round((float) point.X / CharWidth);\n            if (iWordWrapLine > 0)\n                x -= LineInfos[iLine].wordWrapIndent;\n\n            x = x < 0 ? start : start + x;\n            if (x > finish)\n                x = finish + 1;\n            if (x > lines[iLine].Count)\n                x = lines[iLine].Count;\n\n#if debug\n            Console.WriteLine(\"PointToPlace: \" + sw.ElapsedMilliseconds);\n#endif\n\n            return new Place(x, iLine);\n        }\n\n        private Place PointToPlaceSimple(Point point)\n        {\n            point.Offset(HorizontalScroll.Value, VerticalScroll.Value);\n            point.Offset(-LeftIndent - Paddings.Left, 0);\n            int iLine = YtoLineIndex(point.Y);\n            var x = (int) Math.Round((float) point.X / CharWidth);\n            if (x < 0) x = 0;\n            return new Place(x, iLine);\n        }\n\n        /// <summary>\n        /// Gets nearest absolute text position for given point\n        /// </summary>\n        /// <param name=\"point\">Point</param>\n        /// <returns>Position</returns>\n        public int PointToPosition(Point point)\n        {\n            return PlaceToPosition(PointToPlace(point));\n        }\n\n        /// <summary>\n        /// Fires TextChanging event\n        /// </summary>\n        public virtual void OnTextChanging(ref string text)\n        {\n            ClearBracketsPositions();\n\n            if (TextChanging != null)\n            {\n                var args = new TextChangingEventArgs {InsertingText = text};\n                TextChanging(this, args);\n                text = args.InsertingText;\n                if (args.Cancel)\n                    text = string.Empty;\n            }\n        }\n\n        public virtual void OnTextChanging()\n        {\n            string temp = null;\n            OnTextChanging(ref temp);\n        }\n\n        /// <summary>\n        /// Fires TextChanged event\n        /// </summary>\n        public virtual void OnTextChanged()\n        {\n            var r = new Range(this);\n            r.SelectAll();\n            OnTextChanged(new TextChangedEventArgs(r));\n        }\n\n        /// <summary>\n        /// Fires TextChanged event\n        /// </summary>\n        public virtual void OnTextChanged(int fromLine, int toLine)\n        {\n            var r = new Range(this);\n            r.Start = new Place(0, Math.Min(fromLine, toLine));\n            r.End = new Place(lines[Math.Max(fromLine, toLine)].Count, Math.Max(fromLine, toLine));\n            OnTextChanged(new TextChangedEventArgs(r));\n        }\n\n        /// <summary>\n        /// Fires TextChanged event\n        /// </summary>\n        public virtual void OnTextChanged(Range r)\n        {\n            OnTextChanged(new TextChangedEventArgs(r));\n        }\n\n        /// <summary>\n        /// Call this method before multiple text changing\n        /// </summary>\n        public void BeginUpdate()\n        {\n            if (updating == 0)\n                updatingRange = null;\n            updating++;\n        }\n\n        /// <summary>\n        /// Call this method after multiple text changing\n        /// </summary>\n        public void EndUpdate()\n        {\n            updating--;\n\n            if (updating == 0 && updatingRange != null)\n            {\n                updatingRange.Expand();\n                OnTextChanged(updatingRange);\n            }\n        }\n\n\n        /// <summary>\n        /// Fires TextChanged event\n        /// </summary>\n        protected virtual void OnTextChanged(TextChangedEventArgs args)\n        {\n            //\n            args.ChangedRange.Normalize();\n            //\n            if (updating > 0)\n            {\n                if (updatingRange == null)\n                    updatingRange = args.ChangedRange.Clone();\n                else\n                {\n                    if (updatingRange.Start.iLine > args.ChangedRange.Start.iLine)\n                        updatingRange.Start = new Place(0, args.ChangedRange.Start.iLine);\n                    if (updatingRange.End.iLine < args.ChangedRange.End.iLine)\n                        updatingRange.End = new Place(lines[args.ChangedRange.End.iLine].Count,\n                            args.ChangedRange.End.iLine);\n                    updatingRange = updatingRange.GetIntersectionWith(Range);\n                }\n\n                return;\n            }\n            //\n#if debug\n            var sw = Stopwatch.StartNew();\n#endif\n            CancelToolTip();\n            ClearHints();\n            IsChanged = true;\n            TextVersion++;\n            MarkLinesAsChanged(args.ChangedRange);\n            ClearFoldingState(args.ChangedRange);\n            //\n            if (wordWrap)\n                RecalcWordWrap(args.ChangedRange.Start.iLine, args.ChangedRange.End.iLine);\n            //\n            base.OnTextChanged(args);\n\n            //dalayed event stuffs\n            if (delayedTextChangedRange == null)\n                delayedTextChangedRange = args.ChangedRange.Clone();\n            else\n                delayedTextChangedRange = delayedTextChangedRange.GetUnionWith(args.ChangedRange);\n\n            needRiseTextChangedDelayed = true;\n            ResetTimer(timer2);\n            //\n            OnSyntaxHighlight(args);\n            //\n            if (TextChanged != null)\n                TextChanged(this, args);\n            //\n            if (BindingTextChanged != null)\n                BindingTextChanged(this, EventArgs.Empty);\n            //\n            base.OnTextChanged(EventArgs.Empty);\n            //\n#if debug\n            Console.WriteLine(\"OnTextChanged: \" + sw.ElapsedMilliseconds);\n#endif\n\n            OnVisibleRangeChanged();\n        }\n\n        /// <summary>\n        /// Clears folding state for range of text\n        /// </summary>\n        private void ClearFoldingState(Range range)\n        {\n            for (int iLine = range.Start.iLine; iLine <= range.End.iLine; iLine++)\n                if (iLine >= 0 && iLine < lines.Count)\n                    FoldedBlocks.Remove(this[iLine].UniqueId);\n        }\n\n\n        private void MarkLinesAsChanged(Range range)\n        {\n            for (int iLine = range.Start.iLine; iLine <= range.End.iLine; iLine++)\n                if (iLine >= 0 && iLine < lines.Count)\n                    lines[iLine].IsChanged = true;\n        }\n\n        /// <summary>\n        /// Fires SelectionChanged event\n        /// </summary>\n        public virtual void OnSelectionChanged()\n        {\n#if debug\n            var sw = Stopwatch.StartNew();\n#endif\n            //find folding markers for highlighting\n            if (HighlightFoldingIndicator)\n                HighlightFoldings();\n            //\n            needRiseSelectionChangedDelayed = true;\n            ResetTimer(timer);\n\n            if (SelectionChanged != null)\n                SelectionChanged(this, new EventArgs());\n\n#if debug\n            Console.WriteLine(\"OnSelectionChanged: \"+ sw.ElapsedMilliseconds);\n#endif\n        }\n\n        //find folding markers for highlighting\n        private void HighlightFoldings()\n        {\n            if (LinesCount == 0)\n                return;\n            //\n            int prevStartFoldingLine = startFoldingLine;\n            int prevEndFoldingLine = endFoldingLine;\n            //\n            startFoldingLine = -1;\n            endFoldingLine = -1;\n            int counter = 0;\n            for (int i = Selection.Start.iLine; i >= Math.Max(Selection.Start.iLine - maxLinesForFolding, 0); i--)\n            {\n                bool hasStartMarker = lines.LineHasFoldingStartMarker(i);\n                bool hasEndMarker = lines.LineHasFoldingEndMarker(i);\n\n                if (hasEndMarker && hasStartMarker)\n                    continue;\n\n                if (hasStartMarker)\n                {\n                    counter--;\n                    if (counter == -1) //found start folding\n                    {\n                        startFoldingLine = i;\n                        break;\n                    }\n                }\n\n                if (hasEndMarker && i != Selection.Start.iLine)\n                    counter++;\n            }\n\n            if (startFoldingLine >= 0)\n            {\n                //find end of block\n                endFoldingLine = FindEndOfFoldingBlock(startFoldingLine, maxLinesForFolding);\n                if (endFoldingLine == startFoldingLine)\n                    endFoldingLine = -1;\n            }\n\n            if (startFoldingLine != prevStartFoldingLine || endFoldingLine != prevEndFoldingLine)\n                OnFoldingHighlightChanged();\n        }\n\n        protected virtual void OnFoldingHighlightChanged()\n        {\n            if (FoldingHighlightChanged != null)\n                FoldingHighlightChanged(this, EventArgs.Empty);\n        }\n\n        protected override void OnGotFocus(EventArgs e)\n        {\n            SetAsCurrentTB();\n            base.OnGotFocus(e);\n            Invalidate();\n        }\n\n        protected override void OnLostFocus(EventArgs e)\n        {\n            lastModifiers = Keys.None;\n            DeactivateMiddleClickScrollingMode();\n            base.OnLostFocus(e);\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Gets absolute text position from line and char position\n        /// </summary>\n        /// <param name=\"point\">Line and char position</param>\n        /// <returns>Point of char</returns>\n        public int PlaceToPosition(Place point)\n        {\n            if (point.iLine < 0 || point.iLine >= lines.Count ||\n                point.iChar >= lines[point.iLine].Count + Environment.NewLine.Length)\n                return -1;\n\n            int result = 0;\n            for (int i = 0; i < point.iLine; i++)\n                result += lines[i].Count + Environment.NewLine.Length;\n            result += point.iChar;\n\n            return result;\n        }\n\n        /// <summary>\n        /// Gets line and char position from absolute text position\n        /// </summary>\n        public Place PositionToPlace(int pos)\n        {\n            if (pos < 0)\n                return new Place(0, 0);\n\n            for (int i = 0; i < lines.Count; i++)\n            {\n                int lineLength = lines[i].Count + Environment.NewLine.Length;\n                if (pos < lines[i].Count)\n                    return new Place(pos, i);\n                if (pos < lineLength)\n                    return new Place(lines[i].Count, i);\n\n                pos -= lineLength;\n            }\n\n            if (lines.Count > 0)\n                return new Place(lines[lines.Count - 1].Count, lines.Count - 1);\n            else\n                return new Place(0, 0);\n            //throw new ArgumentOutOfRangeException(\"Position out of range\");\n        }\n\n        /// <summary>\n        /// Gets absolute char position from char position\n        /// </summary>\n        public Point PositionToPoint(int pos)\n        {\n            return PlaceToPoint(PositionToPlace(pos));\n        }\n\n        /// <summary>\n        /// Gets point for given line and char position\n        /// </summary>\n        /// <param name=\"place\">Line and char position</param>\n        /// <returns>Coordiantes</returns>\n        public Point PlaceToPoint(Place place)\n        {\n            if (place.iLine >= LineInfos.Count)\n                return new Point();\n            int y = LineInfos[place.iLine].startY;\n            //\n            int iWordWrapIndex = LineInfos[place.iLine].GetWordWrapStringIndex(place.iChar);\n            y += iWordWrapIndex * CharHeight;\n            int x = (place.iChar - LineInfos[place.iLine].GetWordWrapStringStartPosition(iWordWrapIndex)) * CharWidth;\n            if (iWordWrapIndex > 0)\n                x += LineInfos[place.iLine].wordWrapIndent * CharWidth;\n            //\n            y = y - VerticalScroll.Value;\n            x = LeftIndent + Paddings.Left + x - HorizontalScroll.Value;\n\n            return new Point(x, y);\n        }\n\n        /// <summary>\n        /// Get range of text\n        /// </summary>\n        /// <param name=\"fromPos\">Absolute start position</param>\n        /// <param name=\"toPos\">Absolute finish position</param>\n        /// <returns>Range</returns>\n        public Range GetRange(int fromPos, int toPos)\n        {\n            var sel = new Range(this);\n            sel.Start = PositionToPlace(fromPos);\n            sel.End = PositionToPlace(toPos);\n            return sel;\n        }\n\n        /// <summary>\n        /// Get range of text\n        /// </summary>\n        /// <param name=\"fromPlace\">Line and char position</param>\n        /// <param name=\"toPlace\">Line and char position</param>\n        /// <returns>Range</returns>\n        public Range GetRange(Place fromPlace, Place toPlace)\n        {\n            return new Range(this, fromPlace, toPlace);\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex pattern\n        /// </summary>\n        /// <param name=\"regexPattern\">Regex pattern</param>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRanges(string regexPattern)\n        {\n            var range = new Range(this);\n            range.SelectAll();\n            //\n            foreach (Range r in range.GetRanges(regexPattern, RegexOptions.None))\n                yield return r;\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex pattern\n        /// </summary>\n        /// <param name=\"regexPattern\">Regex pattern</param>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRanges(string regexPattern, RegexOptions options)\n        {\n            var range = new Range(this);\n            range.SelectAll();\n            //\n            foreach (Range r in range.GetRanges(regexPattern, options))\n                yield return r;\n        }\n\n        /// <summary>\n        /// Get text of given line\n        /// </summary>\n        /// <param name=\"iLine\">Line index</param>\n        /// <returns>Text</returns>\n        public string GetLineText(int iLine)\n        {\n            if (iLine < 0 || iLine >= lines.Count)\n                throw new ArgumentOutOfRangeException(\"Line index out of range\");\n            var sb = new StringBuilder(lines[iLine].Count);\n            foreach (Char c in lines[iLine])\n                sb.Append(c.c);\n            return sb.ToString();\n        }\n\n        /// <summary>\n        /// Exapnds folded block\n        /// </summary>\n        /// <param name=\"iLine\">Start line</param>\n        public virtual void ExpandFoldedBlock(int iLine)\n        {\n            if (iLine < 0 || iLine >= lines.Count)\n                throw new ArgumentOutOfRangeException(\"Line index out of range\");\n            //find all hidden lines afetr iLine\n            int end = iLine;\n            for (; end < LinesCount - 1; end++)\n            {\n                if (LineInfos[end + 1].VisibleState != VisibleState.Hidden)\n                    break;\n            }\n\n            ExpandBlock(iLine, end);\n\n            FoldedBlocks.Remove(this[iLine].UniqueId); //remove folded state for this line\n            AdjustFolding();\n        }\n\n        /// <summary>\n        /// Collapse folding blocks using FoldedBlocks dictionary.\n        /// </summary>\n        public virtual void AdjustFolding()\n        {\n            //collapse folded blocks\n            for (int iLine = 0; iLine < LinesCount; iLine++)\n                if (LineInfos[iLine].VisibleState == VisibleState.Visible)\n                    if (FoldedBlocks.ContainsKey(this[iLine].UniqueId))\n                        CollapseFoldingBlock(iLine);\n        }\n\n\n        /// <summary>\n        /// Expand collapsed block\n        /// </summary>\n        public virtual void ExpandBlock(int fromLine, int toLine)\n        {\n            int from = Math.Min(fromLine, toLine);\n            int to = Math.Max(fromLine, toLine);\n            for (int i = from; i <= to; i++)\n                SetVisibleState(i, VisibleState.Visible);\n            needRecalc = true;\n\n            Invalidate();\n            OnVisibleRangeChanged();\n        }\n\n        /// <summary>\n        /// Expand collapsed block\n        /// </summary>\n        /// <param name=\"iLine\">Any line inside collapsed block</param>\n        public void ExpandBlock(int iLine)\n        {\n            if (LineInfos[iLine].VisibleState == VisibleState.Visible)\n                return;\n\n            for (int i = iLine; i < LinesCount; i++)\n                if (LineInfos[i].VisibleState == VisibleState.Visible)\n                    break;\n                else\n                {\n                    SetVisibleState(i, VisibleState.Visible);\n                    needRecalc = true;\n                }\n\n            for (int i = iLine - 1; i >= 0; i--)\n                if (LineInfos[i].VisibleState == VisibleState.Visible)\n                    break;\n                else\n                {\n                    SetVisibleState(i, VisibleState.Visible);\n                    needRecalc = true;\n                }\n\n            Invalidate();\n            OnVisibleRangeChanged();\n        }\n\n        /// <summary>\n        /// Collapses all folding blocks\n        /// </summary>\n        public virtual void CollapseAllFoldingBlocks()\n        {\n            for (int i = 0; i < LinesCount; i++)\n                if (lines.LineHasFoldingStartMarker(i))\n                {\n                    int iFinish = FindEndOfFoldingBlock(i);\n                    if (iFinish >= 0)\n                    {\n                        CollapseBlock(i, iFinish);\n                        i = iFinish;\n                    }\n                }\n\n            OnVisibleRangeChanged();\n            UpdateScrollbars();\n        }\n\n        /// <summary>\n        /// Exapnds all folded blocks\n        /// </summary>\n        /// <param name=\"iLine\"></param>\n        public virtual void ExpandAllFoldingBlocks()\n        {\n            for (int i = 0; i < LinesCount; i++)\n                SetVisibleState(i, VisibleState.Visible);\n\n            FoldedBlocks.Clear();\n\n            OnVisibleRangeChanged();\n            Invalidate();\n            UpdateScrollbars();\n        }\n\n        /// <summary>\n        /// Collapses folding block\n        /// </summary>\n        /// <param name=\"iLine\">Start folding line</param>\n        public virtual void CollapseFoldingBlock(int iLine)\n        {\n            if (iLine < 0 || iLine >= lines.Count)\n                throw new ArgumentOutOfRangeException(\"Line index out of range\");\n            if (string.IsNullOrEmpty(lines[iLine].FoldingStartMarker))\n                throw new ArgumentOutOfRangeException(\"This line is not folding start line\");\n            //find end of block\n            int i = FindEndOfFoldingBlock(iLine);\n            //collapse\n            if (i >= 0)\n            {\n                CollapseBlock(iLine, i);\n                var id = this[iLine].UniqueId;\n                FoldedBlocks[id] = id; //add folded state for line\n            }\n        }\n\n        private int FindEndOfFoldingBlock(int iStartLine)\n        {\n            return FindEndOfFoldingBlock(iStartLine, int.MaxValue);\n        }\n\n        protected virtual int FindEndOfFoldingBlock(int iStartLine, int maxLines)\n        {\n            //find end of block\n            int i;\n            string marker = lines[iStartLine].FoldingStartMarker;\n            var stack = new Stack<string>();\n\n            switch (FindEndOfFoldingBlockStrategy)\n            {\n                case FindEndOfFoldingBlockStrategy.Strategy1:\n                    for (i = iStartLine /*+1*/; i < LinesCount; i++)\n                    {\n                        if (lines.LineHasFoldingStartMarker(i))\n                            stack.Push(lines[i].FoldingStartMarker);\n\n                        if (lines.LineHasFoldingEndMarker(i))\n                        {\n                            string m = lines[i].FoldingEndMarker;\n                            while (stack.Count > 0 && stack.Pop() != m) ;\n                            if (stack.Count == 0)\n                                return i;\n                        }\n\n                        maxLines--;\n                        if (maxLines < 0)\n                            return i;\n                    }\n\n                    break;\n\n                case FindEndOfFoldingBlockStrategy.Strategy2:\n                    for (i = iStartLine /*+1*/; i < LinesCount; i++)\n                    {\n                        if (lines.LineHasFoldingEndMarker(i))\n                        {\n                            string m = lines[i].FoldingEndMarker;\n                            while (stack.Count > 0 && stack.Pop() != m) ;\n                            if (stack.Count == 0)\n                                return i;\n                        }\n\n                        if (lines.LineHasFoldingStartMarker(i))\n                            stack.Push(lines[i].FoldingStartMarker);\n\n                        maxLines--;\n                        if (maxLines < 0)\n                            return i;\n                    }\n\n                    break;\n            }\n\n            //return -1;\n            return LinesCount - 1;\n        }\n\n        /// <summary>\n        /// Start foilding marker for the line\n        /// </summary>\n        public string GetLineFoldingStartMarker(int iLine)\n        {\n            if (lines.LineHasFoldingStartMarker(iLine))\n                return lines[iLine].FoldingStartMarker;\n            return null;\n        }\n\n        /// <summary>\n        /// End foilding marker for the line\n        /// </summary>\n        public string GetLineFoldingEndMarker(int iLine)\n        {\n            if (lines.LineHasFoldingEndMarker(iLine))\n                return lines[iLine].FoldingEndMarker;\n            return null;\n        }\n\n        protected virtual void RecalcFoldingLines()\n        {\n            if (!needRecalcFoldingLines)\n                return;\n            needRecalcFoldingLines = false;\n            if (!ShowFoldingLines)\n                return;\n\n            foldingPairs.Clear();\n            //\n            Range range = VisibleRange;\n            int startLine = Math.Max(range.Start.iLine - maxLinesForFolding, 0);\n            int endLine = Math.Min(range.End.iLine + maxLinesForFolding, Math.Max(range.End.iLine, LinesCount - 1));\n            var stack = new Stack<int>();\n            for (int i = startLine; i <= endLine; i++)\n            {\n                bool hasStartMarker = lines.LineHasFoldingStartMarker(i);\n                bool hasEndMarker = lines.LineHasFoldingEndMarker(i);\n\n                if (hasEndMarker && hasStartMarker)\n                    continue;\n\n                if (hasStartMarker)\n                {\n                    stack.Push(i);\n                }\n\n                if (hasEndMarker)\n                {\n                    string m = lines[i].FoldingEndMarker;\n                    while (stack.Count > 0)\n                    {\n                        int iStartLine = stack.Pop();\n                        foldingPairs[iStartLine] = i;\n                        if (m == lines[iStartLine].FoldingStartMarker)\n                            break;\n                    }\n                }\n            }\n\n            while (stack.Count > 0)\n                foldingPairs[stack.Pop()] = endLine + 1;\n        }\n\n        /// <summary>\n        /// Collapse text block\n        /// </summary>\n        public virtual void CollapseBlock(int fromLine, int toLine)\n        {\n            int from = Math.Min(fromLine, toLine);\n            int to = Math.Max(fromLine, toLine);\n            if (from == to)\n                return;\n\n            //find first non empty line\n            for (; from <= to; from++)\n            {\n                if (GetLineText(from).Trim().Length > 0)\n                {\n                    //hide lines\n                    for (int i = from + 1; i <= to; i++)\n                        SetVisibleState(i, VisibleState.Hidden);\n                    SetVisibleState(from, VisibleState.StartOfHiddenBlock);\n                    Invalidate();\n                    break;\n                }\n            }\n\n            //Move caret outside\n            from = Math.Min(fromLine, toLine);\n            to = Math.Max(fromLine, toLine);\n            int newLine = FindNextVisibleLine(to);\n            if (newLine == to)\n                newLine = FindPrevVisibleLine(from);\n            Selection.Start = new Place(0, newLine);\n            //\n            needRecalc = true;\n            Invalidate();\n            OnVisibleRangeChanged();\n        }\n\n\n        internal int FindNextVisibleLine(int iLine)\n        {\n            if (iLine >= lines.Count - 1) return iLine;\n            int old = iLine;\n            do\n                iLine++;\n            while (iLine < lines.Count - 1 && LineInfos[iLine].VisibleState != VisibleState.Visible);\n\n            if (LineInfos[iLine].VisibleState != VisibleState.Visible)\n                return old;\n            else\n                return iLine;\n        }\n\n\n        internal int FindPrevVisibleLine(int iLine)\n        {\n            if (iLine <= 0) return iLine;\n            int old = iLine;\n            do\n                iLine--;\n            while (iLine > 0 && LineInfos[iLine].VisibleState != VisibleState.Visible);\n\n            if (LineInfos[iLine].VisibleState != VisibleState.Visible)\n                return old;\n            else\n                return iLine;\n        }\n\n        private VisualMarker FindVisualMarkerForPoint(Point p)\n        {\n            foreach (VisualMarker m in visibleMarkers)\n                if (m.rectangle.Contains(p))\n                    return m;\n            return null;\n        }\n\n        /// <summary>\n        /// Insert TAB into front of seletcted lines.\n        /// </summary>\n        public virtual void IncreaseIndent()\n        {\n            if (Selection.Start == Selection.End)\n            {\n                if (!Selection.ReadOnly)\n                {\n                    Selection.Start = new Place(this[Selection.Start.iLine].StartSpacesCount, Selection.Start.iLine);\n                    //insert tab as spaces\n                    int spaces = TabLength - (Selection.Start.iChar % TabLength);\n                    //replace mode? select forward chars\n                    if (IsReplaceMode)\n                    {\n                        for (int i = 0; i < spaces; i++)\n                            Selection.GoRight(true);\n                        Selection.Inverse();\n                    }\n\n                    InsertText(new String(' ', spaces));\n                }\n\n                return;\n            }\n\n            bool carretAtEnd = (Selection.Start > Selection.End) && !Selection.ColumnSelectionMode;\n\n            int startChar = 0; // Only move selection when in 'ColumnSelectionMode'\n            if (Selection.ColumnSelectionMode)\n                startChar = Math.Min(Selection.End.iChar, Selection.Start.iChar);\n\n            BeginUpdate();\n            Selection.BeginUpdate();\n            lines.Manager.BeginAutoUndoCommands();\n\n            var old = Selection.Clone();\n            lines.Manager.ExecuteCommand(new SelectCommand(TextSource)); //remember selection\n\n            //\n            Selection.Normalize();\n            Range currentSelection = this.Selection.Clone();\n            int from = Selection.Start.iLine;\n            int to = Selection.End.iLine;\n\n            if (!Selection.ColumnSelectionMode)\n                if (Selection.End.iChar == 0)\n                    to--;\n\n            for (int i = from; i <= to; i++)\n            {\n                if (lines[i].Count == 0) continue;\n                Selection.Start = new Place(startChar, i);\n                lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, new String(' ', TabLength)));\n            }\n\n            // Restore selection\n            if (Selection.ColumnSelectionMode == false)\n            {\n                int newSelectionStartCharacterIndex = currentSelection.Start.iChar + this.TabLength;\n                int newSelectionEndCharacterIndex =\n                    currentSelection.End.iChar + (currentSelection.End.iLine == to ? this.TabLength : 0);\n                this.Selection.Start = new Place(newSelectionStartCharacterIndex, currentSelection.Start.iLine);\n                this.Selection.End = new Place(newSelectionEndCharacterIndex, currentSelection.End.iLine);\n            }\n            else\n            {\n                Selection = old;\n            }\n\n            lines.Manager.EndAutoUndoCommands();\n\n            if (carretAtEnd)\n                Selection.Inverse();\n\n            needRecalc = true;\n            Selection.EndUpdate();\n            EndUpdate();\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Remove TAB from front of seletcted lines.\n        /// </summary>\n        public virtual void DecreaseIndent()\n        {\n            if (Selection.Start.iLine == Selection.End.iLine)\n            {\n                DecreaseIndentOfSingleLine();\n                return;\n            }\n\n            int startCharIndex = 0;\n            if (Selection.ColumnSelectionMode)\n                startCharIndex = Math.Min(Selection.End.iChar, Selection.Start.iChar);\n\n            BeginUpdate();\n            Selection.BeginUpdate();\n            lines.Manager.BeginAutoUndoCommands();\n            var old = Selection.Clone();\n            lines.Manager.ExecuteCommand(new SelectCommand(TextSource)); //remember selection\n\n            // Remember current selection infos\n            Range currentSelection = this.Selection.Clone();\n            Selection.Normalize();\n            int from = Selection.Start.iLine;\n            int to = Selection.End.iLine;\n\n            if (!Selection.ColumnSelectionMode)\n                if (Selection.End.iChar == 0)\n                    to--;\n\n            int numberOfDeletedWhitespacesOfFirstLine = 0;\n            int numberOfDeletetWhitespacesOfLastLine = 0;\n\n            for (int i = from; i <= to; i++)\n            {\n                if (startCharIndex > lines[i].Count)\n                    continue;\n                // Select first characters from the line\n                int endIndex = Math.Min(this.lines[i].Count, startCharIndex + this.TabLength);\n                string wasteText = this.lines[i].Text.Substring(startCharIndex, endIndex - startCharIndex);\n\n                // Only select the first whitespace characters\n                endIndex = Math.Min(endIndex, startCharIndex + wasteText.Length - wasteText.TrimStart().Length);\n\n                // Select the characters to remove\n                this.Selection = new Range(this, new Place(startCharIndex, i), new Place(endIndex, i));\n\n                // Remember characters to remove for first and last line\n                int numberOfWhitespacesToRemove = endIndex - startCharIndex;\n                if (i == currentSelection.Start.iLine)\n                {\n                    numberOfDeletedWhitespacesOfFirstLine = numberOfWhitespacesToRemove;\n                }\n\n                if (i == currentSelection.End.iLine)\n                {\n                    numberOfDeletetWhitespacesOfLastLine = numberOfWhitespacesToRemove;\n                }\n\n                // Remove marked/selected whitespace characters\n                if (!Selection.IsEmpty)\n                    this.ClearSelected();\n            }\n\n            // Restore selection\n            if (Selection.ColumnSelectionMode == false)\n            {\n                int newSelectionStartCharacterIndex = Math.Max(0,\n                    currentSelection.Start.iChar - numberOfDeletedWhitespacesOfFirstLine);\n                int newSelectionEndCharacterIndex =\n                    Math.Max(0, currentSelection.End.iChar - numberOfDeletetWhitespacesOfLastLine);\n                this.Selection.Start = new Place(newSelectionStartCharacterIndex, currentSelection.Start.iLine);\n                this.Selection.End = new Place(newSelectionEndCharacterIndex, currentSelection.End.iLine);\n            }\n            else\n            {\n                Selection = old;\n            }\n\n            lines.Manager.EndAutoUndoCommands();\n\n            needRecalc = true;\n            Selection.EndUpdate();\n            EndUpdate();\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Remove TAB in front of the caret ot the selected line.\n        /// </summary>\n        protected virtual void DecreaseIndentOfSingleLine()\n        {\n            if (this.Selection.Start.iLine != this.Selection.End.iLine)\n                return;\n\n            // Remeber current selection infos\n            Range currentSelection = this.Selection.Clone();\n            int currentLineIndex = this.Selection.Start.iLine;\n            int currentLeftSelectionStartIndex = Math.Min(this.Selection.Start.iChar, this.Selection.End.iChar);\n\n            // Determine number of whitespaces to remove\n            string lineText = this.lines[currentLineIndex].Text;\n            Match whitespacesLeftOfSelectionStartMatch =\n                new Regex(@\"\\s*\", RegexOptions.RightToLeft).Match(lineText, currentLeftSelectionStartIndex);\n            int leftOffset = whitespacesLeftOfSelectionStartMatch.Index;\n            int countOfWhitespaces = whitespacesLeftOfSelectionStartMatch.Length;\n            int numberOfCharactersToRemove = 0;\n            if (countOfWhitespaces > 0)\n            {\n                int remainder = (this.TabLength > 0)\n                    ? currentLeftSelectionStartIndex % this.TabLength\n                    : 0;\n                numberOfCharactersToRemove = (remainder != 0)\n                    ? Math.Min(remainder, countOfWhitespaces)\n                    : Math.Min(this.TabLength, countOfWhitespaces);\n            }\n\n            // Remove whitespaces if available\n            if (numberOfCharactersToRemove > 0)\n            {\n                // Start selection update\n                this.BeginUpdate();\n                this.Selection.BeginUpdate();\n                lines.Manager.BeginAutoUndoCommands();\n                lines.Manager.ExecuteCommand(new SelectCommand(TextSource)); //remember selection\n\n                // Remove whitespaces\n                this.Selection.Start = new Place(leftOffset, currentLineIndex);\n                this.Selection.End = new Place(leftOffset + numberOfCharactersToRemove, currentLineIndex);\n                ClearSelected();\n\n                // Restore selection\n                int newSelectionStartCharacterIndex = currentSelection.Start.iChar - numberOfCharactersToRemove;\n                int newSelectionEndCharacterIndex = currentSelection.End.iChar - numberOfCharactersToRemove;\n                this.Selection.Start = new Place(newSelectionStartCharacterIndex, currentLineIndex);\n                this.Selection.End = new Place(newSelectionEndCharacterIndex, currentLineIndex);\n\n                lines.Manager.ExecuteCommand(new SelectCommand(TextSource)); //remember selection\n                // End selection update\n                lines.Manager.EndAutoUndoCommands();\n                this.Selection.EndUpdate();\n                this.EndUpdate();\n            }\n\n            Invalidate();\n        }\n\n\n        /// <summary>\n        /// Insert autoindents into selected lines\n        /// </summary>\n        public virtual void DoAutoIndent()\n        {\n            if (Selection.ColumnSelectionMode)\n                return;\n            Range r = Selection.Clone();\n            r.Normalize();\n            //\n            BeginUpdate();\n            Selection.BeginUpdate();\n            lines.Manager.BeginAutoUndoCommands();\n            //\n            for (int i = r.Start.iLine; i <= r.End.iLine; i++)\n                DoAutoIndent(i);\n            //\n            lines.Manager.EndAutoUndoCommands();\n            Selection.Start = r.Start;\n            Selection.End = r.End;\n            Selection.Expand();\n            //\n            Selection.EndUpdate();\n            EndUpdate();\n        }\n\n        /// <summary>\n        /// Insert prefix into front of seletcted lines\n        /// </summary>\n        public virtual void InsertLinePrefix(string prefix)\n        {\n            Range old = Selection.Clone();\n            int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);\n            int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);\n            BeginUpdate();\n            Selection.BeginUpdate();\n            lines.Manager.BeginAutoUndoCommands();\n            lines.Manager.ExecuteCommand(new SelectCommand(TextSource));\n            int spaces = GetMinStartSpacesCount(from, to);\n            for (int i = from; i <= to; i++)\n            {\n                Selection.Start = new Place(spaces, i);\n                lines.Manager.ExecuteCommand(new InsertTextCommand(TextSource, prefix));\n            }\n\n            Selection.Start = new Place(0, from);\n            Selection.End = new Place(lines[to].Count, to);\n            needRecalc = true;\n            lines.Manager.EndAutoUndoCommands();\n            Selection.EndUpdate();\n            EndUpdate();\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Remove prefix from front of selected lines\n        /// This method ignores forward spaces of the line\n        /// </summary>\n        public virtual void RemoveLinePrefix(string prefix)\n        {\n            Range old = Selection.Clone();\n            int from = Math.Min(Selection.Start.iLine, Selection.End.iLine);\n            int to = Math.Max(Selection.Start.iLine, Selection.End.iLine);\n            BeginUpdate();\n            Selection.BeginUpdate();\n            lines.Manager.BeginAutoUndoCommands();\n            lines.Manager.ExecuteCommand(new SelectCommand(TextSource));\n            for (int i = from; i <= to; i++)\n            {\n                string text = lines[i].Text;\n                string trimmedText = text.TrimStart();\n                if (trimmedText.StartsWith(prefix))\n                {\n                    int spaces = text.Length - trimmedText.Length;\n                    Selection.Start = new Place(spaces, i);\n                    Selection.End = new Place(spaces + prefix.Length, i);\n                    ClearSelected();\n                }\n            }\n\n            Selection.Start = new Place(0, from);\n            Selection.End = new Place(lines[to].Count, to);\n            needRecalc = true;\n            lines.Manager.EndAutoUndoCommands();\n            Selection.EndUpdate();\n            EndUpdate();\n        }\n\n        /// <summary>\n        /// Begins AutoUndo block.\n        /// All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.\n        /// </summary>\n        public void BeginAutoUndo()\n        {\n            lines.Manager.BeginAutoUndoCommands();\n        }\n\n        /// <summary>\n        /// Ends AutoUndo block.\n        /// All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.\n        /// </summary>\n        public void EndAutoUndo()\n        {\n            lines.Manager.EndAutoUndoCommands();\n        }\n\n        public virtual void OnVisualMarkerClick(MouseEventArgs args, StyleVisualMarker marker)\n        {\n            if (VisualMarkerClick != null)\n                VisualMarkerClick(this, new VisualMarkerEventArgs(marker.Style, marker, args));\n            marker.Style.OnVisualMarkerClick(this, new VisualMarkerEventArgs(marker.Style, marker, args));\n        }\n\n        protected virtual void OnMarkerClick(MouseEventArgs args, VisualMarker marker)\n        {\n            if (marker is StyleVisualMarker)\n            {\n                OnVisualMarkerClick(args, marker as StyleVisualMarker);\n                return;\n            }\n\n            if (marker is CollapseFoldingMarker)\n            {\n                CollapseFoldingBlock((marker as CollapseFoldingMarker).iLine);\n                return;\n            }\n\n            if (marker is ExpandFoldingMarker)\n            {\n                ExpandFoldedBlock((marker as ExpandFoldingMarker).iLine);\n                return;\n            }\n\n            if (marker is FoldedAreaMarker)\n            {\n                //select folded block\n                int iStart = (marker as FoldedAreaMarker).iLine;\n                int iEnd = FindEndOfFoldingBlock(iStart);\n                if (iEnd < 0)\n                    return;\n                Selection.BeginUpdate();\n                Selection.Start = new Place(0, iStart);\n                Selection.End = new Place(lines[iEnd].Count, iEnd);\n                Selection.EndUpdate();\n                Invalidate();\n                return;\n            }\n        }\n\n        protected virtual void OnMarkerDoubleClick(VisualMarker marker)\n        {\n            if (marker is FoldedAreaMarker)\n            {\n                ExpandFoldedBlock((marker as FoldedAreaMarker).iLine);\n                Invalidate();\n                return;\n            }\n        }\n\n        private void ClearBracketsPositions()\n        {\n            leftBracketPosition = null;\n            rightBracketPosition = null;\n            leftBracketPosition2 = null;\n            rightBracketPosition2 = null;\n        }\n\n        /// <summary>\n        /// Highlights brackets around caret\n        /// </summary>\n        private void HighlightBrackets(char LeftBracket, char RightBracket, ref Range leftBracketPosition,\n            ref Range rightBracketPosition)\n        {\n            switch (BracketsHighlightStrategy)\n            {\n                case BracketsHighlightStrategy.Strategy1:\n                    HighlightBrackets1(LeftBracket, RightBracket, ref leftBracketPosition, ref rightBracketPosition);\n                    break;\n                case BracketsHighlightStrategy.Strategy2:\n                    HighlightBrackets2(LeftBracket, RightBracket, ref leftBracketPosition, ref rightBracketPosition);\n                    break;\n            }\n        }\n\n        private void HighlightBrackets1(char LeftBracket, char RightBracket, ref Range leftBracketPosition,\n            ref Range rightBracketPosition)\n        {\n            if (!Selection.IsEmpty)\n                return;\n            if (LinesCount == 0)\n                return;\n            //\n            Range oldLeftBracketPosition = leftBracketPosition;\n            Range oldRightBracketPosition = rightBracketPosition;\n            var range = GetBracketsRange(Selection.Start, LeftBracket, RightBracket, true);\n\n            if (range != null)\n            {\n                leftBracketPosition = new Range(this, range.Start, new Place(range.Start.iChar + 1, range.Start.iLine));\n                rightBracketPosition = new Range(this, new Place(range.End.iChar - 1, range.End.iLine), range.End);\n            }\n\n            if (oldLeftBracketPosition != leftBracketPosition ||\n                oldRightBracketPosition != rightBracketPosition)\n                Invalidate();\n        }\n\n        /// <summary>\n        /// Returns range between brackets (or null if not found)\n        /// </summary>\n        public Range GetBracketsRange(Place placeInsideBrackets, char leftBracket, char rightBracket,\n            bool includeBrackets)\n        {\n            var startRange = new Range(this, placeInsideBrackets, placeInsideBrackets);\n            var range = startRange.Clone();\n\n            Range leftBracketPosition = null;\n            Range rightBracketPosition = null;\n\n            int counter = 0;\n            int maxIterations = maxBracketSearchIterations;\n            while (range.GoLeftThroughFolded()) //move caret left\n            {\n                if (range.CharAfterStart == leftBracket) counter++;\n                if (range.CharAfterStart == rightBracket) counter--;\n                if (counter == 1)\n                {\n                    range.Start = new Place(range.Start.iChar + (!includeBrackets ? 1 : 0), range.Start.iLine);\n                    leftBracketPosition = range;\n                    break;\n                }\n\n                //\n                maxIterations--;\n                if (maxIterations <= 0) break;\n            }\n\n            //\n            range = startRange.Clone();\n            counter = 0;\n            maxIterations = maxBracketSearchIterations;\n            do\n            {\n                if (range.CharAfterStart == leftBracket) counter++;\n                if (range.CharAfterStart == rightBracket) counter--;\n                if (counter == -1)\n                {\n                    range.End = new Place(range.Start.iChar + (includeBrackets ? 1 : 0), range.Start.iLine);\n                    rightBracketPosition = range;\n                    break;\n                }\n\n                //\n                maxIterations--;\n                if (maxIterations <= 0) break;\n            } while (range.GoRightThroughFolded()); //move caret right\n\n            if (leftBracketPosition != null && rightBracketPosition != null)\n                return new Range(this, leftBracketPosition.Start, rightBracketPosition.End);\n            else\n                return null;\n        }\n\n        private void HighlightBrackets2(char LeftBracket, char RightBracket, ref Range leftBracketPosition,\n            ref Range rightBracketPosition)\n        {\n            if (!Selection.IsEmpty)\n                return;\n            if (LinesCount == 0)\n                return;\n            //\n            Range oldLeftBracketPosition = leftBracketPosition;\n            Range oldRightBracketPosition = rightBracketPosition;\n            Range range = Selection.Clone(); //need clone because we will move caret\n\n            bool found = false;\n            int counter = 0;\n            int maxIterations = maxBracketSearchIterations;\n            if (range.CharBeforeStart == RightBracket)\n            {\n                rightBracketPosition = new Range(this, range.Start.iChar - 1, range.Start.iLine, range.Start.iChar,\n                    range.Start.iLine);\n                while (range.GoLeftThroughFolded()) //move caret left\n                {\n                    if (range.CharAfterStart == LeftBracket) counter++;\n                    if (range.CharAfterStart == RightBracket) counter--;\n                    if (counter == 0)\n                    {\n                        //highlighting\n                        range.End = new Place(range.Start.iChar + 1, range.Start.iLine);\n                        leftBracketPosition = range;\n                        found = true;\n                        break;\n                    }\n\n                    //\n                    maxIterations--;\n                    if (maxIterations <= 0) break;\n                }\n            }\n\n            //\n            range = Selection.Clone(); //need clone because we will move caret\n            counter = 0;\n            maxIterations = maxBracketSearchIterations;\n            if (!found)\n                if (range.CharAfterStart == LeftBracket)\n                {\n                    leftBracketPosition = new Range(this, range.Start.iChar, range.Start.iLine, range.Start.iChar + 1,\n                        range.Start.iLine);\n                    do\n                    {\n                        if (range.CharAfterStart == LeftBracket) counter++;\n                        if (range.CharAfterStart == RightBracket) counter--;\n                        if (counter == 0)\n                        {\n                            //highlighting\n                            range.End = new Place(range.Start.iChar + 1, range.Start.iLine);\n                            rightBracketPosition = range;\n                            found = true;\n                            break;\n                        }\n\n                        //\n                        maxIterations--;\n                        if (maxIterations <= 0) break;\n                    } while (range.GoRightThroughFolded()); //move caret right\n                }\n\n            if (oldLeftBracketPosition != leftBracketPosition || oldRightBracketPosition != rightBracketPosition)\n                Invalidate();\n        }\n\n        /// <summary>\n        /// Selectes next fragment for given regex.\n        /// </summary>\n        public bool SelectNext(string regexPattern, bool backward = false, RegexOptions options = RegexOptions.None)\n        {\n            var sel = Selection.Clone();\n            sel.Normalize();\n            var range1 = backward ? new Range(this, Range.Start, sel.Start) : new Range(this, sel.End, Range.End);\n\n            Range res = null;\n            foreach (var r in range1.GetRanges(regexPattern, options))\n            {\n                res = r;\n                if (!backward) break;\n            }\n\n            if (res == null) return false;\n            Selection = res;\n            Invalidate();\n            return true;\n        }\n\n        public virtual void OnSyntaxHighlight(TextChangedEventArgs args)\n        {\n#if debug\n            Stopwatch sw = Stopwatch.StartNew();\n#endif\n\n            Range range;\n\n            switch (HighlightingRangeType)\n            {\n                case HighlightingRangeType.VisibleRange:\n                    range = VisibleRange.GetUnionWith(args.ChangedRange);\n                    break;\n                case HighlightingRangeType.AllTextRange:\n                    range = Range;\n                    break;\n                default:\n                    range = args.ChangedRange;\n                    break;\n            }\n\n            if (SyntaxHighlighter != null)\n            {\n                if (!string.IsNullOrEmpty(DescriptionFile))\n                    SyntaxHighlighter.HighlightSyntax(DescriptionFile, range);\n                else\n                    SyntaxHighlighter.HighlightSyntax(Language, range);\n            }\n\n#if debug\n            Console.WriteLine(\"OnSyntaxHighlight: \"+ sw.ElapsedMilliseconds);\n#endif\n        }\n\n        private void InitializeComponent()\n        {\n            SuspendLayout();\n            // \n            // FastColoredTextBox\n            // \n            Name = \"FastColoredTextBox\";\n            ResumeLayout(false);\n        }\n\n        /// <summary>\n        /// Prints range of text\n        /// </summary>\n        public virtual void Print(Range range, PrintDialogSettings settings)\n        {\n            //prepare export with wordwrapping\n            var exporter = new ExportToHTML();\n            exporter.UseBr = true;\n            exporter.UseForwardNbsp = true;\n            exporter.UseNbsp = true;\n            exporter.UseStyleTag = false;\n            exporter.IncludeLineNumbers = settings.IncludeLineNumbers;\n\n            if (range == null)\n                range = Range;\n\n            if (range.Text == string.Empty)\n                return;\n\n            //change visible range\n            visibleRange = range;\n            try\n            {\n                //call handlers for VisibleRange\n                if (VisibleRangeChanged != null)\n                    VisibleRangeChanged(this, new EventArgs());\n                if (VisibleRangeChangedDelayed != null)\n                    VisibleRangeChangedDelayed(this, new EventArgs());\n            }\n            finally\n            {\n                //restore visible range\n                visibleRange = null;\n            }\n\n            //generate HTML\n            string HTML = exporter.GetHtml(range);\n            HTML = \"<META HTTP-EQUIV=\\\"Content-Type\\\" CONTENT=\\\"text/html; charset=UTF-8\\\"><head><title>\" +\n                   PrepareHtmlText(settings.Title) + \"</title></head>\" + HTML + \"<br>\" + SelectHTMLRangeScript();\n            string tempFile = Path.GetTempPath() + \"fctb.html\";\n            File.WriteAllText(tempFile, HTML);\n\n            //clear wb page setup settings\n            SetPageSetupSettings(settings);\n\n            //create wb\n            var wb = new WebBrowser();\n            wb.Tag = settings;\n            wb.Visible = false;\n            wb.Location = new Point(-1000, -1000);\n            wb.Parent = this;\n            wb.StatusTextChanged += wb_StatusTextChanged;\n            wb.Navigate(tempFile);\n        }\n\n        protected virtual string PrepareHtmlText(string s)\n        {\n            return s.Replace(\"<\", \"&lt;\").Replace(\">\", \"&gt;\").Replace(\"&\", \"&amp;\");\n        }\n\n        private void wb_StatusTextChanged(object sender, EventArgs e)\n        {\n            var wb = sender as WebBrowser;\n            if (wb.StatusText.Contains(\"#print\"))\n            {\n                var settings = wb.Tag as PrintDialogSettings;\n                try\n                {\n                    //show print dialog\n                    if (settings.ShowPrintPreviewDialog)\n                        wb.ShowPrintPreviewDialog();\n                    else\n                    {\n                        if (settings.ShowPageSetupDialog)\n                            wb.ShowPageSetupDialog();\n\n                        if (settings.ShowPrintDialog)\n                            wb.ShowPrintDialog();\n                        else\n                            wb.Print();\n                    }\n                }\n                finally\n                {\n                    //destroy webbrowser\n                    wb.Parent = null;\n                    wb.Dispose();\n                }\n            }\n        }\n\n        /// <summary>\n        /// Prints all text\n        /// </summary>\n        public void Print(PrintDialogSettings settings)\n        {\n            Print(Range, settings);\n        }\n\n        /// <summary>\n        /// Prints all text, without any dialog windows\n        /// </summary>\n        public void Print()\n        {\n            Print(Range,\n                new PrintDialogSettings\n                    {ShowPageSetupDialog = false, ShowPrintDialog = false, ShowPrintPreviewDialog = false});\n        }\n\n        private string SelectHTMLRangeScript()\n        {\n            Range sel = Selection.Clone();\n            sel.Normalize();\n            int start = PlaceToPosition(sel.Start) - sel.Start.iLine;\n            int len = sel.Text.Length - (sel.End.iLine - sel.Start.iLine);\n            return string.Format(\n                @\"<script type=\"\"text/javascript\"\">\ntry{{\n    var sel = document.selection;\n    var rng = sel.createRange();\n    rng.moveStart(\"\"character\"\", {0});\n    rng.moveEnd(\"\"character\"\", {1});\n    rng.select();\n}}catch(ex){{}}\nwindow.status = \"\"#print\"\";\n</script>\",\n                start, len);\n        }\n\n        private static void SetPageSetupSettings(PrintDialogSettings settings)\n        {\n            RegistryKey key = Registry.CurrentUser.OpenSubKey(@\"Software\\Microsoft\\Internet Explorer\\PageSetup\", true);\n            if (key != null)\n            {\n                key.SetValue(\"footer\", settings.Footer);\n                key.SetValue(\"header\", settings.Header);\n            }\n        }\n\n        protected override void Dispose(bool disposing)\n        {\n            base.Dispose(disposing);\n            if (disposing)\n            {\n                if (SyntaxHighlighter != null)\n                    SyntaxHighlighter.Dispose();\n                timer.Dispose();\n                timer2.Dispose();\n                middleClickScrollingTimer.Dispose();\n\n                if (findForm != null)\n                    findForm.Dispose();\n\n                if (replaceForm != null)\n                    replaceForm.Dispose();\n                /*\n                if (Font != null)\n                    Font.Dispose();\n\n                if (originalFont != null)\n                    originalFont.Dispose();*/\n\n                if (TextSource != null)\n                    TextSource.Dispose();\n\n                if (ToolTip != null)\n                    ToolTip.Dispose();\n            }\n        }\n\n        protected virtual void OnPaintLine(PaintLineEventArgs e)\n        {\n            if (PaintLine != null)\n                PaintLine(this, e);\n        }\n\n        internal void OnLineInserted(int index)\n        {\n            OnLineInserted(index, 1);\n        }\n\n        internal void OnLineInserted(int index, int count)\n        {\n            if (LineInserted != null)\n                LineInserted(this, new LineInsertedEventArgs(index, count));\n        }\n\n        internal void OnLineRemoved(int index, int count, List<int> removedLineIds)\n        {\n            if (count > 0)\n                if (LineRemoved != null)\n                    LineRemoved(this, new LineRemovedEventArgs(index, count, removedLineIds));\n        }\n\n        /// <summary>\n        /// Open text file\n        /// </summary>\n        public void OpenFile(string fileName, Encoding enc)\n        {\n            var ts = CreateTextSource();\n            try\n            {\n                InitTextSource(ts);\n                Text = File.ReadAllText(fileName, enc);\n                ClearUndo();\n                IsChanged = false;\n                OnVisibleRangeChanged();\n            }\n            catch\n            {\n                InitTextSource(CreateTextSource());\n                lines.InsertLine(0, TextSource.CreateLine());\n                IsChanged = false;\n                throw;\n            }\n\n            Selection.Start = Place.Empty;\n            DoSelectionVisible();\n        }\n\n        /// <summary>\n        /// Open text file (with automatic encoding detector)\n        /// </summary>\n        public void OpenFile(string fileName)\n        {\n            try\n            {\n                var enc = EncodingDetector.DetectTextFileEncoding(fileName);\n                if (enc != null)\n                    OpenFile(fileName, enc);\n                else\n                    OpenFile(fileName, Encoding.Default);\n            }\n            catch\n            {\n                InitTextSource(CreateTextSource());\n                lines.InsertLine(0, TextSource.CreateLine());\n                IsChanged = false;\n                throw;\n            }\n        }\n\n        /// <summary>\n        /// Open file binding mode\n        /// </summary>\n        /// <param name=\"fileName\"></param>\n        /// <param name=\"enc\"></param>\n        public void OpenBindingFile(string fileName, Encoding enc)\n        {\n            var fts = new FileTextSource(this);\n            try\n            {\n                InitTextSource(fts);\n                fts.OpenFile(fileName, enc);\n                IsChanged = false;\n                OnVisibleRangeChanged();\n            }\n            catch\n            {\n                fts.CloseFile();\n                InitTextSource(CreateTextSource());\n                lines.InsertLine(0, TextSource.CreateLine());\n                IsChanged = false;\n                throw;\n            }\n\n            Invalidate();\n        }\n\n        /// <summary>\n        /// Close file binding mode\n        /// </summary>\n        public void CloseBindingFile()\n        {\n            if (lines is FileTextSource)\n            {\n                var fts = lines as FileTextSource;\n                fts.CloseFile();\n\n                InitTextSource(CreateTextSource());\n                lines.InsertLine(0, TextSource.CreateLine());\n                IsChanged = false;\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Save text to the file\n        /// </summary>\n        /// <param name=\"fileName\"></param>\n        /// <param name=\"enc\"></param>\n        public void SaveToFile(string fileName, Encoding enc)\n        {\n            lines.SaveToFile(fileName, enc);\n            IsChanged = false;\n            OnVisibleRangeChanged();\n            UpdateScrollbars();\n        }\n\n        /// <summary>\n        /// Set VisibleState of line\n        /// </summary>\n        public void SetVisibleState(int iLine, VisibleState state)\n        {\n            LineInfo li = LineInfos[iLine];\n            li.VisibleState = state;\n            LineInfos[iLine] = li;\n            needRecalc = true;\n        }\n\n        /// <summary>\n        /// Returns VisibleState of the line\n        /// </summary>\n        public VisibleState GetVisibleState(int iLine)\n        {\n            return LineInfos[iLine].VisibleState;\n        }\n\n        /// <summary>\n        /// Shows Goto dialog form\n        /// </summary>\n        public void ShowGoToDialog()\n        {\n            var form = new GoToForm();\n            form.TotalLineCount = LinesCount;\n            form.SelectedLineNumber = Selection.Start.iLine + 1;\n\n            if (form.ShowDialog() == DialogResult.OK)\n            {\n                int line = Math.Min(LinesCount - 1, Math.Max(0, form.SelectedLineNumber - 1));\n                Selection = new Range(this, 0, line, 0, line);\n                DoSelectionVisible();\n            }\n        }\n\n        /// <summary>\n        /// Occurs when undo/redo stack is changed\n        /// </summary>\n        public void OnUndoRedoStateChanged()\n        {\n            if (UndoRedoStateChanged != null)\n                UndoRedoStateChanged(this, EventArgs.Empty);\n        }\n\n        /// <summary>\n        /// Search lines by regex pattern\n        /// </summary>\n        public List<int> FindLines(string searchPattern, RegexOptions options)\n        {\n            var iLines = new List<int>();\n            foreach (Range r in Range.GetRangesByLines(searchPattern, options))\n                iLines.Add(r.Start.iLine);\n\n            return iLines;\n        }\n\n        /// <summary>\n        /// Removes given lines\n        /// </summary>\n        public void RemoveLines(List<int> iLines)\n        {\n            TextSource.Manager.ExecuteCommand(new RemoveLinesCommand(TextSource, iLines));\n            if (iLines.Count > 0)\n                IsChanged = true;\n            if (LinesCount == 0)\n                Text = \"\";\n            NeedRecalc();\n            Invalidate();\n        }\n\n        void ISupportInitialize.BeginInit()\n        {\n            //\n        }\n\n        void ISupportInitialize.EndInit()\n        {\n            OnTextChanged();\n            Selection.Start = Place.Empty;\n            DoCaretVisible();\n            IsChanged = false;\n            ClearUndo();\n        }\n\n        #region Drag and drop\n\n        private bool IsDragDrop { get; set; }\n\n\n        protected override void OnDragEnter(DragEventArgs e)\n        {\n            if (e.Data.GetDataPresent(DataFormats.Text) && AllowDrop)\n            {\n                e.Effect = DragDropEffects.Copy;\n                IsDragDrop = true;\n            }\n\n            base.OnDragEnter(e);\n        }\n\n        protected override void OnDragDrop(DragEventArgs e)\n        {\n            if (ReadOnly || !AllowDrop)\n            {\n                IsDragDrop = false;\n                return;\n            }\n\n            if (e.Data.GetDataPresent(DataFormats.Text))\n            {\n                if (ParentForm != null)\n                    ParentForm.Activate();\n                Focus();\n                Point p = PointToClient(new Point(e.X, e.Y));\n                var text = e.Data.GetData(DataFormats.Text).ToString();\n                var place = PointToPlace(p);\n                DoDragDrop(place, text);\n                IsDragDrop = false;\n            }\n\n            base.OnDragDrop(e);\n        }\n\n        private void DoDragDrop_old(Place place, string text)\n        {\n            Range insertRange = new Range(this, place, place);\n\n            // Abort, if insertRange is read only\n            if (insertRange.ReadOnly)\n                return;\n\n            // Abort, if dragged range contains target place\n            if ((draggedRange != null) && (draggedRange.Contains(place) == true))\n                return;\n\n            // Determine, if the dragged string should be copied or moved\n            bool copyMode =\n                (draggedRange == null) || // drag from outside\n                (draggedRange.ReadOnly) || // dragged range is read only\n                ((ModifierKeys & Keys.Control) != Keys.None);\n\n            //drag from outside?\n            if (draggedRange == null)\n            {\n                Selection.BeginUpdate();\n                // Insert text\n                Selection.Start = place;\n                InsertText(text);\n                // Select inserted text\n                Selection = new Range(this, place, Selection.Start);\n                Selection.EndUpdate();\n                return;\n            }\n\n            //drag from me\n            Place caretPositionAfterInserting;\n            BeginAutoUndo();\n            Selection.BeginUpdate();\n\n            //remember dragged selection for undo/redo\n            Selection = draggedRange;\n            lines.Manager.ExecuteCommand(new SelectCommand(lines));\n            //\n            if (draggedRange.ColumnSelectionMode)\n            {\n                draggedRange.Normalize();\n                insertRange =\n                    new Range(this, place,\n                            new Place(place.iChar, place.iLine + draggedRange.End.iLine - draggedRange.Start.iLine))\n                        {ColumnSelectionMode = true};\n                for (int i = LinesCount; i <= insertRange.End.iLine; i++)\n                {\n                    Selection.GoLast(false);\n                    InsertChar('\\n');\n                }\n            }\n\n            if (!insertRange.ReadOnly)\n            {\n                if (place < draggedRange.Start)\n                {\n                    // Delete dragged range if not in copy mode\n                    if (copyMode == false)\n                    {\n                        Selection = draggedRange;\n                        ClearSelected();\n                    }\n\n                    // Insert text\n                    Selection = insertRange;\n                    Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;\n                    InsertText(text);\n                    caretPositionAfterInserting = Selection.Start;\n                }\n                else\n                {\n                    // Insert text\n                    Selection = insertRange;\n                    Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;\n                    InsertText(text);\n                    caretPositionAfterInserting = Selection.Start;\n                    var lineLength = this[caretPositionAfterInserting.iLine].Count;\n\n                    // Delete dragged range if not in copy mode\n                    if (copyMode == false)\n                    {\n                        Selection = draggedRange;\n                        ClearSelected();\n                    }\n\n                    var shift = lineLength - this[caretPositionAfterInserting.iLine].Count;\n                    caretPositionAfterInserting.iChar = caretPositionAfterInserting.iChar - shift;\n                    place.iChar = place.iChar - shift;\n                }\n\n                // Select inserted text\n                if (!draggedRange.ColumnSelectionMode)\n                {\n                    Selection = new Range(this, place, caretPositionAfterInserting);\n                }\n                else\n                {\n                    draggedRange.Normalize();\n                    Selection = new Range(this, place,\n                            new Place(place.iChar + draggedRange.End.iChar - draggedRange.Start.iChar,\n                                place.iLine + draggedRange.End.iLine - draggedRange.Start.iLine))\n                        {ColumnSelectionMode = true};\n                }\n            }\n\n            Selection.EndUpdate();\n            EndAutoUndo();\n            draggedRange = null;\n        }\n\n        protected virtual void DoDragDrop(Place place, string text)\n        {\n            Range insertRange = new Range(this, place, place);\n\n            // Abort, if insertRange is read only\n            if (insertRange.ReadOnly)\n                return;\n\n            // Abort, if dragged range contains target place\n            if ((draggedRange != null) && (draggedRange.Contains(place) == true))\n                return;\n\n            // Determine, if the dragged string should be copied or moved\n            bool copyMode =\n                (draggedRange == null) || // drag from outside\n                (draggedRange.ReadOnly) || // dragged range is read only\n                ((ModifierKeys & Keys.Control) != Keys.None);\n\n            if (draggedRange == null) //drag from outside\n            {\n                Selection.BeginUpdate();\n                // Insert text\n                Selection.Start = place;\n                InsertText(text);\n                // Select inserted text\n                Selection = new Range(this, place, Selection.Start);\n                Selection.EndUpdate();\n            }\n            else //drag from me\n            {\n                if (!draggedRange.Contains(place))\n                {\n                    BeginAutoUndo();\n\n                    //remember dragged selection for undo/redo\n                    Selection = draggedRange;\n                    lines.Manager.ExecuteCommand(new SelectCommand(lines));\n                    //\n                    if (draggedRange.ColumnSelectionMode)\n                    {\n                        draggedRange.Normalize();\n                        insertRange =\n                            new Range(this, place,\n                                    new Place(place.iChar,\n                                        place.iLine + draggedRange.End.iLine - draggedRange.Start.iLine))\n                                {ColumnSelectionMode = true};\n                        for (int i = LinesCount; i <= insertRange.End.iLine; i++)\n                        {\n                            Selection.GoLast(false);\n                            InsertChar('\\n');\n                        }\n                    }\n\n                    if (!insertRange.ReadOnly)\n                    {\n                        if (place < draggedRange.Start)\n                        {\n                            // Delete dragged range if not in copy mode\n                            if (copyMode == false)\n                            {\n                                Selection = draggedRange;\n                                ClearSelected();\n                            }\n\n                            // Insert text\n                            Selection = insertRange;\n                            Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;\n                            InsertText(text);\n                        }\n                        else\n                        {\n                            // Insert text\n                            Selection = insertRange;\n                            Selection.ColumnSelectionMode = insertRange.ColumnSelectionMode;\n                            InsertText(text);\n\n                            // Delete dragged range if not in copy mode\n                            if (copyMode == false)\n                            {\n                                Selection = draggedRange;\n                                ClearSelected();\n                            }\n                        }\n                    }\n\n                    // Selection start and end position\n                    Place startPosition = place;\n                    Place endPosition = Selection.Start;\n\n                    // Correct selection\n                    Range dR = (draggedRange.End > draggedRange.Start) // dragged selection\n                        ? this.GetRange(draggedRange.Start, draggedRange.End)\n                        : this.GetRange(draggedRange.End, draggedRange.Start);\n                    Place tP = place; // targetPlace\n                    int tS_S_Line; // targetSelection.Start.iLine\n                    int tS_S_Char; // targetSelection.Start.iChar\n                    int tS_E_Line; // targetSelection.End.iLine\n                    int tS_E_Char; // targetSelection.End.iChar\n                    if ((place > draggedRange.Start) && (copyMode == false))\n                    {\n                        if (draggedRange.ColumnSelectionMode == false)\n                        {\n                            // Normal selection mode:\n\n                            // Determine character/column position of target selection\n                            if (dR.Start.iLine != dR.End.iLine) // If more then one line was selected/dragged ...\n                            {\n                                tS_S_Char = (dR.End.iLine != tP.iLine)\n                                    ? tP.iChar\n                                    : dR.Start.iChar + (tP.iChar - dR.End.iChar);\n                                tS_E_Char = dR.End.iChar;\n                            }\n                            else // only one line was selected/dragged\n                            {\n                                if (dR.End.iLine == tP.iLine)\n                                {\n                                    tS_S_Char = tP.iChar - dR.Text.Length;\n                                    tS_E_Char = tP.iChar;\n                                }\n                                else\n                                {\n                                    tS_S_Char = tP.iChar;\n                                    tS_E_Char = tP.iChar + dR.Text.Length;\n                                }\n                            }\n\n                            // Determine line/row of target selection\n                            if (dR.End.iLine != tP.iLine)\n                            {\n                                tS_S_Line = tP.iLine - (dR.End.iLine - dR.Start.iLine);\n                                tS_E_Line = tP.iLine;\n                            }\n                            else\n                            {\n                                tS_S_Line = dR.Start.iLine;\n                                tS_E_Line = dR.End.iLine;\n                            }\n\n                            startPosition = new Place(tS_S_Char, tS_S_Line);\n                            endPosition = new Place(tS_E_Char, tS_E_Line);\n                        }\n                    }\n\n\n                    // Select inserted text\n                    if (!draggedRange.ColumnSelectionMode)\n                        Selection = new Range(this, startPosition, endPosition);\n                    else\n                    {\n                        if ((copyMode == false) &&\n                            (place.iLine >= dR.Start.iLine) && (place.iLine <= dR.End.iLine) &&\n                            (place.iChar >= dR.End.iChar))\n                        {\n                            tS_S_Char = tP.iChar - (dR.End.iChar - dR.Start.iChar);\n                            tS_E_Char = tP.iChar;\n                        }\n                        else\n                        {\n                            tS_S_Char = tP.iChar;\n                            tS_E_Char = tP.iChar + (dR.End.iChar - dR.Start.iChar);\n                        }\n\n                        tS_S_Line = tP.iLine;\n                        tS_E_Line = tP.iLine + (dR.End.iLine - dR.Start.iLine);\n\n                        startPosition = new Place(tS_S_Char, tS_S_Line);\n                        endPosition = new Place(tS_E_Char, tS_E_Line);\n                        Selection = new Range(this, startPosition, endPosition)\n                        {\n                            ColumnSelectionMode = true\n                        };\n                    }\n\n                    EndAutoUndo();\n                }\n\n                this.selection.Inverse();\n                OnSelectionChanged();\n            }\n\n            draggedRange = null;\n        }\n\n        protected override void OnDragOver(DragEventArgs e)\n        {\n            if (e.Data.GetDataPresent(DataFormats.Text))\n            {\n                Point p = PointToClient(new Point(e.X, e.Y));\n                Selection.Start = PointToPlace(p);\n                if (p.Y < 6 && VerticalScroll.Visible && VerticalScroll.Value > 0)\n                    VerticalScroll.Value = Math.Max(0, VerticalScroll.Value - charHeight);\n\n                DoCaretVisible();\n                Invalidate();\n            }\n\n            base.OnDragOver(e);\n        }\n\n        protected override void OnDragLeave(EventArgs e)\n        {\n            IsDragDrop = false;\n            base.OnDragLeave(e);\n        }\n\n        #endregion\n\n        #region MiddleClickScrolling\n\n        private bool middleClickScrollingActivated;\n        private Point middleClickScrollingOriginPoint;\n        private Point middleClickScrollingOriginScroll;\n        private readonly Timer middleClickScrollingTimer = new Timer();\n        private ScrollDirection middleClickScollDirection = ScrollDirection.None;\n\n        /// <summary>\n        /// Activates the scrolling mode (middle click button).\n        /// </summary>\n        /// <param name=\"e\">MouseEventArgs</param>\n        private void ActivateMiddleClickScrollingMode(MouseEventArgs e)\n        {\n            if (!middleClickScrollingActivated)\n            {\n                if ((!HorizontalScroll.Visible) && (!VerticalScroll.Visible))\n                    if (ShowScrollBars)\n                        return;\n                middleClickScrollingActivated = true;\n                middleClickScrollingOriginPoint = e.Location;\n                middleClickScrollingOriginScroll = new Point(HorizontalScroll.Value, VerticalScroll.Value);\n                middleClickScrollingTimer.Interval = 50;\n                middleClickScrollingTimer.Enabled = true;\n                Capture = true;\n                // Refresh the control \n                Refresh();\n                // Disable drawing\n                NativeMethodWrapper.SendMessage(Handle, WM_SETREDRAW, 0, 0);\n            }\n        }\n\n        /// <summary>\n        /// Deactivates the scrolling mode (middle click button).\n        /// </summary>\n        private void DeactivateMiddleClickScrollingMode()\n        {\n            if (middleClickScrollingActivated)\n            {\n                middleClickScrollingActivated = false;\n                middleClickScrollingTimer.Enabled = false;\n                Capture = false;\n                base.Cursor = defaultCursor;\n                // Enable drawing\n                NativeMethodWrapper.SendMessage(Handle, WM_SETREDRAW, 1, 0);\n                Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// Restore scrolls\n        /// </summary>\n        private void RestoreScrollsAfterMiddleClickScrollingMode()\n        {\n            var xea = new ScrollEventArgs(ScrollEventType.ThumbPosition,\n                HorizontalScroll.Value,\n                middleClickScrollingOriginScroll.X,\n                ScrollOrientation.HorizontalScroll);\n            OnScroll(xea);\n\n            var yea = new ScrollEventArgs(ScrollEventType.ThumbPosition,\n                VerticalScroll.Value,\n                middleClickScrollingOriginScroll.Y,\n                ScrollOrientation.VerticalScroll);\n            OnScroll(yea);\n        }\n\n       \n\n        private const int WM_SETREDRAW = 0xB;\n\n        void middleClickScrollingTimer_Tick(object sender, EventArgs e)\n        {\n            if (IsDisposed)\n                return;\n\n            if (!middleClickScrollingActivated)\n                return;\n\n            Point currentMouseLocation = PointToClient(Cursor.Position);\n\n            Capture = true;\n\n            // Calculate angle and distance between current position point and origin point\n            int distanceX = this.middleClickScrollingOriginPoint.X - currentMouseLocation.X;\n            int distanceY = this.middleClickScrollingOriginPoint.Y - currentMouseLocation.Y;\n\n            if (!VerticalScroll.Visible && ShowScrollBars) distanceY = 0;\n            if (!HorizontalScroll.Visible && ShowScrollBars) distanceX = 0;\n\n            double angleInDegree = 180 - Math.Atan2(distanceY, distanceX) * 180 / Math.PI;\n            double distance = Math.Sqrt(Math.Pow(distanceX, 2) + Math.Pow(distanceY, 2));\n\n            // determine scrolling direction depending on the angle\n            if (distance > 10)\n            {\n                if (angleInDegree >= 325 || angleInDegree <= 35)\n                    this.middleClickScollDirection = ScrollDirection.Right;\n                else if (angleInDegree <= 55)\n                    this.middleClickScollDirection = ScrollDirection.Right | ScrollDirection.Up;\n                else if (angleInDegree <= 125)\n                    this.middleClickScollDirection = ScrollDirection.Up;\n                else if (angleInDegree <= 145)\n                    this.middleClickScollDirection = ScrollDirection.Up | ScrollDirection.Left;\n                else if (angleInDegree <= 215)\n                    this.middleClickScollDirection = ScrollDirection.Left;\n                else if (angleInDegree <= 235)\n                    this.middleClickScollDirection = ScrollDirection.Left | ScrollDirection.Down;\n                else if (angleInDegree <= 305)\n                    this.middleClickScollDirection = ScrollDirection.Down;\n                else\n                    this.middleClickScollDirection = ScrollDirection.Down | ScrollDirection.Right;\n            }\n            else\n            {\n                this.middleClickScollDirection = ScrollDirection.None;\n            }\n\n            // Set mouse cursor\n            switch (this.middleClickScollDirection)\n            {\n                case ScrollDirection.Right:\n                    base.Cursor = Cursors.PanEast;\n                    break;\n                case ScrollDirection.Right | ScrollDirection.Up:\n                    base.Cursor = Cursors.PanNE;\n                    break;\n                case ScrollDirection.Up:\n                    base.Cursor = Cursors.PanNorth;\n                    break;\n                case ScrollDirection.Up | ScrollDirection.Left:\n                    base.Cursor = Cursors.PanNW;\n                    break;\n                case ScrollDirection.Left:\n                    base.Cursor = Cursors.PanWest;\n                    break;\n                case ScrollDirection.Left | ScrollDirection.Down:\n                    base.Cursor = Cursors.PanSW;\n                    break;\n                case ScrollDirection.Down:\n                    base.Cursor = Cursors.PanSouth;\n                    break;\n                case ScrollDirection.Down | ScrollDirection.Right:\n                    base.Cursor = Cursors.PanSE;\n                    break;\n                default:\n                    base.Cursor = defaultCursor;\n                    return;\n            }\n\n            var xScrollOffset = (int) (-distanceX / 5.0);\n            var yScrollOffset = (int) (-distanceY / 5.0);\n\n            var xea = new ScrollEventArgs(\n                xScrollOffset < 0 ? ScrollEventType.SmallIncrement : ScrollEventType.SmallDecrement,\n                HorizontalScroll.Value,\n                HorizontalScroll.Value + xScrollOffset,\n                ScrollOrientation.HorizontalScroll);\n\n            var yea = new ScrollEventArgs(\n                yScrollOffset < 0 ? ScrollEventType.SmallDecrement : ScrollEventType.SmallIncrement,\n                VerticalScroll.Value,\n                VerticalScroll.Value + yScrollOffset,\n                ScrollOrientation.VerticalScroll);\n\n            if ((middleClickScollDirection & (ScrollDirection.Down | ScrollDirection.Up)) > 0)\n                //DoScrollVertical(1 + Math.Abs(yScrollOffset), Math.Sign(distanceY));\n                OnScroll(yea, false);\n\n            if ((middleClickScollDirection & (ScrollDirection.Right | ScrollDirection.Left)) > 0)\n                OnScroll(xea);\n\n            // Enable drawing\n            NativeMethodWrapper.SendMessage(Handle, WM_SETREDRAW, 1, 0);\n            // Refresh the control \n            Refresh();\n            // Disable drawing\n            NativeMethodWrapper.SendMessage(Handle, WM_SETREDRAW, 0, 0);\n        }\n\n        private void DrawMiddleClickScrolling(Graphics gr)\n        {\n            // If mouse scrolling mode activated draw the scrolling cursor image\n            bool ableToScrollVertically = this.VerticalScroll.Visible || !ShowScrollBars;\n            bool ableToScrollHorizontally = this.HorizontalScroll.Visible || !ShowScrollBars;\n\n            // Calculate inverse color\n            Color inverseColor = Color.FromArgb(100, (byte) ~this.BackColor.R, (byte) ~this.BackColor.G,\n                (byte) ~this.BackColor.B);\n            using (SolidBrush inverseColorBrush = new SolidBrush(inverseColor))\n            {\n                var p = middleClickScrollingOriginPoint;\n\n                var state = gr.Save();\n\n                gr.SmoothingMode = SmoothingMode.HighQuality;\n                gr.TranslateTransform(p.X, p.Y);\n                gr.FillEllipse(inverseColorBrush, -2, -2, 4, 4);\n\n                if (ableToScrollVertically) DrawTriangle(gr, inverseColorBrush);\n                gr.RotateTransform(90);\n                if (ableToScrollHorizontally) DrawTriangle(gr, inverseColorBrush);\n                gr.RotateTransform(90);\n                if (ableToScrollVertically) DrawTriangle(gr, inverseColorBrush);\n                gr.RotateTransform(90);\n                if (ableToScrollHorizontally) DrawTriangle(gr, inverseColorBrush);\n\n                gr.Restore(state);\n            }\n        }\n\n        private void DrawTriangle(Graphics g, Brush brush)\n        {\n            const int size = 5;\n            var points = new Point[] {new Point(size, 2 * size), new Point(0, 3 * size), new Point(-size, 2 * size)};\n            g.FillPolygon(brush, points);\n        }\n\n        #endregion\n\n\n        #region Nested type: LineYComparer\n\n        private class LineYComparer : IComparer<LineInfo>\n        {\n            private readonly int Y;\n\n            public LineYComparer(int Y)\n            {\n                this.Y = Y;\n            }\n\n            #region IComparer<LineInfo> Members\n\n            public int Compare(LineInfo x, LineInfo y)\n            {\n                if (x.startY == -10)\n                    return -y.startY.CompareTo(Y);\n                else\n                    return x.startY.CompareTo(Y);\n            }\n\n            #endregion\n        }\n\n        #endregion\n    }\n\n    public class PaintLineEventArgs : PaintEventArgs\n    {\n        public PaintLineEventArgs(int iLine, Rectangle rect, Graphics gr, Rectangle clipRect) : base(gr, clipRect)\n        {\n            LineIndex = iLine;\n            LineRect = rect;\n        }\n\n        public int LineIndex { get; private set; }\n        public Rectangle LineRect { get; private set; }\n    }\n\n    public class LineInsertedEventArgs : EventArgs\n    {\n        public LineInsertedEventArgs(int index, int count)\n        {\n            Index = index;\n            Count = count;\n        }\n\n        /// <summary>\n        /// Inserted line index\n        /// </summary>\n        public int Index { get; private set; }\n\n        /// <summary>\n        /// Count of inserted lines\n        /// </summary>\n        public int Count { get; private set; }\n    }\n\n    public class LineRemovedEventArgs : EventArgs\n    {\n        public LineRemovedEventArgs(int index, int count, List<int> removedLineIds)\n        {\n            Index = index;\n            Count = count;\n            RemovedLineUniqueIds = removedLineIds;\n        }\n\n        /// <summary>\n        /// Removed line index\n        /// </summary>\n        public int Index { get; private set; }\n\n        /// <summary>\n        /// Count of removed lines\n        /// </summary>\n        public int Count { get; private set; }\n\n        /// <summary>\n        /// UniqueIds of removed lines\n        /// </summary>\n        public List<int> RemovedLineUniqueIds { get; private set; }\n    }\n\n    /// <summary>\n    /// TextChanged event argument\n    /// </summary>\n    public class TextChangedEventArgs : EventArgs\n    {\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        public TextChangedEventArgs(Range changedRange)\n        {\n            ChangedRange = changedRange;\n        }\n\n        /// <summary>\n        /// This range contains changed area of text\n        /// </summary>\n        public Range ChangedRange { get; set; }\n    }\n\n    public class TextChangingEventArgs : EventArgs\n    {\n        public string InsertingText { get; set; }\n\n        /// <summary>\n        /// Set to true if you want to cancel text inserting\n        /// </summary>\n        public bool Cancel { get; set; }\n    }\n\n    public class WordWrapNeededEventArgs : EventArgs\n    {\n        public List<int> CutOffPositions { get; private set; }\n        public bool ImeAllowed { get; private set; }\n        public Line Line { get; private set; }\n\n        public WordWrapNeededEventArgs(List<int> cutOffPositions, bool imeAllowed, Line line)\n        {\n            this.CutOffPositions = cutOffPositions;\n            this.ImeAllowed = imeAllowed;\n            this.Line = line;\n        }\n    }\n\n    public enum WordWrapMode\n    {\n        /// <summary>\n        /// Word wrapping by control width\n        /// </summary>\n        WordWrapControlWidth,\n\n        /// <summary>\n        /// Word wrapping by preferred line width (PreferredLineWidth)\n        /// </summary>\n        WordWrapPreferredWidth,\n\n        /// <summary>\n        /// Char wrapping by control width\n        /// </summary>\n        CharWrapControlWidth,\n\n        /// <summary>\n        /// Char wrapping by preferred line width (PreferredLineWidth)\n        /// </summary>\n        CharWrapPreferredWidth,\n\n        /// <summary>\n        /// Custom wrap (by event WordWrapNeeded)\n        /// </summary>\n        Custom\n    }\n\n    public class PrintDialogSettings\n    {\n        public PrintDialogSettings()\n        {\n            ShowPrintPreviewDialog = true;\n            Title = \"\";\n            Footer = \"\";\n            Header = \"\";\n        }\n\n        public bool ShowPageSetupDialog { get; set; }\n        public bool ShowPrintDialog { get; set; }\n        public bool ShowPrintPreviewDialog { get; set; }\n\n        /// <summary>\n        /// Title of page. If you want to print Title on the page, insert code &amp;w in Footer or Header.\n        /// </summary>\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Footer of page.\n        /// Here you can use special codes: &amp;w (Window title), &amp;D, &amp;d (Date), &amp;t(), &amp;4 (Time), &amp;p (Current page number), &amp;P (Total number of pages),  &amp;&amp; (A single ampersand), &amp;b (Right justify text, Center text. If &amp;b occurs once, then anything after the &amp;b is right justified. If &amp;b occurs twice, then anything between the two &amp;b is centered, and anything after the second &amp;b is right justified).\n        /// More detailed see <see cref=\"http://msdn.microsoft.com/en-us/library/aa969429(v=vs.85).aspx\">here</see>\n        /// </summary>\n        public string Footer { get; set; }\n\n        /// <summary>\n        /// Header of page\n        /// Here you can use special codes: &amp;w (Window title), &amp;D, &amp;d (Date), &amp;t(), &amp;4 (Time), &amp;p (Current page number), &amp;P (Total number of pages),  &amp;&amp; (A single ampersand), &amp;b (Right justify text, Center text. If &amp;b occurs once, then anything after the &amp;b is right justified. If &amp;b occurs twice, then anything between the two &amp;b is centered, and anything after the second &amp;b is right justified).\n        /// More detailed see <see cref=\"http://msdn.microsoft.com/en-us/library/aa969429(v=vs.85).aspx\">here</see>\n        /// </summary>\n        public string Header { get; set; }\n\n        /// <summary>\n        /// Prints line numbers\n        /// </summary>\n        public bool IncludeLineNumbers { get; set; }\n    }\n\n    public class AutoIndentEventArgs : EventArgs\n    {\n        public AutoIndentEventArgs(int iLine, string lineText, string prevLineText, int tabLength,\n            int currentIndentation)\n        {\n            this.iLine = iLine;\n            LineText = lineText;\n            PrevLineText = prevLineText;\n            TabLength = tabLength;\n            AbsoluteIndentation = currentIndentation;\n        }\n\n        public int iLine { get; internal set; }\n        public int TabLength { get; internal set; }\n        public string LineText { get; internal set; }\n        public string PrevLineText { get; internal set; }\n\n        /// <summary>\n        /// Additional spaces count for this line, relative to previous line\n        /// </summary>\n        public int Shift { get; set; }\n\n        /// <summary>\n        /// Additional spaces count for next line, relative to previous line\n        /// </summary>\n        public int ShiftNextLines { get; set; }\n\n        /// <summary>\n        /// Absolute indentation of current line. You can change this property if you want to set absolute indentation.\n        /// </summary>\n        public int AbsoluteIndentation { get; set; }\n    }\n\n    /// <summary>\n    /// Type of highlighting\n    /// </summary>\n    public enum HighlightingRangeType\n    {\n        /// <summary>\n        /// Highlight only changed range of text. Highest performance.\n        /// </summary>\n        ChangedRange,\n\n        /// <summary>\n        /// Highlight visible range of text. Middle performance.\n        /// </summary>\n        VisibleRange,\n\n        /// <summary>\n        /// Highlight all (visible and invisible) text. Lowest performance.\n        /// </summary>\n        AllTextRange\n    }\n\n    /// <summary>\n    /// Strategy of search of end of folding block\n    /// </summary>\n    public enum FindEndOfFoldingBlockStrategy\n    {\n        Strategy1,\n        Strategy2\n    }\n\n    /// <summary>\n    /// Strategy of search of brackets to highlighting\n    /// </summary>\n    public enum BracketsHighlightStrategy\n    {\n        Strategy1,\n        Strategy2\n    }\n\n    /// <summary>\n    /// ToolTipNeeded event args\n    /// </summary>\n    public class ToolTipNeededEventArgs : EventArgs\n    {\n        public ToolTipNeededEventArgs(Place place, string hoveredWord)\n        {\n            HoveredWord = hoveredWord;\n            Place = place;\n        }\n\n        public Place Place { get; private set; }\n        public string HoveredWord { get; private set; }\n        public string ToolTipTitle { get; set; }\n        public string ToolTipText { get; set; }\n        public ToolTipIcon ToolTipIcon { get; set; }\n    }\n\n    /// <summary>\n    /// HintClick event args\n    /// </summary>\n    public class HintClickEventArgs : EventArgs\n    {\n        public HintClickEventArgs(Hint hint)\n        {\n            Hint = hint;\n        }\n\n        public Hint Hint { get; private set; }\n    }\n\n    /// <summary>\n    /// CustomAction event args\n    /// </summary>\n    public class CustomActionEventArgs : EventArgs\n    {\n        public FCTBAction Action { get; private set; }\n\n        public CustomActionEventArgs(FCTBAction action)\n        {\n            Action = action;\n        }\n    }\n\n    public enum TextAreaBorderType\n    {\n        None,\n        Single,\n        Shadow\n    }\n\n    [Flags]\n    public enum ScrollDirection : ushort\n    {\n        None = 0,\n        Left = 1,\n        Right = 2,\n        Up = 4,\n        Down = 8\n    }\n\n    [Serializable]\n    public class ServiceColors\n    {\n        public Color CollapseMarkerForeColor { get; set; }\n        public Color CollapseMarkerBackColor { get; set; }\n        public Color CollapseMarkerBorderColor { get; set; }\n        public Color ExpandMarkerForeColor { get; set; }\n        public Color ExpandMarkerBackColor { get; set; }\n        public Color ExpandMarkerBorderColor { get; set; }\n\n        public ServiceColors()\n        {\n            CollapseMarkerForeColor = Color.Silver;\n            CollapseMarkerBackColor = Color.White;\n            CollapseMarkerBorderColor = Color.Silver;\n            ExpandMarkerForeColor = Color.Red;\n            ExpandMarkerBackColor = Color.White;\n            ExpandMarkerBorderColor = Color.Silver;\n        }\n    }\n\n#if Styles32\n    /// <summary>\n    /// Style index mask (32 styles)\n    /// </summary>\n    [Flags]\n    public enum StyleIndex : uint\n    {\n        None = 0,\n        Style0 = 0x1,\n        Style1 = 0x2,\n        Style2 = 0x4,\n        Style3 = 0x8,\n        Style4 = 0x10,\n        Style5 = 0x20,\n        Style6 = 0x40,\n        Style7 = 0x80,\n        Style8 = 0x100,\n        Style9 = 0x200,\n        Style10 = 0x400,\n        Style11 = 0x800,\n        Style12 = 0x1000,\n        Style13 = 0x2000,\n        Style14 = 0x4000,\n        Style15 = 0x8000,\n\n        Style16 = 0x10000,\n        Style17 = 0x20000,\n        Style18 = 0x40000,\n        Style19 = 0x80000,\n        Style20 = 0x100000,\n        Style21 = 0x200000,\n        Style22 = 0x400000,\n        Style23 = 0x800000,\n        Style24 = 0x1000000,\n        Style25 = 0x2000000,\n        Style26 = 0x4000000,\n        Style27 = 0x8000000,\n        Style28 = 0x10000000,\n        Style29 = 0x20000000,\n        Style30 = 0x40000000,\n        Style31 = 0x80000000,\n\n        All = 0xffffffff\n    }\n#else\n    /// <summary>\n    /// Style index mask (16 styles)\n    /// </summary>\n    [Flags]\n    public enum StyleIndex : ushort\n    {\n        None = 0,\n        Style0 = 0x1,\n        Style1 = 0x2,\n        Style2 = 0x4,\n        Style3 = 0x8,\n        Style4 = 0x10,\n        Style5 = 0x20,\n        Style6 = 0x40,\n        Style7 = 0x80,\n        Style8 = 0x100,\n        Style9 = 0x200,\n        Style10 = 0x400,\n        Style11 = 0x800,\n        Style12 = 0x1000,\n        Style13 = 0x2000,\n        Style14 = 0x4000,\n        Style15 = 0x8000,\n        All = 0xffff\n    }\n#endif\n}"
  },
  {
    "path": "FastColoredTextBox/FastColoredTextBox.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProductVersion>9.0.21022</ProductVersion>\n    <SchemaVersion>2.0</SchemaVersion>\n    <ProjectGuid>{6DD14A85-CCFC-4774-BD26-0F5772512319}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>FastColoredTextBoxNS</RootNamespace>\n    <AssemblyName>FastColoredTextBox</AssemblyName>\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <TargetFrameworkProfile />\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>..\\bin\\Win32\\Debug\\</OutputPath>\n    <DefineConstants>TRACE;DEBUG</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <DocumentationFile>\n    </DocumentationFile>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>..\\bin\\Win32\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup>\n    <SignAssembly>true</SignAssembly>\n  </PropertyGroup>\n  <PropertyGroup>\n    <AssemblyOriginatorKeyFile>FCTB_key.snk</AssemblyOriginatorKeyFile>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\n    <DebugSymbols>true</DebugSymbols>\n    <OutputPath>..\\bin\\x64\\Debug\\</OutputPath>\n    <DefineConstants>TRACE;DEBUG</DefineConstants>\n    <DebugType>full</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <LangVersion>7.3</LangVersion>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\n    <OutputPath>..\\bin\\x64\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <Optimize>true</Optimize>\n    <DebugType>pdbonly</DebugType>\n    <PlatformTarget>x64</PlatformTarget>\n    <LangVersion>7.3</LangVersion>\n    <ErrorReport>prompt</ErrorReport>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <Prefer32Bit>false</Prefer32Bit>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Design\" />\n    <Reference Include=\"System.Drawing\" />\n    <Reference Include=\"System.Windows.Forms\" />\n    <Reference Include=\"System.Xml\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"AutocompleteItem.cs\" />\n    <Compile Include=\"AutocompleteMenu.cs\">\n      <SubType>UserControl</SubType>\n    </Compile>\n    <Compile Include=\"Bookmarks.cs\" />\n    <Compile Include=\"Char.cs\" />\n    <Compile Include=\"DocumentMap.cs\">\n      <SubType>Component</SubType>\n    </Compile>\n    <Compile Include=\"EncodingDetector.cs\" />\n    <Compile Include=\"ExportToHTML.cs\" />\n    <Compile Include=\"ExportToRTF.cs\" />\n    <Compile Include=\"GoToForm.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"GoToForm.Designer.cs\">\n      <DependentUpon>GoToForm.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"Hints.cs\" />\n    <Compile Include=\"HotkeysEditorForm.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"HotkeysEditorForm.Designer.cs\">\n      <DependentUpon>HotkeysEditorForm.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"LinesAccessor.cs\" />\n    <Compile Include=\"MacrosManager.cs\" />\n    <Compile Include=\"NativeMethods.cs\" />\n    <Compile Include=\"PlatformType.cs\" />\n    <Compile Include=\"Hotkeys.cs\" />\n    <Compile Include=\"Ruler.cs\">\n      <SubType>UserControl</SubType>\n    </Compile>\n    <Compile Include=\"Ruler.Designer.cs\">\n      <DependentUpon>Ruler.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"SyntaxDescriptor.cs\" />\n    <Compile Include=\"SyntaxHighlighter.cs\" />\n    <Compile Include=\"ReplaceForm.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"ReplaceForm.Designer.cs\">\n      <DependentUpon>ReplaceForm.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"FastColoredTextBox.cs\">\n      <SubType>UserControl</SubType>\n    </Compile>\n    <Compile Include=\"CommandManager.cs\" />\n    <Compile Include=\"Commands.cs\" />\n    <Compile Include=\"FindForm.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"FindForm.Designer.cs\">\n      <DependentUpon>FindForm.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"LimitedStack.cs\" />\n    <Compile Include=\"Line.cs\" />\n    <Compile Include=\"Place.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"Range.cs\" />\n    <Compile Include=\"Style.cs\" />\n    <Compile Include=\"TextSource.cs\" />\n    <Compile Include=\"TypeDescriptor.cs\" />\n    <Compile Include=\"FileTextSource.cs\" />\n    <Compile Include=\"UnfocusablePanel.cs\">\n      <SubType>UserControl</SubType>\n    </Compile>\n    <Compile Include=\"VisualMarker.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <EmbeddedResource Include=\"FastColoredTextBox.resx\">\n      <DependentUpon>FastColoredTextBox.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"FindForm.resx\">\n      <DependentUpon>FindForm.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"GoToForm.resx\">\n      <DependentUpon>GoToForm.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"HotkeysEditorForm.resx\">\n      <DependentUpon>HotkeysEditorForm.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"ReplaceForm.resx\">\n      <DependentUpon>ReplaceForm.cs</DependentUpon>\n      <SubType>Designer</SubType>\n    </EmbeddedResource>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"FCTB_key.snk\" />\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "FastColoredTextBox/FastColoredTextBox.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "FastColoredTextBox/FastColoredTextBox.xml",
    "content": "<?xml version=\"1.0\"?>\n<doc>\n    <assembly>\n        <name>FastColoredTextBox</name>\n    </assembly>\n    <members>\n        <member name=\"T:FastColoredTextBoxNS.AutocompleteItem\">\n            <summary>\n            Item of autocomplete menu\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.AutocompleteItem.GetTextForReplace\">\n            <summary>\n            Returns text for inserting into Textbox\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.AutocompleteItem.Compare(System.String)\">\n            <summary>\n            Compares fragment text with this item\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.AutocompleteItem.ToString\">\n            <summary>\n            Returns text for display into popup menu\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.AutocompleteItem.OnSelected(FastColoredTextBoxNS.AutocompleteMenu,FastColoredTextBoxNS.SelectedEventArgs)\">\n            <summary>\n            This method is called after item inserted into text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteItem.ToolTipTitle\">\n            <summary>\n            Title for tooltip.\n            </summary>\n            <remarks>Return null for disable tooltip for this item</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteItem.ToolTipText\">\n            <summary>\n            Tooltip text.\n            </summary>\n            <remarks>For display tooltip text, ToolTipTitle must be not null</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteItem.MenuText\">\n            <summary>\n            Menu text. This text is displayed in the drop-down menu.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteItem.ForeColor\">\n            <summary>\n            Fore color of text of item\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteItem.BackColor\">\n            <summary>\n            Back color of item\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.CompareResult.Hidden\">\n            <summary>\n            Item do not appears\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.CompareResult.Visible\">\n            <summary>\n            Item appears\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.CompareResult.VisibleAndSelected\">\n            <summary>\n            Item appears and will selected\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.SnippetAutocompleteItem\">\n            <summary>\n            Autocomplete item for code snippets\n            </summary>\n            <remarks>Snippet can contain special char ^ for caret position.</remarks>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SnippetAutocompleteItem.Compare(System.String)\">\n            <summary>\n            Compares fragment text with this item\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.MethodAutocompleteItem\">\n            <summary>\n            This autocomplete item appears after dot\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.SuggestItem\">\n            <summary>\n            This Item does not check correspondence to current text fragment.\n            SuggestItem is intended for dynamic menus.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.AutocompleteMenu\">\n            <summary>\n            Popup menu for autocomplete\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.SearchPattern\">\n            <summary>\n            Regex pattern for serach fragment around caret\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.MinFragmentLength\">\n            <summary>\n            Minimum fragment length for popup\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.AutocompleteMenu.Selecting\">\n            <summary>\n            User selects item\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.AutocompleteMenu.Selected\">\n            <summary>\n            It fires after item inserting\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.AutocompleteMenu.Opening\">\n            <summary>\n            Occurs when popup menu is opening\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.AllowTabKey\">\n            <summary>\n            Allow TAB for select menu item\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.AppearInterval\">\n            <summary>\n            Interval of menu appear (ms)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.SelectedColor\">\n            <summary>\n            Back color of selected item\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.HoveredColor\">\n            <summary>\n            Border color of hovered item\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.AutocompleteMenu.Show(System.Boolean)\">\n            <summary>\n            Shows popup menu immediately\n            </summary>\n            <param name=\"forced\">If True - MinFragmentLength will be ignored</param>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.MinimumSize\">\n            <summary>\n            Minimal size of menu\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.ImageList\">\n            <summary>\n            Image list of menu\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.ToolTipDuration\">\n            <summary>\n            Tooltip duration (ms)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutocompleteMenu.ToolTip\">\n            <summary>\n            Tooltip\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.BaseBookmarks\">\n            <summary>\n            Base class for bookmark collection\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Bookmarks\">\n            <summary>\n            Collection of bookmarks\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Bookmarks.Remove(System.Int32)\">\n            <summary>\n            Removes bookmark by line index\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Bookmarks.GetBookmark(System.Int32)\">\n            <summary>\n            Returns Bookmark by index.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Bookmark\">\n            <summary>\n            Bookmark of FastColoredTextbox\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Bookmark.Name\">\n            <summary>\n            Name of bookmark\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Bookmark.LineIndex\">\n            <summary>\n            Line index\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Bookmark.Color\">\n            <summary>\n            Color of bookmark sign\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Bookmark.DoVisible\">\n            <summary>\n            Scroll textbox to the bookmark\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Char\">\n            <summary>\n            Char and style\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.Char.c\">\n            <summary>\n            Unicode character\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.Char.style\">\n            <summary>\n            Style bit mask\n            </summary>\n            <remarks>Bit 1 in position n means that this char will rendering by FastColoredTextBox.Styles[n]</remarks>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.DocumentMap\">\n            <summary>\n            Shows document map of FCTB\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.DocumentMap.Scale\">\n            <summary>\n            Scale\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.DocumentMap.ScrollbarVisible\">\n            <summary>\n            Scrollbar visibility\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ExportToHTML\">\n            <summary>\n            Exports colored text as HTML\n            </summary>\n            <remarks>At this time only TextStyle renderer is supported. Other styles is not exported.</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToHTML.UseNbsp\">\n            <summary>\n            Use nbsp; instead space\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToHTML.UseForwardNbsp\">\n            <summary>\n            Use nbsp; instead space in beginning of line\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToHTML.UseOriginalFont\">\n            <summary>\n            Use original font\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToHTML.UseStyleTag\">\n            <summary>\n            Use style tag instead style attribute\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToHTML.UseBr\">\n            <summary>\n            Use 'br' tag instead of '\\n'\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToHTML.IncludeLineNumbers\">\n            <summary>\n            Includes line numbers\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ExportToRTF\">\n            <summary>\n            Exports colored text as RTF\n            </summary>\n            <remarks>At this time only TextStyle renderer is supported. Other styles is not exported.</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToRTF.IncludeLineNumbers\">\n            <summary>\n            Includes line numbers\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.ExportToRTF.UseOriginalFont\">\n            <summary>\n            Use original font\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.GoToForm.components\">\n            <summary>\n            Required designer variable.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.GoToForm.Dispose(System.Boolean)\">\n            <summary>\n            Clean up any resources being used.\n            </summary>\n            <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.GoToForm.InitializeComponent\">\n            <summary>\n            Required method for Designer support - do not modify\n            the contents of this method with the code editor.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Hints\">\n            <summary>\n            Collection of Hints.\n            This is temporary buffer for currently displayed hints.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hints.Clear\">\n            <summary>\n            Clears all displayed hints\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hints.Add(FastColoredTextBoxNS.Hint)\">\n            <summary>\n            Add and shows the hint\n            </summary>\n            <param name=\"hint\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hints.Contains(FastColoredTextBoxNS.Hint)\">\n            <summary>\n            Is collection contains the hint?\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hints.Count\">\n            <summary>\n            Count of hints\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Hint\">\n            <summary>\n            Hint of FastColoredTextbox\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Text\">\n            <summary>\n            Text of simple hint\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Range\">\n            <summary>\n            Linked range\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.BackColor\">\n            <summary>\n            Backcolor\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.BackColor2\">\n            <summary>\n            Second backcolor\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.BorderColor\">\n            <summary>\n            Border color\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.ForeColor\">\n            <summary>\n            Fore color\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.TextAlignment\">\n            <summary>\n            Text alignment\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Font\">\n            <summary>\n            Font\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.Hint.Click\">\n            <summary>\n            Occurs when user click on simple hint\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.InnerControl\">\n            <summary>\n            Inner control\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Dock\">\n            <summary>\n            Docking (allows None and Fill only)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Width\">\n            <summary>\n            Width of hint (if Dock is None)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Height\">\n            <summary>\n            Height of hint\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.HostPanel\">\n            <summary>\n            Host panel\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Tag\">\n            <summary>\n            Tag\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Cursor\">\n            <summary>\n            Cursor\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Hint.Inline\">\n            <summary>\n            Inlining. If True then hint will moves apart text.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hint.DoVisible\">\n            <summary>\n            Scroll textbox to the hint\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hint.#ctor(FastColoredTextBoxNS.Range,System.String,System.Boolean,System.Boolean)\">\n            <summary>\n            Creates Hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"text\">Text for simple hint</param>\n            <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n            <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hint.#ctor(FastColoredTextBoxNS.Range,System.String)\">\n            <summary>\n            Creates Hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"text\">Text for simple hint</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hint.#ctor(FastColoredTextBoxNS.Range,System.Windows.Forms.Control,System.Boolean,System.Boolean)\">\n            <summary>\n            Creates Hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"innerControl\">Inner control</param>\n            <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n            <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Hint.#ctor(FastColoredTextBoxNS.Range,System.Windows.Forms.Control)\">\n            <summary>\n            Creates Hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"innerControl\">Inner control</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.HotkeysEditorForm.GetHotkeys\">\n            <summary>\n            Returns edited hotkey map\n            </summary>\n            <returns></returns>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.HotkeysEditorForm.components\">\n            <summary>\n            Required designer variable.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.HotkeysEditorForm.Dispose(System.Boolean)\">\n            <summary>\n            Clean up any resources being used.\n            </summary>\n            <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.HotkeysEditorForm.InitializeComponent\">\n            <summary>\n            Required method for Designer support - do not modify\n            the contents of this method with the code editor.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.MacrosManager\">\n            <summary>\n            This class records, stores and executes the macros.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.MacrosManager.AllowMacroRecordingByUser\">\n            <summary>\n            Allows to user to record macros\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.MacrosManager.IsRecording\">\n            <summary>\n            Returns current recording state. Set to True/False to start/stop recording programmatically.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.MacrosManager.UnderlayingControl\">\n            <summary>\n            FCTB\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.MacrosManager.ExecuteMacros\">\n            <summary>\n            Executes recorded macro\n            </summary>\n            <returns></returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.MacrosManager.AddCharToMacros(System.Char,System.Windows.Forms.Keys)\">\n            <summary>\n            Adds the char to current macro\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.MacrosManager.AddKeyToMacros(System.Windows.Forms.Keys)\">\n            <summary>\n            Adds keyboard key to current macro\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.MacrosManager.ClearMacros\">\n            <summary>\n            Clears last recorded macro\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.MacrosManager.MacroIsEmpty\">\n            <summary>\n            Returns True if last macro is empty\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.MacrosManager.Macros\">\n            <summary>\n            Macros as string.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.HotkeysMapping\">\n            <summary>\n            Dictionary of shortcuts for FCTB\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.FCTBAction\">\n            <summary>\n            Actions for shortcuts\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.Ruler.components\">\n            <summary> \n            Required designer variable.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Ruler.Dispose(System.Boolean)\">\n            <summary> \n            Clean up any resources being used.\n            </summary>\n            <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Ruler.InitializeComponent\">\n            <summary> \n            Required method for Designer support - do not modify \n            the contents of this method with the code editor.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.HighlightSyntax(FastColoredTextBoxNS.Language,FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights syntax for given language\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.HighlightSyntax(System.String,FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights syntax for given XML description file\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.CSharpSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights C# code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.VBSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights VB code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.HTMLSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights HTML code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.XMLSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights XML code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.SQLSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights SQL code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.PHPSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights PHP code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.JScriptSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights JavaScript code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.SyntaxHighlighter.LuaSyntaxHighlight(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Highlights Lua code\n            </summary>\n            <param name=\"range\"></param>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.StringStyle\">\n            <summary>\n            String style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.CommentStyle\">\n            <summary>\n            Comment style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.NumberStyle\">\n            <summary>\n            Number style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.AttributeStyle\">\n            <summary>\n            C# attribute style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.ClassNameStyle\">\n            <summary>\n            Class name style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.KeywordStyle\">\n            <summary>\n            Keyword style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.CommentTagStyle\">\n            <summary>\n            Style of tags in comments of C#\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.AttributeValueStyle\">\n            <summary>\n            HTML attribute value style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.TagBracketStyle\">\n            <summary>\n            HTML tag brackets style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.TagNameStyle\">\n            <summary>\n            HTML tag name style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.HtmlEntityStyle\">\n            <summary>\n            HTML Entity style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.XmlAttributeStyle\">\n            <summary>\n            XML attribute style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.XmlAttributeValueStyle\">\n            <summary>\n            XML attribute value style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.XmlTagBracketStyle\">\n            <summary>\n            XML tag brackets style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.XmlTagNameStyle\">\n            <summary>\n            XML tag name style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.XmlEntityStyle\">\n            <summary>\n            XML Entity style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.XmlCDataStyle\">\n            <summary>\n            XML CData style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.VariableStyle\">\n            <summary>\n            Variable style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.KeywordStyle2\">\n            <summary>\n            Specific PHP keyword style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.KeywordStyle3\">\n            <summary>\n            Specific PHP keyword style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.StatementsStyle\">\n            <summary>\n            SQL Statements style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.FunctionsStyle\">\n            <summary>\n            SQL Functions style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.SyntaxHighlighter.TypesStyle\">\n            <summary>\n            SQL Types style\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Language\">\n            <summary>\n            Language\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.ReplaceForm.components\">\n            <summary>\n            Required designer variable.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceForm.Dispose(System.Boolean)\">\n            <summary>\n            Clean up any resources being used.\n            </summary>\n            <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceForm.InitializeComponent\">\n            <summary>\n            Required method for Designer support - do not modify\n            the contents of this method with the code editor.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.FastColoredTextBox\">\n            <summary>\n            Fast colored textbox\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.#ctor\">\n            <summary>\n            Constructor\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AutoCompleteBrackets\">\n            <summary>\n            AutoComplete brackets\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ServiceColors\">\n            <summary>\n            Colors of some service visual markers\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.FoldedBlocks\">\n            <summary>\n            Contains UniqueId of start lines of folded blocks\n            </summary>\n            <remarks>This dictionary remembers folding state of blocks.\n            It is needed to restore child folding after user collapsed/expanded top-level folding block.</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.BracketsHighlightStrategy\">\n            <summary>\n            Strategy of search of brackets to highlighting\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.WordWrapAutoIndent\">\n            <summary>\n            Automatically shifts secondary wordwrap lines on the shift amount of the first line\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.WordWrapIndent\">\n            <summary>\n            Indent of secondary wordwrap lines (in chars)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.MacrosManager\">\n            <summary>\n            MacrosManager records, stores and executes the macroses\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AllowDrop\">\n            <summary>\n            Allows drag and drop\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Hints\">\n            <summary>\n            Collection of Hints.\n            This is temporary buffer for currently displayed hints.\n            </summary>\n            <remarks>You can asynchronously add, remove and clear hints. Appropriate hints will be shown or hidden from the screen.</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ToolTipDelay\">\n            <summary>\n            Delay (ms) of ToolTip\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ToolTip\">\n            <summary>\n            ToolTip component\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.BookmarkColor\">\n            <summary>\n            Color of bookmarks\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Bookmarks\">\n            <summary>\n            Bookmarks\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.VirtualSpace\">\n            <summary>\n            Enables virtual spaces\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.FindEndOfFoldingBlockStrategy\">\n            <summary>\n            Strategy of search of end of folding block\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AcceptsTab\">\n            <summary>\n            Indicates if tab characters are accepted as input\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AcceptsReturn\">\n            <summary>\n            Indicates if return characters are accepted as input\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.CaretVisible\">\n            <summary>\n            Shows or hides the caret\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.CaretBlinking\">\n            <summary>\n            Enables caret blinking\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.TextAreaBorderColor\">\n            <summary>\n            Color of border of text area\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.TextAreaBorder\">\n            <summary>\n            Type of border of text area\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.CurrentLineColor\">\n            <summary>\n            Background color for current line\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ChangedLineColor\">\n            <summary>\n            Background color for highlighting of changed lines\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ForeColor\">\n            <summary>\n            Fore color (default style color)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.CharHeight\">\n            <summary>\n            Height of char in pixels (includes LineInterval)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LineInterval\">\n            <summary>\n            Interval between lines (in pixels)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.CharWidth\">\n            <summary>\n            Width of char in pixels\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.TabLength\">\n            <summary>\n            Spaces count for tab\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.IsChanged\">\n            <summary>\n            Text was changed\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.TextVersion\">\n            <summary>\n            Text version\n            </summary>\n            <remarks>This counter is incremented each time changes the text</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ReadOnly\">\n            <summary>\n            Read only\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ShowLineNumbers\">\n            <summary>\n            Shows line numbers.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ShowFoldingLines\">\n            <summary>\n            Shows vertical lines between folding start line and folding end line.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.TextAreaRect\">\n            <summary>\n            Rectangle where located text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LineNumberColor\">\n            <summary>\n            Color of line numbers.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LineNumberStartValue\">\n            <summary>\n            Start value of first line number.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.IndentBackColor\">\n            <summary>\n            Background color of indent area\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.PaddingBackColor\">\n            <summary>\n            Background color of padding area\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.DisabledColor\">\n            <summary>\n            Color of disabled component\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.CaretColor\">\n            <summary>\n            Color of caret\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.WideCaret\">\n            <summary>\n            Wide caret\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ServiceLinesColor\">\n            <summary>\n            Color of service lines (folding lines, borders of blocks etc.)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Paddings\">\n            <summary>\n            Padings of text area\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Padding\">\n            <summary>\n            --Do not use this property--\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.FoldingIndicatorColor\">\n            <summary>\n            Color of folding area indicator\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.HighlightFoldingIndicator\">\n            <summary>\n            Enables folding indicator (left vertical line between folding bounds)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LeftIndent\">\n            <summary>\n            Left distance to text beginning\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LeftPadding\">\n            <summary>\n            Left padding in pixels\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.PreferredLineWidth\">\n            <summary>\n            This property draws vertical line after defined char position.\n            Set to 0 for disable drawing of vertical line.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Styles\">\n            <summary>\n            Styles\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Hotkeys\">\n            <summary>\n            Hotkeys. Do not use this property in your code, use HotkeysMapping property.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.HotkeysMapping\">\n            <summary>\n            Hotkeys mapping\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.DefaultStyle\">\n            <summary>\n            Default text style\n            This style is using when no one other TextStyle is not defined in Char.style\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SelectionStyle\">\n            <summary>\n            Style for rendering Selection area\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.FoldedBlockStyle\">\n            <summary>\n            Style for folded block rendering\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.BracketsStyle\">\n            <summary>\n            Style for brackets highlighting\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.BracketsStyle2\">\n            <summary>\n            Style for alternative brackets highlighting\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LeftBracket\">\n            <summary>\n            Opening bracket for brackets highlighting.\n            Set to '\\x0' for disable brackets highlighting.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.RightBracket\">\n            <summary>\n            Closing bracket for brackets highlighting.\n            Set to '\\x0' for disable brackets highlighting.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LeftBracket2\">\n            <summary>\n            Alternative opening bracket for brackets highlighting.\n            Set to '\\x0' for disable brackets highlighting.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.RightBracket2\">\n            <summary>\n            Alternative closing bracket for brackets highlighting.\n            Set to '\\x0' for disable brackets highlighting.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.CommentPrefix\">\n            <summary>\n            Comment line prefix.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.HighlightingRangeType\">\n            <summary>\n            This property specifies which part of the text will be highlighted as you type (by built-in highlighter).\n            </summary>\n            <remarks>When a user enters text, a component refreshes highlighting (because the text was changed).\n            This property specifies exactly which section of the text will be re-highlighted.\n            This can be useful to highlight multi-line comments, for example.</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.IsReplaceMode\">\n            <summary>\n            Is keyboard in replace mode (wide caret) ?\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AllowSeveralTextStyleDrawing\">\n            <summary>\n            Allows text rendering several styles same time.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AllowMacroRecording\">\n            <summary>\n            Allows to record macros.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AutoIndent\">\n            <summary>\n            Allows AutoIndent. Inserts spaces before new line.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AutoIndentExistingLines\">\n            <summary>\n            Does autoindenting in existing lines. It works only if AutoIndent is True.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.DelayedEventsInterval\">\n            <summary>\n            Minimal delay(ms) for delayed events (except TextChangedDelayed).\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.DelayedTextChangedInterval\">\n            <summary>\n            Minimal delay(ms) for TextChangedDelayed event.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Language\">\n            <summary>\n            Language for highlighting by built-in highlighter.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SyntaxHighlighter\">\n            <summary>\n            Syntax Highlighter\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.DescriptionFile\">\n            <summary>\n            XML file with description of syntax highlighting.\n            This property works only with Language == Language.Custom.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LeftBracketPosition\">\n            <summary>\n            Position of left highlighted bracket.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.RightBracketPosition\">\n            <summary>\n            Position of right highlighted bracket.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LeftBracketPosition2\">\n            <summary>\n            Position of left highlighted alternative bracket.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.RightBracketPosition2\">\n            <summary>\n            Position of right highlighted alternative bracket.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.StartFoldingLine\">\n            <summary>\n            Start line index of current highlighted folding area. Return -1 if start of area is not found.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.EndFoldingLine\">\n            <summary>\n            End line index of current highlighted folding area. Return -1 if end of area is not found.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.TextSource\">\n            <summary>\n            TextSource\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SourceTextBox\">\n            <summary>\n            The source of the text.\n            Allows to get text from other FastColoredTextBox.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.VisibleRange\">\n            <summary>\n            Returns current visible range of text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Selection\">\n            <summary>\n            Current selection range\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.BackColor\">\n            <summary>\n            Background color.\n            It is used if BackBrush is null.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.BackBrush\">\n            <summary>\n            Background brush.\n            If Null then BackColor is used.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Multiline\">\n            <summary>\n            Multiline\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.WordWrap\">\n            <summary>\n            WordWrap.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.WordWrapMode\">\n            <summary>\n            WordWrap mode.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SelectionHighlightingForLineBreaksEnabled\">\n            <summary>\n            If <c>true</c> then line breaks included into the selection will be selected too.\n            Then line breaks will be shown as selected blank character.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AutoScroll\">\n            <summary>\n            Do not change this property\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.LinesCount\">\n            <summary>\n            Count of lines\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Item(FastColoredTextBoxNS.Place)\">\n            <summary>\n            Gets or sets char and styleId for given place\n            This property does not fire OnTextChanged event\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Item(System.Int32)\">\n            <summary>\n            Gets Line\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Text\">\n            <summary>\n            Text of control\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Lines\">\n            <summary>\n            Text lines\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Html\">\n            <summary>\n            Gets colored text as HTML\n            </summary>\n            <remarks>For more flexibility you can use ExportToHTML class also</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Rtf\">\n            <summary>\n            Gets colored text as RTF\n            </summary>\n            <remarks>For more flexibility you can use ExportToRTF class also</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SelectedText\">\n            <summary>\n            Text of current selection\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SelectionStart\">\n            <summary>\n            Start position of selection\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SelectionLength\">\n            <summary>\n            Length of selected text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Font\">\n            <summary>\n            Font\n            </summary>\n            <remarks>Use only monospaced font</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.BaseFont\">\n            <summary>\n            Font\n            </summary>\n            <remarks>Use only monospaced font</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ImeAllowed\">\n            <summary>\n            Indicates that IME is allowed (for CJK language entering)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.UndoEnabled\">\n            <summary>\n            Is undo enabled?\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.RedoEnabled\">\n            <summary>\n            Is redo enabled?\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Range\">\n            <summary>\n            Range of all text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.SelectionColor\">\n            <summary>\n            Color of selected area\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.ReservedCountOfLineNumberChars\">\n            <summary>\n            Reserved space for line number characters.\n            If smaller than needed (e. g. line count >= 10 and this value set to 1) this value will have no impact.\n            If you want to reserve space, e. g. for line numbers >= 10 or >= 100 than you can set this value to 2 or 3 or higher.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.ToolTipNeeded\">\n            <summary>\n            Occurs when mouse is moving over text and tooltip is needed\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ClearHints\">\n            <summary>\n            Removes all hints\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AddHint(FastColoredTextBoxNS.Range,System.Windows.Forms.Control,System.Boolean,System.Boolean,System.Boolean)\">\n            <summary>\n            Add and shows the hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"innerControl\">Inner control</param>\n            <param name=\"scrollToHint\">Scrolls textbox to the hint</param>\n            <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n            <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AddHint(FastColoredTextBoxNS.Range,System.Windows.Forms.Control)\">\n            <summary>\n            Add and shows the hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"innerControl\">Inner control</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AddHint(FastColoredTextBoxNS.Range,System.String,System.Boolean,System.Boolean,System.Boolean)\">\n            <summary>\n            Add and shows simple text hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"text\">Text of simple hint</param>\n            <param name=\"scrollToHint\">Scrolls textbox to the hint</param>\n            <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n            <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AddHint(FastColoredTextBoxNS.Range,System.String)\">\n            <summary>\n            Add and shows simple text hint\n            </summary>\n            <param name=\"range\">Linked range</param>\n            <param name=\"text\">Text of simple hint</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnHintClick(FastColoredTextBoxNS.Hint)\">\n            <summary>\n            Occurs when user click on the hint\n            </summary>\n            <param name=\"hint\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnVisibleRangeChanged\">\n            <summary>\n            Occurs when VisibleRange is changed\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Invalidate\">\n            <summary>\n            Invalidates the entire surface of the control and causes the control to be redrawn.\n            This method is thread safe and does not require Invoke.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.HintClick\">\n            <summary>\n            HintClick event.\n            It occurs if user click on the hint.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.TextChanged\">\n            <summary>\n            TextChanged event.\n            It occurs after insert, delete, clear, undo and redo operations.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.BindingTextChanged\">\n            <summary>\n            Fake event for correct data binding\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.Pasting\">\n            <summary>\n            Occurs when user paste text from clipboard\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.TextChanging\">\n            <summary>\n            TextChanging event.\n            It occurs before insert, delete, clear, undo and redo operations.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.SelectionChanged\">\n            <summary>\n            SelectionChanged event.\n            It occurs after changing of selection.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.VisibleRangeChanged\">\n            <summary>\n            VisibleRangeChanged event.\n            It occurs after changing of visible range.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.TextChangedDelayed\">\n            <summary>\n            TextChangedDelayed event. \n            It occurs after insert, delete, clear, undo and redo operations. \n            This event occurs with a delay relative to TextChanged, and fires only once.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.SelectionChangedDelayed\">\n            <summary>\n            SelectionChangedDelayed event.\n            It occurs after changing of selection.\n            This event occurs with a delay relative to SelectionChanged, and fires only once.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.VisibleRangeChangedDelayed\">\n            <summary>\n            VisibleRangeChangedDelayed event.\n            It occurs after changing of visible range.\n            This event occurs with a delay relative to VisibleRangeChanged, and fires only once.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.VisualMarkerClick\">\n            <summary>\n            It occurs when user click on VisualMarker.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.KeyPressing\">\n            <summary>\n            It occurs when visible char is enetering (alphabetic, digit, punctuation, DEL, BACKSPACE)\n            </summary>\n            <remarks>Set Handle to True for cancel key</remarks>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.KeyPressed\">\n            <summary>\n            It occurs when visible char is enetered (alphabetic, digit, punctuation, DEL, BACKSPACE)\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.AutoIndentNeeded\">\n            <summary>\n            It occurs when calculates AutoIndent for new line\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.PaintLine\">\n            <summary>\n            It occurs when line background is painting\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.LineInserted\">\n            <summary>\n            Occurs when line was inserted/added\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.LineRemoved\">\n            <summary>\n            Occurs when line was removed\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.FoldingHighlightChanged\">\n            <summary>\n            Occurs when current highlighted folding area is changed.\n            Current folding area see in StartFoldingLine and EndFoldingLine.\n            </summary>\n            <remarks></remarks>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.UndoRedoStateChanged\">\n            <summary>\n            Occurs when undo/redo stack is changed\n            </summary>\n            <remarks></remarks>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.ZoomChanged\">\n            <summary>\n            Occurs when component was zoomed\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.CustomAction\">\n            <summary>\n            Occurs when user pressed key, that specified as CustomAction\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.ScrollbarsUpdated\">\n            <summary>\n            Occurs when scroolbars are updated\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FastColoredTextBox.WordWrapNeeded\">\n            <summary>\n            Occurs when custom wordwrap is needed\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetStylesOfChar(FastColoredTextBoxNS.Place)\">\n            <summary>\n            Returns list of styles of given place\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.NeedRecalc\">\n            <summary>\n            Call this method if the recalc of the position of lines is needed.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.NeedRecalc(System.Boolean)\">\n            <summary>\n            Call this method if the recalc of the position of lines is needed.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.NeedRecalc(System.Boolean,System.Boolean)\">\n            <summary>\n            Call this method if the recalc of the position of lines is needed.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.NavigateForward\">\n            <summary>\n            Navigates forward (by Line.LastVisit property)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.NavigateBackward\">\n            <summary>\n            Navigates backward (by Line.LastVisit property)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Navigate(System.Int32)\">\n            <summary>\n            Navigates to defined line, without Line.LastVisit reseting\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AddStyle(FastColoredTextBoxNS.Style)\">\n            <summary>\n            Add new style\n            </summary>\n            <returns>Layer index of this style</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ShowFindDialog\">\n            <summary>\n            Shows find dialog\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ShowFindDialog(System.String)\">\n            <summary>\n            Shows find dialog\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ShowReplaceDialog\">\n            <summary>\n            Shows replace dialog\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ShowReplaceDialog(System.String)\">\n            <summary>\n            Shows replace dialog\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetLineLength(System.Int32)\">\n            <summary>\n            Gets length of given line\n            </summary>\n            <param name=\"iLine\">Line index</param>\n            <returns>Length of line</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetLine(System.Int32)\">\n            <summary>\n            Get range of line\n            </summary>\n            <param name=\"iLine\">Line index</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Copy\">\n            <summary>\n            Copy selected text into Clipboard\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Cut\">\n            <summary>\n            Cut selected text into Clipboard\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Paste\">\n            <summary>\n            Paste text from clipboard into selected position\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.SelectAll\">\n            <summary>\n            Select all chars of text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GoEnd\">\n            <summary>\n            Move caret to end of text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GoHome\">\n            <summary>\n            Move caret to first position\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Clear\">\n            <summary>\n            Clear text, styles, history, caches\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ClearStylesBuffer\">\n            <summary>\n            Clear buffer of styles\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ClearStyle(FastColoredTextBoxNS.StyleIndex)\">\n            <summary>\n            Clear style of all text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ClearUndo\">\n            <summary>\n            Clears undo and redo stacks\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.InsertText(System.String)\">\n            <summary>\n            Insert text into current selected position\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.InsertText(System.String,System.Boolean)\">\n            <summary>\n            Insert text into current selected position\n            </summary>\n            <param name=\"text\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.InsertText(System.String,FastColoredTextBoxNS.Style)\">\n            <summary>\n            Insert text into current selection position (with predefined style)\n            </summary>\n            <param name=\"text\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.InsertText(System.String,FastColoredTextBoxNS.Style,System.Boolean)\">\n            <summary>\n            Insert text into current selection position (with predefined style)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AppendText(System.String)\">\n            <summary>\n            Append string to end of the Text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AppendText(System.String,FastColoredTextBoxNS.Style)\">\n            <summary>\n            Append string to end of the Text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetStyleIndex(FastColoredTextBoxNS.Style)\">\n            <summary>\n            Returns index of the style in Styles\n            -1 otherwise\n            </summary>\n            <param name=\"style\"></param>\n            <returns>Index of the style in Styles</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetStyleIndexMask(FastColoredTextBoxNS.Style[])\">\n            <summary>\n            Returns StyleIndex mask of given styles\n            </summary>\n            <param name=\"styles\"></param>\n            <returns>StyleIndex mask of given styles</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ClearSelected\">\n            <summary>\n            Deletes selected chars\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ClearCurrentLine\">\n            <summary>\n            Deletes current line(s)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CalcCutOffs(System.Collections.Generic.List{System.Int32},System.Int32,System.Int32,System.Boolean,System.Boolean,FastColoredTextBoxNS.Line)\">\n            <summary>\n            Calculates wordwrap cutoffs\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoVisibleRectangle(System.Drawing.Rectangle)\">\n            <summary>\n            Scroll control for display defined rectangle\n            </summary>\n            <param name=\"rect\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.UpdateScrollbars\">\n            <summary>\n            Updates scrollbar position after Value changed\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoCaretVisible\">\n            <summary>\n            Scroll control for display caret\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ScrollLeft\">\n            <summary>\n            Scroll control left\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoSelectionVisible\">\n            <summary>\n            Scroll control for display selection area\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoRangeVisible(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Scroll control for display given range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoRangeVisible(FastColoredTextBoxNS.Range,System.Boolean)\">\n            <summary>\n            Scroll control for display given range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ProcessKey(System.Windows.Forms.Keys)\">\n            <summary>\n            Process control keys\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GotoNextBookmark(System.Int32)\">\n            <summary>\n            Scrolls to nearest bookmark or to first bookmark\n            </summary>\n            <param name=\"iLine\">Current bookmark line index</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GotoPrevBookmark(System.Int32)\">\n            <summary>\n            Scrolls to nearest previous bookmark or to last bookmark\n            </summary>\n            <param name=\"iLine\">Current bookmark line index</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.BookmarkLine(System.Int32)\">\n            <summary>\n            Bookmarks line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.UnbookmarkLine(System.Int32)\">\n            <summary>\n            Unbookmarks current line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.MoveSelectedLinesDown\">\n            <summary>\n            Moves selected lines down\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.MoveSelectedLinesUp\">\n            <summary>\n            Moves selected lines up\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.UpperCase\">\n            <summary>\n            Convert selected text to upper case\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.LowerCase\">\n            <summary>\n            Convert selected text to lower case\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.TitleCase\">\n            <summary>\n            Convert selected text to title case\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CommentSelected\">\n            <summary>\n            Insert/remove comment prefix into selected lines\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CommentSelected(System.String)\">\n            <summary>\n            Insert/remove comment prefix into selected lines\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ProcessKey(System.Char,System.Windows.Forms.Keys)\">\n            <summary>\n            Process \"real\" keys (no control)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AutoIndentChars\">\n            <summary>\n            Enables AutoIndentChars mode\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.AutoIndentCharsPatterns\">\n            <summary>\n            Regex patterns for AutoIndentChars (one regex per line)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoAutoIndentChars(System.Int32)\">\n            <summary>\n            Do AutoIndentChars\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.FindChar(System.Char)\">\n            <summary>\n            Finds given char after current caret position, moves the caret to found pos.\n            </summary>\n            <param name=\"c\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoAutoIndent(System.Int32)\">\n            <summary>\n            Inserts autoindent's spaces in the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CalcAutoIndent(System.Int32)\">\n            <summary>\n            Returns needed start space count for the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Undo\">\n            <summary>\n            Undo last operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Redo\">\n            <summary>\n            Redo\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DrawText(System.Drawing.Graphics,FastColoredTextBoxNS.Place,System.Drawing.Size)\">\n            <summary>\n            Draws text to given Graphics\n            </summary>\n            <param name=\"gr\"></param>\n            <param name=\"start\">Start place of drawing text</param>\n            <param name=\"size\">Size of drawing</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnPaint(System.Windows.Forms.PaintEventArgs)\">\n            <summary>\n            Draw control\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetControlPanelWheelScrollLinesValue\">\n            <summary>\n            Gets the value for the system control panel mouse wheel scroll settings.\n            The value returns the number of lines that shall be scolled if the user turns the mouse wheet one step.\n            </summary>\n            <remarks>\n            This methods gets the \"WheelScrollLines\" value our from the registry key \"HKEY_CURRENT_USER\\Control Panel\\Desktop\".\n            If the value of this option is 0, the screen will not scroll when the mouse wheel is turned.\n            If the value of this option is -1 or is greater than the number of lines visible in the window,\n            the screen will scroll up or down by one page.\n            </remarks>\n            <returns>\n            Number of lines to scrol l when the mouse wheel is turned\n            </returns>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FastColoredTextBox.Zoom\">\n            <summary>\n            Zooming (in percentages)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.PointToPlace(System.Drawing.Point)\">\n            <summary>\n            Gets nearest line and char position from coordinates\n            </summary>\n            <param name=\"point\">Point</param>\n            <returns>Line and char position</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.PointToPosition(System.Drawing.Point)\">\n            <summary>\n            Gets nearest absolute text position for given point\n            </summary>\n            <param name=\"point\">Point</param>\n            <returns>Position</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnTextChanging(System.String@)\">\n            <summary>\n            Fires TextChanging event\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnTextChanged\">\n            <summary>\n            Fires TextChanged event\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnTextChanged(System.Int32,System.Int32)\">\n            <summary>\n            Fires TextChanged event\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnTextChanged(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Fires TextChanged event\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.BeginUpdate\">\n            <summary>\n            Call this method before multiple text changing\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.EndUpdate\">\n            <summary>\n            Call this method after multiple text changing\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnTextChanged(FastColoredTextBoxNS.TextChangedEventArgs)\">\n            <summary>\n            Fires TextChanged event\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ClearFoldingState(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Clears folding state for range of text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnSelectionChanged\">\n            <summary>\n            Fires SelectionChanged event\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.PlaceToPosition(FastColoredTextBoxNS.Place)\">\n            <summary>\n            Gets absolute text position from line and char position\n            </summary>\n            <param name=\"point\">Line and char position</param>\n            <returns>Point of char</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.PositionToPlace(System.Int32)\">\n            <summary>\n            Gets line and char position from absolute text position\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.PositionToPoint(System.Int32)\">\n            <summary>\n            Gets absolute char position from char position\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.PlaceToPoint(FastColoredTextBoxNS.Place)\">\n            <summary>\n            Gets point for given line and char position\n            </summary>\n            <param name=\"place\">Line and char position</param>\n            <returns>Coordiantes</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetRange(System.Int32,System.Int32)\">\n            <summary>\n            Get range of text\n            </summary>\n            <param name=\"fromPos\">Absolute start position</param>\n            <param name=\"toPos\">Absolute finish position</param>\n            <returns>Range</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetRange(FastColoredTextBoxNS.Place,FastColoredTextBoxNS.Place)\">\n            <summary>\n            Get range of text\n            </summary>\n            <param name=\"fromPlace\">Line and char position</param>\n            <param name=\"toPlace\">Line and char position</param>\n            <returns>Range</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetRanges(System.String)\">\n            <summary>\n            Finds ranges for given regex pattern\n            </summary>\n            <param name=\"regexPattern\">Regex pattern</param>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetRanges(System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Finds ranges for given regex pattern\n            </summary>\n            <param name=\"regexPattern\">Regex pattern</param>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetLineText(System.Int32)\">\n            <summary>\n            Get text of given line\n            </summary>\n            <param name=\"iLine\">Line index</param>\n            <returns>Text</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ExpandFoldedBlock(System.Int32)\">\n            <summary>\n            Exapnds folded block\n            </summary>\n            <param name=\"iLine\">Start line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.AdjustFolding\">\n            <summary>\n            Collapse folding blocks using FoldedBlocks dictionary.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ExpandBlock(System.Int32,System.Int32)\">\n            <summary>\n            Expand collapsed block\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ExpandBlock(System.Int32)\">\n            <summary>\n            Expand collapsed block\n            </summary>\n            <param name=\"iLine\">Any line inside collapsed block</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CollapseAllFoldingBlocks\">\n            <summary>\n            Collapses all folding blocks\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ExpandAllFoldingBlocks\">\n            <summary>\n            Exapnds all folded blocks\n            </summary>\n            <param name=\"iLine\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CollapseFoldingBlock(System.Int32)\">\n            <summary>\n            Collapses folding block\n            </summary>\n            <param name=\"iLine\">Start folding line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetLineFoldingStartMarker(System.Int32)\">\n            <summary>\n            Start foilding marker for the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetLineFoldingEndMarker(System.Int32)\">\n            <summary>\n            End foilding marker for the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CollapseBlock(System.Int32,System.Int32)\">\n            <summary>\n            Collapse text block\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.IncreaseIndent\">\n            <summary>\n            Insert TAB into front of seletcted lines.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DecreaseIndent\">\n            <summary>\n            Remove TAB from front of seletcted lines.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DecreaseIndentOfSingleLine\">\n            <summary>\n            Remove TAB in front of the caret ot the selected line.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DoAutoIndent\">\n            <summary>\n            Insert autoindents into selected lines\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.InsertLinePrefix(System.String)\">\n            <summary>\n            Insert prefix into front of seletcted lines\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.RemoveLinePrefix(System.String)\">\n            <summary>\n            Remove prefix from front of selected lines\n            This method ignores forward spaces of the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.BeginAutoUndo\">\n            <summary>\n            Begins AutoUndo block.\n            All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.EndAutoUndo\">\n            <summary>\n            Ends AutoUndo block.\n            All changes of text between BeginAutoUndo() and EndAutoUndo() will be canceled in one operation Undo.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.HighlightBrackets(System.Char,System.Char,FastColoredTextBoxNS.Range@,FastColoredTextBoxNS.Range@)\">\n            <summary>\n            Highlights brackets around caret\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetBracketsRange(FastColoredTextBoxNS.Place,System.Char,System.Char)\">\n            <summary>\n            Returns range between brackets (or null if not found)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.SelectNext(System.String,System.Boolean,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Selectes next fragment for given regex.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Print(FastColoredTextBoxNS.Range,FastColoredTextBoxNS.PrintDialogSettings)\">\n            <summary>\n            Prints range of text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Print(FastColoredTextBoxNS.PrintDialogSettings)\">\n            <summary>\n            Prints all text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.Print\">\n            <summary>\n            Prints all text, without any dialog windows\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OpenFile(System.String,System.Text.Encoding)\">\n            <summary>\n            Open text file\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OpenFile(System.String)\">\n            <summary>\n            Open text file (with automatic encoding detector)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OpenBindingFile(System.String,System.Text.Encoding)\">\n            <summary>\n            Open file binding mode\n            </summary>\n            <param name=\"fileName\"></param>\n            <param name=\"enc\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.CloseBindingFile\">\n            <summary>\n            Close file binding mode\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.SaveToFile(System.String,System.Text.Encoding)\">\n            <summary>\n            Save text to the file\n            </summary>\n            <param name=\"fileName\"></param>\n            <param name=\"enc\"></param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.SetVisibleState(System.Int32,FastColoredTextBoxNS.VisibleState)\">\n            <summary>\n            Set VisibleState of line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.GetVisibleState(System.Int32)\">\n            <summary>\n            Returns VisibleState of the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ShowGoToDialog\">\n            <summary>\n            Shows Goto dialog form\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.OnUndoRedoStateChanged\">\n            <summary>\n            Occurs when undo/redo stack is changed\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.FindLines(System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Search lines by regex pattern\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.RemoveLines(System.Collections.Generic.List{System.Int32})\">\n            <summary>\n            Removes given lines\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.ActivateMiddleClickScrollingMode(System.Windows.Forms.MouseEventArgs)\">\n            <summary>\n            Activates the scrolling mode (middle click button).\n            </summary>\n            <param name=\"e\">MouseEventArgs</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.DeactivateMiddleClickScrollingMode\">\n            <summary>\n            Deactivates the scrolling mode (middle click button).\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FastColoredTextBox.RestoreScrollsAfterMiddleClickScrollingMode\">\n            <summary>\n            Restore scrolls\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineInsertedEventArgs.Index\">\n            <summary>\n            Inserted line index\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineInsertedEventArgs.Count\">\n            <summary>\n            Count of inserted lines\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineRemovedEventArgs.Index\">\n            <summary>\n            Removed line index\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineRemovedEventArgs.Count\">\n            <summary>\n            Count of removed lines\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineRemovedEventArgs.RemovedLineUniqueIds\">\n            <summary>\n            UniqueIds of removed lines\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.TextChangedEventArgs\">\n            <summary>\n            TextChanged event argument\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.TextChangedEventArgs.#ctor(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Constructor\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.TextChangedEventArgs.ChangedRange\">\n            <summary>\n            This range contains changed area of text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.TextChangingEventArgs.Cancel\">\n            <summary>\n            Set to true if you want to cancel text inserting\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.WordWrapMode.WordWrapControlWidth\">\n            <summary>\n            Word wrapping by control width\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.WordWrapMode.WordWrapPreferredWidth\">\n            <summary>\n            Word wrapping by preferred line width (PreferredLineWidth)\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.WordWrapMode.CharWrapControlWidth\">\n            <summary>\n            Char wrapping by control width\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.WordWrapMode.CharWrapPreferredWidth\">\n            <summary>\n            Char wrapping by preferred line width (PreferredLineWidth)\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.WordWrapMode.Custom\">\n            <summary>\n            Custom wrap (by event WordWrapNeeded)\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.PrintDialogSettings.Title\">\n            <summary>\n            Title of page. If you want to print Title on the page, insert code &amp;w in Footer or Header.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.PrintDialogSettings.Footer\">\n            <summary>\n            Footer of page.\n            Here you can use special codes: &amp;w (Window title), &amp;D, &amp;d (Date), &amp;t(), &amp;4 (Time), &amp;p (Current page number), &amp;P (Total number of pages),  &amp;&amp; (A single ampersand), &amp;b (Right justify text, Center text. If &amp;b occurs once, then anything after the &amp;b is right justified. If &amp;b occurs twice, then anything between the two &amp;b is centered, and anything after the second &amp;b is right justified).\n            More detailed see <see cref=\"!:http://msdn.microsoft.com/en-us/library/aa969429(v=vs.85).aspx\">here</see>\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.PrintDialogSettings.Header\">\n            <summary>\n            Header of page\n            Here you can use special codes: &amp;w (Window title), &amp;D, &amp;d (Date), &amp;t(), &amp;4 (Time), &amp;p (Current page number), &amp;P (Total number of pages),  &amp;&amp; (A single ampersand), &amp;b (Right justify text, Center text. If &amp;b occurs once, then anything after the &amp;b is right justified. If &amp;b occurs twice, then anything between the two &amp;b is centered, and anything after the second &amp;b is right justified).\n            More detailed see <see cref=\"!:http://msdn.microsoft.com/en-us/library/aa969429(v=vs.85).aspx\">here</see>\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.PrintDialogSettings.IncludeLineNumbers\">\n            <summary>\n            Prints line numbers\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutoIndentEventArgs.Shift\">\n            <summary>\n            Additional spaces count for this line, relative to previous line\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutoIndentEventArgs.ShiftNextLines\">\n            <summary>\n            Additional spaces count for next line, relative to previous line\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.AutoIndentEventArgs.AbsoluteIndentation\">\n            <summary>\n            Absolute indentation of current line. You can change this property if you want to set absolute indentation.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.HighlightingRangeType\">\n            <summary>\n            Type of highlighting\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.HighlightingRangeType.ChangedRange\">\n            <summary>\n            Highlight only changed range of text. Highest performance.\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.HighlightingRangeType.VisibleRange\">\n            <summary>\n            Highlight visible range of text. Middle performance.\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.HighlightingRangeType.AllTextRange\">\n            <summary>\n            Highlight all (visible and invisible) text. Lowest performance.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.FindEndOfFoldingBlockStrategy\">\n            <summary>\n            Strategy of search of end of folding block\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.BracketsHighlightStrategy\">\n            <summary>\n            Strategy of search of brackets to highlighting\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ToolTipNeededEventArgs\">\n            <summary>\n            ToolTipNeeded event args\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.HintClickEventArgs\">\n            <summary>\n            HintClick event args\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.CustomActionEventArgs\">\n            <summary>\n            CustomAction event args\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.StyleIndex\">\n            <summary>\n            Style index mask (16 styles)\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.InsertCharCommand\">\n            <summary>\n            Insert single char\n            </summary>\n            <remarks>This operation includes also insertion of new line and removing char by backspace</remarks>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.InsertCharCommand.#ctor(FastColoredTextBoxNS.TextSource,System.Char)\">\n            <summary>\n            Constructor\n            </summary>\n            <param name=\"tb\">Underlaying textbox</param>\n            <param name=\"c\">Inserting char</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.InsertCharCommand.Undo\">\n            <summary>\n            Undo operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.InsertCharCommand.Execute\">\n            <summary>\n            Execute operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.InsertCharCommand.MergeLines(System.Int32,FastColoredTextBoxNS.TextSource)\">\n            <summary>\n            Merge lines i and i+1\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.InsertTextCommand\">\n            <summary>\n            Insert text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.InsertTextCommand.#ctor(FastColoredTextBoxNS.TextSource,System.String)\">\n            <summary>\n            Constructor\n            </summary>\n            <param name=\"tb\">Underlaying textbox</param>\n            <param name=\"insertedText\">Text for inserting</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.InsertTextCommand.Undo\">\n            <summary>\n            Undo operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.InsertTextCommand.Execute\">\n            <summary>\n            Execute operation\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ReplaceTextCommand\">\n            <summary>\n            Insert text into given ranges\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceTextCommand.#ctor(FastColoredTextBoxNS.TextSource,System.Collections.Generic.List{FastColoredTextBoxNS.Range},System.String)\">\n            <summary>\n            Constructor\n            </summary>\n            <param name=\"tb\">Underlaying textbox</param>\n            <param name=\"ranges\">List of ranges for replace</param>\n            <param name=\"insertedText\">Text for inserting</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceTextCommand.Undo\">\n            <summary>\n            Undo operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceTextCommand.Execute\">\n            <summary>\n            Execute operation\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ClearSelectedCommand\">\n            <summary>\n            Clear selected text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ClearSelectedCommand.#ctor(FastColoredTextBoxNS.TextSource)\">\n            <summary>\n            Construstor\n            </summary>\n            <param name=\"tb\">Underlaying textbox</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ClearSelectedCommand.Undo\">\n            <summary>\n            Undo operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ClearSelectedCommand.Execute\">\n            <summary>\n            Execute operation\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ReplaceMultipleTextCommand\">\n            <summary>\n            Replaces text\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceMultipleTextCommand.#ctor(FastColoredTextBoxNS.TextSource,System.Collections.Generic.List{FastColoredTextBoxNS.ReplaceMultipleTextCommand.ReplaceRange})\">\n            <summary>\n            Constructor\n            </summary>\n            <param name=\"ts\">Underlaying textsource</param>\n            <param name=\"ranges\">List of ranges for replace</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceMultipleTextCommand.Undo\">\n            <summary>\n            Undo operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.ReplaceMultipleTextCommand.Execute\">\n            <summary>\n            Execute operation\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.RemoveLinesCommand\">\n            <summary>\n            Removes lines\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.RemoveLinesCommand.#ctor(FastColoredTextBoxNS.TextSource,System.Collections.Generic.List{System.Int32})\">\n            <summary>\n            Constructor\n            </summary>\n            <param name=\"tb\">Underlaying textbox</param>\n            <param name=\"ranges\">List of ranges for replace</param>\n            <param name=\"insertedText\">Text for inserting</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.RemoveLinesCommand.Undo\">\n            <summary>\n            Undo operation\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.RemoveLinesCommand.Execute\">\n            <summary>\n            Execute operation\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.MultiRangeCommand\">\n            <summary>\n            Wrapper for multirange commands\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.SelectCommand\">\n            <summary>\n            Remembers current selection and restore it after Undo\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.FindForm.components\">\n            <summary>\n            Required designer variable.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FindForm.Dispose(System.Boolean)\">\n            <summary>\n            Clean up any resources being used.\n            </summary>\n            <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.FindForm.InitializeComponent\">\n            <summary>\n            Required method for Designer support - do not modify\n            the contents of this method with the code editor.\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.LimitedStack`1\">\n            <summary>\n            Limited stack\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LimitedStack`1.MaxItemCount\">\n            <summary>\n            Max stack length\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LimitedStack`1.Count\">\n            <summary>\n            Current length of stack\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.LimitedStack`1.#ctor(System.Int32)\">\n            <summary>\n            Constructor\n            </summary>\n            <param name=\"maxItemCount\">Maximum length of stack</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.LimitedStack`1.Pop\">\n            <summary>\n            Pop item\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.LimitedStack`1.Peek\">\n            <summary>\n            Peek item\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.LimitedStack`1.Push(`0)\">\n            <summary>\n            Push item\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.LimitedStack`1.Clear\">\n            <summary>\n            Clear stack\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Line\">\n            <summary>\n            Line of text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.IsChanged\">\n            <summary>\n            Text of line was changed\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.LastVisit\">\n            <summary>\n            Time of last visit of caret in this line\n            </summary>\n            <remarks>This property can be used for forward/backward navigating</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.BackgroundBrush\">\n            <summary>\n            Background brush.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.UniqueId\">\n            <summary>\n            Unique ID\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.AutoIndentSpacesNeededCount\">\n            <summary>\n            Count of needed start spaces for AutoIndent\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Line.ClearStyle(FastColoredTextBoxNS.StyleIndex)\">\n            <summary>\n            Clears style of chars, delete folding markers\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.Text\">\n            <summary>\n            Text of the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Line.ClearFoldingMarkers\">\n            <summary>\n            Clears folding markers\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.StartSpacesCount\">\n            <summary>\n            Count of start spaces\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Line.Count\">\n            <summary>\n            Chars count\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.LineInfo.VisibleState\">\n            <summary>\n            Visible state\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineInfo.CutOffPositions\">\n            <summary>\n            Positions for wordwrap cutoffs\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineInfo.WordWrapStringsCount\">\n            <summary>\n            Count of wordwrap string count for this line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.LineInfo.GetWordWrapStringIndex(System.Int32)\">\n            <summary>\n            Gets index of wordwrap string for given char position\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Place\">\n            <summary>\n            Line index and char index\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Range\">\n            <summary>\n            Diapason of text chars\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.#ctor(FastColoredTextBoxNS.FastColoredTextBox)\">\n            <summary>\n            Constructor\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.IsEmpty\">\n            <summary>\n            Return true if no selected text\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.ColumnSelectionMode\">\n            <summary>\n            Column selection mode\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.#ctor(FastColoredTextBoxNS.FastColoredTextBox,System.Int32,System.Int32,System.Int32,System.Int32)\">\n            <summary>\n            Constructor\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.#ctor(FastColoredTextBoxNS.FastColoredTextBox,FastColoredTextBoxNS.Place,FastColoredTextBoxNS.Place)\">\n            <summary>\n            Constructor\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.#ctor(FastColoredTextBoxNS.FastColoredTextBox,System.Int32)\">\n            <summary>\n            Constructor. Creates range of the line\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetIntersectionWith(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Returns intersection with other range,\n            empty range returned otherwise\n            </summary>\n            <param name=\"range\"></param>\n            <returns></returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetUnionWith(FastColoredTextBoxNS.Range)\">\n            <summary>\n            Returns union with other range.\n            </summary>\n            <param name=\"range\"></param>\n            <returns></returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SelectAll\">\n            <summary>\n            Select all chars of control\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.Start\">\n            <summary>\n            Start line and char position\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.End\">\n            <summary>\n            Finish line and char position\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.Text\">\n            <summary>\n            Text of range\n            </summary>\n            <remarks>This property has not 'set' accessor because undo/redo stack works only with \n            FastColoredTextBox.Selection range. So, if you want to set text, you need to use FastColoredTextBox.Selection\n            and FastColoredTextBox.InsertText() mehtod.\n            </remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.CharAfterStart\">\n            <summary>\n            Returns first char after Start place\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.CharBeforeStart\">\n            <summary>\n            Returns first char before Start place\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetCharsBeforeStart(System.Int32)\">\n            <summary>\n            Returns required char's number before start of the Range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetCharsAfterStart(System.Int32)\">\n            <summary>\n            Returns required char's number after start of the Range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.Clone\">\n            <summary>\n            Clone range\n            </summary>\n            <returns></returns>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.FromX\">\n            <summary>\n            Return minimum of end.X and start.X\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.ToX\">\n            <summary>\n            Return maximum of end.X and start.X\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GoRight\">\n            <summary>\n            Move range right\n            </summary>\n            <remarks>This method jump over folded blocks</remarks>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GoRightThroughFolded\">\n            <summary>\n            Move range left\n            </summary>\n            <remarks>This method can to go inside folded blocks</remarks>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GoLeft\">\n            <summary>\n            Move range left\n            </summary>\n            <remarks>This method jump over folded blocks</remarks>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GoLeftThroughFolded\">\n            <summary>\n            Move range left\n            </summary>\n            <remarks>This method can to go inside folded blocks</remarks>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetStyle(FastColoredTextBoxNS.Style)\">\n            <summary>\n            Set style for range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetStyle(FastColoredTextBoxNS.Style,System.String)\">\n            <summary>\n            Set style for given regex pattern\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetStyle(FastColoredTextBoxNS.Style,System.Text.RegularExpressions.Regex)\">\n            <summary>\n            Set style for given regex\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetStyle(FastColoredTextBoxNS.Style,System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Set style for given regex pattern\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetStyle(FastColoredTextBoxNS.StyleIndex,System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Set style for given regex pattern\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetStyle(FastColoredTextBoxNS.StyleIndex,System.Text.RegularExpressions.Regex)\">\n            <summary>\n            Set style for given regex pattern\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetStyle(FastColoredTextBoxNS.StyleIndex)\">\n            <summary>\n            Appends style to chars of range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetFoldingMarkers(System.String,System.String)\">\n            <summary>\n            Sets folding markers\n            </summary>\n            <param name=\"startFoldingPattern\">Pattern for start folding line</param>\n            <param name=\"finishFoldingPattern\">Pattern for finish folding line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetFoldingMarkers(System.String,System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Sets folding markers\n            </summary>\n            <param name=\"startFoldingPattern\">Pattern for start folding line</param>\n            <param name=\"finishFoldingPattern\">Pattern for finish folding line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.SetFoldingMarkers(System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Sets folding markers\n            </summary>\n            <param name=\"startEndFoldingPattern\">Pattern for start and end folding line</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetRanges(System.String)\">\n            <summary>\n            Finds ranges for given regex pattern\n            </summary>\n            <param name=\"regexPattern\">Regex pattern</param>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetRanges(System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Finds ranges for given regex pattern\n            </summary>\n            <param name=\"regexPattern\">Regex pattern</param>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetRangesByLines(System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Finds ranges for given regex pattern.\n            Search is separately in each line.\n            This method requires less memory than GetRanges().\n            </summary>\n            <param name=\"regexPattern\">Regex pattern</param>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetRangesByLines(System.Text.RegularExpressions.Regex)\">\n            <summary>\n            Finds ranges for given regex.\n            Search is separately in each line.\n            This method requires less memory than GetRanges().\n            </summary>\n            <param name=\"regex\">Regex</param>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetRangesByLinesReversed(System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Finds ranges for given regex pattern.\n            Search is separately in each line (order of lines is reversed).\n            This method requires less memory than GetRanges().\n            </summary>\n            <param name=\"regexPattern\">Regex pattern</param>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetRanges(System.Text.RegularExpressions.Regex)\">\n            <summary>\n            Finds ranges for given regex\n            </summary>\n            <returns>Enumeration of ranges</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.ClearStyle(FastColoredTextBoxNS.Style[])\">\n            <summary>\n            Clear styles of range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.ClearStyle(FastColoredTextBoxNS.StyleIndex)\">\n            <summary>\n            Clear styles of range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.ClearFoldingMarkers\">\n            <summary>\n            Clear folding markers of all lines of range\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.BeginUpdate\">\n            <summary>\n            Starts selection position updating\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.EndUpdate\">\n            <summary>\n            Ends selection position updating\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.Normalize\">\n            <summary>\n            Exchanges Start and End if End appears before Start\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.Inverse\">\n            <summary>\n            Exchanges Start and End\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.Expand\">\n            <summary>\n            Expands range from first char of Start line to last char of End line\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.Chars\">\n            <summary>\n            Chars of range (exclude \\n)\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetFragment(System.String)\">\n            <summary>\n            Get fragment of text around Start place. Returns maximal matched to pattern fragment.\n            </summary>\n            <param name=\"allowedSymbolsPattern\">Allowed chars pattern for fragment</param>\n            <returns>Range of found fragment</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetFragment(FastColoredTextBoxNS.Style,System.Boolean)\">\n            <summary>\n            Get fragment of text around Start place. Returns maximal matched to given Style.\n            </summary>\n            <param name=\"style\">Allowed style for fragment</param>\n            <returns>Range of found fragment</returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.GetFragment(System.String,System.Text.RegularExpressions.RegexOptions)\">\n            <summary>\n            Get fragment of text around Start place. Returns maximal mathed to pattern fragment.\n            </summary>\n            <param name=\"allowedSymbolsPattern\">Allowed chars pattern for fragment</param>\n            <returns>Range of found fragment</returns>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Range.ReadOnly\">\n            <summary>\n            Range is readonly?\n            This property return True if any char of the range contains ReadOnlyStyle.\n            Set this property to True/False to mark chars of the range as Readonly/Writable.\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.IsReadOnlyLeftChar\">\n            <summary>\n            Is char before range readonly\n            </summary>\n            <returns></returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Range.IsReadOnlyRightChar\">\n            <summary>\n            Is char after range readonly\n            </summary>\n            <returns></returns>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.Style\">\n            <summary>\n            Style of chars\n            </summary>\n            <remarks>This is base class for all text and design renderers</remarks>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.Style.IsExportable\">\n            <summary>\n            This style is exported to outer formats (HTML for example)\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.Style.VisualMarkerClick\">\n            <summary>\n            Occurs when user click on StyleVisualMarker joined to this style \n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Style.#ctor\">\n            <summary>\n            Constructor\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Style.Draw(System.Drawing.Graphics,System.Drawing.Point,FastColoredTextBoxNS.Range)\">\n            <summary>\n            Renders given range of text\n            </summary>\n            <param name=\"gr\">Graphics object</param>\n            <param name=\"position\">Position of the range in absolute control coordinates</param>\n            <param name=\"range\">Rendering range of text</param>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Style.OnVisualMarkerClick(FastColoredTextBoxNS.FastColoredTextBox,FastColoredTextBoxNS.VisualMarkerEventArgs)\">\n            <summary>\n            Occurs when user click on StyleVisualMarker joined to this style \n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Style.AddVisualMarker(FastColoredTextBoxNS.FastColoredTextBox,FastColoredTextBoxNS.StyleVisualMarker)\">\n            <summary>\n            Shows VisualMarker\n            Call this method in Draw method, when you need to show VisualMarker for your style\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Style.GetCSS\">\n            <summary>\n            Returns CSS for export to HTML\n            </summary>\n            <returns></returns>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.Style.GetRTF\">\n            <summary>\n            Returns RTF descriptor for export to RTF\n            </summary>\n            <returns></returns>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.TextStyle\">\n            <summary>\n            Style for chars rendering\n            This renderer can draws chars, with defined fore and back colors\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.FoldedBlockStyle\">\n            <summary>\n            Renderer for folded block\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.SelectionStyle\">\n            <summary>\n            Renderer for selected area\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.MarkerStyle\">\n            <summary>\n            Marker style\n            Draws background color for text\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ShortcutStyle\">\n            <summary>\n            Draws small rectangle for popup menu\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.WavyLineStyle\">\n            <summary>\n            This style draws a wavy line below a given text range.\n            </summary>\n            <remarks>Thanks for Yallie</remarks>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.ReadOnlyStyle\">\n            <summary>\n            This style is used to mark range of text as ReadOnly block\n            </summary>\n            <remarks>You can inherite this style to add visual effects of readonly text</remarks>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.TextSource\">\n            <summary>\n            This class contains the source text (chars and styles).\n            It stores a text lines, the manager of commands, undo/redo stack, styles.\n            </summary>\n        </member>\n        <member name=\"F:FastColoredTextBoxNS.TextSource.Styles\">\n            <summary>\n            Styles\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.TextSource.LineInserted\">\n            <summary>\n            Occurs when line was inserted/added\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.TextSource.LineRemoved\">\n            <summary>\n            Occurs when line was removed\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.TextSource.TextChanged\">\n            <summary>\n            Occurs when text was changed\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.TextSource.RecalcNeeded\">\n            <summary>\n            Occurs when recalc is needed\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.TextSource.RecalcWordWrap\">\n            <summary>\n            Occurs when recalc wordwrap is needed\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.TextSource.TextChanging\">\n            <summary>\n            Occurs before text changing\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.TextSource.CurrentTBChanged\">\n            <summary>\n            Occurs after CurrentTB was changed\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.TextSource.CurrentTB\">\n            <summary>\n            Current focused FastColoredTextBox\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.TextSource.DefaultStyle\">\n            <summary>\n            Default text style\n            This style is using when no one other TextStyle is not defined in Char.style\n            </summary>\n        </member>\n        <member name=\"M:FastColoredTextBoxNS.TextSource.GetLines\">\n            <summary>\n            Text lines\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.TextSource.Count\">\n            <summary>\n            Lines count\n            </summary>\n        </member>\n        <member name=\"T:FastColoredTextBoxNS.FCTBDescriptionProvider\">\n            \n             These classes are required for correct data binding to Text property of FastColoredTextbox\n             \n        </member>\n        <member name=\"T:FastColoredTextBoxNS.FileTextSource\">\n            <summary>\n            This class contains the source text (chars and styles).\n            It stores a text lines, the manager of commands, undo/redo stack, styles.\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FileTextSource.LineNeeded\">\n            <summary>\n            Occurs when need to display line in the textbox\n            </summary>\n        </member>\n        <member name=\"E:FastColoredTextBoxNS.FileTextSource.LinePushed\">\n            <summary>\n            Occurs when need to save line in the file\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.FileTextSource.SaveEOL\">\n            <summary>\n            End Of Line characters used for saving\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LineNeededEventArgs.DisplayedLineText\">\n            <summary>\n            This text will be displayed in textbox\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LinePushedEventArgs.DisplayedLineText\">\n            <summary>\n            This property contains only changed text.\n            If text of line is not changed, this property contains null.\n            </summary>\n        </member>\n        <member name=\"P:FastColoredTextBoxNS.LinePushedEventArgs.SavedText\">\n            <summary>\n            This text will be saved in the file\n            </summary>\n        </member>\n    </members>\n</doc>\n"
  },
  {
    "path": "FastColoredTextBox/FileTextSource.cs",
    "content": "﻿//#define debug\n\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.IO;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// This class contains the source text (chars and styles).\n    /// It stores a text lines, the manager of commands, undo/redo stack, styles.\n    /// </summary>\n    public class FileTextSource : TextSource, IDisposable\n    {\n        List<int> sourceFileLinePositions = new List<int>();\n        FileStream fs;\n        Encoding fileEncoding;\n        System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();\n\n        /// <summary>\n        /// Occurs when need to display line in the textbox\n        /// </summary>\n        public event EventHandler<LineNeededEventArgs> LineNeeded;\n\n        /// <summary>\n        /// Occurs when need to save line in the file\n        /// </summary>\n        public event EventHandler<LinePushedEventArgs> LinePushed;\n\n        public FileTextSource(FastColoredTextBox currentTB)\n            : base(currentTB)\n        {\n            timer.Interval = 10000;\n            timer.Tick += new EventHandler(timer_Tick);\n            timer.Enabled = true;\n\n            SaveEOL = Environment.NewLine;\n        }\n\n        void timer_Tick(object sender, EventArgs e)\n        {\n            timer.Enabled = false;\n            try\n            {\n                UnloadUnusedLines();\n            }\n            finally\n            {\n                timer.Enabled = true;\n            }\n        }\n\n        private void UnloadUnusedLines()\n        {\n            const int margin = 2000;\n            var iStartVisibleLine = CurrentTB.VisibleRange.Start.iLine;\n            var iFinishVisibleLine = CurrentTB.VisibleRange.End.iLine;\n\n            int count = 0;\n            for (int i = 0; i < Count; i++)\n                if (base.lines[i] != null && !base.lines[i].IsChanged && Math.Abs(i - iFinishVisibleLine) > margin)\n                {\n                    base.lines[i] = null;\n                    count++;\n                }\n#if debug\n            Console.WriteLine(\"UnloadUnusedLines: \" + count);\n#endif\n        }\n\n        public void OpenFile(string fileName, Encoding enc)\n        {\n            Clear();\n\n            if (fs != null)\n                fs.Dispose();\n\n            SaveEOL = Environment.NewLine;\n\n            //read lines of file\n            fs = new FileStream(fileName, FileMode.Open);\n            var length = fs.Length;\n            //read signature\n            enc = DefineEncoding(enc, fs);\n            int shift = DefineShift(enc);\n            //first line\n            sourceFileLinePositions.Add((int) fs.Position);\n            base.lines.Add(null);\n            //other lines\n            sourceFileLinePositions.Capacity = (int) (length / 7 + 1000);\n\n            //int prev = 0;\n            //while(fs.Position < length)\n            //{\n            //    var b = fs.ReadByte();\n\n            //    if (b == 10)// \\n\n            //    {\n            //        sourceFileLinePositions.Add((int)(fs.Position) + shift);\n            //        base.lines.Add(null);\n            //    }else\n            //    if (prev == 13)// \\r (Mac format)\n            //    {\n            //        sourceFileLinePositions.Add((int)(fs.Position - 1) + shift);\n            //        base.lines.Add(null);\n            //        SaveEOL = \"\\r\";\n            //    }\n\n            //    prev = b;\n            //}\n\n            //if (prev == 13)\n            //{\n            //    sourceFileLinePositions.Add((int)(fs.Position) + shift);\n            //    base.lines.Add(null);\n            //}\n\n            int prev = 0;\n            int prevPos = 0;\n            BinaryReader br = new BinaryReader(fs, enc);\n            while (fs.Position < length)\n            {\n                prevPos = (int) fs.Position;\n                var b = br.ReadChar();\n\n                if (b == 10) // \\n\n                {\n                    sourceFileLinePositions.Add((int) fs.Position);\n                    base.lines.Add(null);\n                }\n                else if (prev == 13) // \\r (Mac format)\n                {\n                    sourceFileLinePositions.Add((int) prevPos);\n                    base.lines.Add(null);\n                    SaveEOL = \"\\r\";\n                }\n\n                prev = b;\n            }\n\n            if (prev == 13)\n            {\n                sourceFileLinePositions.Add((int) prevPos);\n                base.lines.Add(null);\n            }\n\n            if (length > 2000000)\n                GC.Collect();\n\n            Line[] temp = new Line[100];\n\n            var c = base.lines.Count;\n            base.lines.AddRange(temp);\n            base.lines.TrimExcess();\n            base.lines.RemoveRange(c, temp.Length);\n\n\n            int[] temp2 = new int[100];\n            c = base.lines.Count;\n            sourceFileLinePositions.AddRange(temp2);\n            sourceFileLinePositions.TrimExcess();\n            sourceFileLinePositions.RemoveRange(c, temp.Length);\n\n\n            fileEncoding = enc;\n\n            OnLineInserted(0, Count);\n            //load first lines for calc width of the text\n            var linesCount = Math.Min(lines.Count, CurrentTB.ClientRectangle.Height / CurrentTB.CharHeight);\n            for (int i = 0; i < linesCount; i++)\n                LoadLineFromSourceFile(i);\n            //\n            NeedRecalc(new TextChangedEventArgs(0, linesCount - 1));\n            if (CurrentTB.WordWrap)\n                OnRecalcWordWrap(new TextChangedEventArgs(0, linesCount - 1));\n        }\n\n        private int DefineShift(Encoding enc)\n        {\n            if (enc.IsSingleByte)\n                return 0;\n\n            if (enc.HeaderName == \"unicodeFFFE\")\n                return 0; //UTF16 BE\n\n            if (enc.HeaderName == \"utf-16\")\n                return 1; //UTF16 LE\n\n            if (enc.HeaderName == \"utf-32BE\")\n                return 0; //UTF32 BE\n\n            if (enc.HeaderName == \"utf-32\")\n                return 3; //UTF32 LE\n\n            return 0;\n        }\n\n        private static Encoding DefineEncoding(Encoding enc, FileStream fs)\n        {\n            int bytesPerSignature = 0;\n            byte[] signature = new byte[4];\n            int c = fs.Read(signature, 0, 4);\n            if (signature[0] == 0xFF && signature[1] == 0xFE && signature[2] == 0x00 && signature[3] == 0x00 && c >= 4)\n            {\n                enc = Encoding.UTF32; //UTF32 LE\n                bytesPerSignature = 4;\n            }\n            else if (signature[0] == 0x00 && signature[1] == 0x00 && signature[2] == 0xFE && signature[3] == 0xFF)\n            {\n                enc = new UTF32Encoding(true, true); //UTF32 BE\n                bytesPerSignature = 4;\n            }\n            else if (signature[0] == 0xEF && signature[1] == 0xBB && signature[2] == 0xBF)\n            {\n                enc = Encoding.UTF8; //UTF8\n                bytesPerSignature = 3;\n            }\n            else if (signature[0] == 0xFE && signature[1] == 0xFF)\n            {\n                enc = Encoding.BigEndianUnicode; //UTF16 BE\n                bytesPerSignature = 2;\n            }\n            else if (signature[0] == 0xFF && signature[1] == 0xFE)\n            {\n                enc = Encoding.Unicode; //UTF16 LE\n                bytesPerSignature = 2;\n            }\n\n            fs.Seek(bytesPerSignature, SeekOrigin.Begin);\n\n            return enc;\n        }\n\n        public void CloseFile()\n        {\n            if (fs != null)\n                try\n                {\n                    fs.Dispose();\n                }\n                catch\n                {\n                    ;\n                }\n\n            fs = null;\n        }\n\n        /// <summary>\n        /// End Of Line characters used for saving\n        /// </summary>\n        public string SaveEOL { get; set; }\n\n        public override void SaveToFile(string fileName, Encoding enc)\n        {\n            //\n            var newLinePos = new List<int>(Count);\n            //create temp file\n            var dir = Path.GetDirectoryName(fileName);\n            var tempFileName = Path.Combine(dir, Path.GetFileNameWithoutExtension(fileName) + \".tmp\");\n\n            StreamReader sr = new StreamReader(fs, fileEncoding);\n            using (FileStream tempFs = new FileStream(tempFileName, FileMode.Create))\n            using (StreamWriter sw = new StreamWriter(tempFs, enc))\n            {\n                sw.Flush();\n\n                for (int i = 0; i < Count; i++)\n                {\n                    newLinePos.Add((int) tempFs.Length);\n\n                    var sourceLine = ReadLine(sr, i); //read line from source file\n                    string line;\n\n                    bool lineIsChanged = lines[i] != null && lines[i].IsChanged;\n\n                    if (lineIsChanged)\n                        line = lines[i].Text;\n                    else\n                        line = sourceLine;\n\n                    //call event handler\n                    if (LinePushed != null)\n                    {\n                        var args = new LinePushedEventArgs(sourceLine, i, lineIsChanged ? line : null);\n                        LinePushed(this, args);\n\n                        if (args.SavedText != null)\n                            line = args.SavedText;\n                    }\n\n                    //save line to file\n                    sw.Write(line);\n\n                    if (i < Count - 1)\n                        sw.Write(SaveEOL);\n\n                    sw.Flush();\n                }\n            }\n\n            //clear lines buffer\n            for (int i = 0; i < Count; i++)\n                lines[i] = null;\n            //deattach from source file\n            sr.Dispose();\n            fs.Dispose();\n            //delete target file\n            if (File.Exists(fileName))\n                File.Delete(fileName);\n            //rename temp file\n            File.Move(tempFileName, fileName);\n\n            //binding to new file\n            sourceFileLinePositions = newLinePos;\n            fs = new FileStream(fileName, FileMode.Open);\n            this.fileEncoding = enc;\n        }\n\n        private string ReadLine(StreamReader sr, int i)\n        {\n            string line;\n            var filePos = sourceFileLinePositions[i];\n            if (filePos < 0)\n                return \"\";\n            fs.Seek(filePos, SeekOrigin.Begin);\n            sr.DiscardBufferedData();\n            line = sr.ReadLine();\n            return line;\n        }\n\n        public override void ClearIsChanged()\n        {\n            foreach (var line in lines)\n                if (line != null)\n                    line.IsChanged = false;\n        }\n\n        public override Line this[int i]\n        {\n            get\n            {\n                if (base.lines[i] != null)\n                    return lines[i];\n                else\n                    LoadLineFromSourceFile(i);\n\n                return lines[i];\n            }\n            set { throw new NotImplementedException(); }\n        }\n\n        private void LoadLineFromSourceFile(int i)\n        {\n            var line = CreateLine();\n            fs.Seek(sourceFileLinePositions[i], SeekOrigin.Begin);\n            StreamReader sr = new StreamReader(fs, fileEncoding);\n\n            var s = sr.ReadLine();\n            if (s == null)\n                s = \"\";\n\n            //call event handler\n            if (LineNeeded != null)\n            {\n                var args = new LineNeededEventArgs(s, i);\n                LineNeeded(this, args);\n                s = args.DisplayedLineText;\n                if (s == null)\n                    return;\n            }\n\n            foreach (var c in s)\n                line.Add(new Char(c));\n            base.lines[i] = line;\n\n            if (CurrentTB.WordWrap)\n                OnRecalcWordWrap(new TextChangedEventArgs(i, i));\n        }\n\n        public override void InsertLine(int index, Line line)\n        {\n            sourceFileLinePositions.Insert(index, -1);\n            base.InsertLine(index, line);\n        }\n\n        public override void RemoveLine(int index, int count)\n        {\n            sourceFileLinePositions.RemoveRange(index, count);\n            base.RemoveLine(index, count);\n        }\n\n        public override void Clear()\n        {\n            base.Clear();\n        }\n\n        public override int GetLineLength(int i)\n        {\n            if (base.lines[i] == null)\n                return 0;\n            else\n                return base.lines[i].Count;\n        }\n\n        public override bool LineHasFoldingStartMarker(int iLine)\n        {\n            if (lines[iLine] == null)\n                return false;\n            else\n                return !string.IsNullOrEmpty(lines[iLine].FoldingStartMarker);\n        }\n\n        public override bool LineHasFoldingEndMarker(int iLine)\n        {\n            if (lines[iLine] == null)\n                return false;\n            else\n                return !string.IsNullOrEmpty(lines[iLine].FoldingEndMarker);\n        }\n\n        public override void Dispose()\n        {\n            if (fs != null)\n                fs.Dispose();\n\n            timer.Dispose();\n        }\n\n        internal void UnloadLine(int iLine)\n        {\n            if (lines[iLine] != null && !lines[iLine].IsChanged)\n                lines[iLine] = null;\n        }\n    }\n\n    public class LineNeededEventArgs : EventArgs\n    {\n        public string SourceLineText { get; private set; }\n        public int DisplayedLineIndex { get; private set; }\n\n        /// <summary>\n        /// This text will be displayed in textbox\n        /// </summary>\n        public string DisplayedLineText { get; set; }\n\n        public LineNeededEventArgs(string sourceLineText, int displayedLineIndex)\n        {\n            this.SourceLineText = sourceLineText;\n            this.DisplayedLineIndex = displayedLineIndex;\n            this.DisplayedLineText = sourceLineText;\n        }\n    }\n\n    public class LinePushedEventArgs : EventArgs\n    {\n        public string SourceLineText { get; private set; }\n        public int DisplayedLineIndex { get; private set; }\n\n        /// <summary>\n        /// This property contains only changed text.\n        /// If text of line is not changed, this property contains null.\n        /// </summary>\n        public string DisplayedLineText { get; private set; }\n\n        /// <summary>\n        /// This text will be saved in the file\n        /// </summary>\n        public string SavedText { get; set; }\n\n        public LinePushedEventArgs(string sourceLineText, int displayedLineIndex, string displayedLineText)\n        {\n            this.SourceLineText = sourceLineText;\n            this.DisplayedLineIndex = displayedLineIndex;\n            this.DisplayedLineText = displayedLineText;\n            this.SavedText = displayedLineText;\n        }\n    }\n\n    class CharReader : TextReader\n    {\n        public override int Read()\n        {\n            return base.Read();\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/FindForm.Designer.cs",
    "content": "﻿namespace FastColoredTextBoxNS\n{\n    partial class FindForm\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.btClose = new System.Windows.Forms.Button();\n            this.btFindNext = new System.Windows.Forms.Button();\n            this.tbFind = new System.Windows.Forms.TextBox();\n            this.cbRegex = new System.Windows.Forms.CheckBox();\n            this.cbMatchCase = new System.Windows.Forms.CheckBox();\n            this.label1 = new System.Windows.Forms.Label();\n            this.cbWholeWord = new System.Windows.Forms.CheckBox();\n            this.SuspendLayout();\n            // \n            // btClose\n            // \n            this.btClose.Location = new System.Drawing.Point(318, 69);\n            this.btClose.Name = \"btClose\";\n            this.btClose.Size = new System.Drawing.Size(87, 27);\n            this.btClose.TabIndex = 5;\n            this.btClose.Text = \"Close\";\n            this.btClose.UseVisualStyleBackColor = true;\n            this.btClose.Click += new System.EventHandler(this.btClose_Click);\n            // \n            // btFindNext\n            // \n            this.btFindNext.Location = new System.Drawing.Point(225, 69);\n            this.btFindNext.Name = \"btFindNext\";\n            this.btFindNext.Size = new System.Drawing.Size(87, 27);\n            this.btFindNext.TabIndex = 4;\n            this.btFindNext.Text = \"Find next\";\n            this.btFindNext.UseVisualStyleBackColor = true;\n            this.btFindNext.Click += new System.EventHandler(this.btFindNext_Click);\n            // \n            // tbFind\n            // \n            this.tbFind.Location = new System.Drawing.Point(49, 14);\n            this.tbFind.Name = \"tbFind\";\n            this.tbFind.Size = new System.Drawing.Size(356, 23);\n            this.tbFind.TabIndex = 0;\n            this.tbFind.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            this.tbFind.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);\n            // \n            // cbRegex\n            // \n            this.cbRegex.AutoSize = true;\n            this.cbRegex.Location = new System.Drawing.Point(290, 44);\n            this.cbRegex.Name = \"cbRegex\";\n            this.cbRegex.Size = new System.Drawing.Size(57, 19);\n            this.cbRegex.TabIndex = 3;\n            this.cbRegex.Text = \"Regex\";\n            this.cbRegex.UseVisualStyleBackColor = true;\n            this.cbRegex.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            // \n            // cbMatchCase\n            // \n            this.cbMatchCase.AutoSize = true;\n            this.cbMatchCase.Location = new System.Drawing.Point(49, 44);\n            this.cbMatchCase.Name = \"cbMatchCase\";\n            this.cbMatchCase.Size = new System.Drawing.Size(86, 19);\n            this.cbMatchCase.TabIndex = 1;\n            this.cbMatchCase.Text = \"Match case\";\n            this.cbMatchCase.UseVisualStyleBackColor = true;\n            this.cbMatchCase.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            // \n            // label1\n            // \n            this.label1.AutoSize = true;\n            this.label1.Location = new System.Drawing.Point(7, 17);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(36, 15);\n            this.label1.TabIndex = 5;\n            this.label1.Text = \"Find: \";\n            // \n            // cbWholeWord\n            // \n            this.cbWholeWord.AutoSize = true;\n            this.cbWholeWord.Location = new System.Drawing.Point(152, 44);\n            this.cbWholeWord.Name = \"cbWholeWord\";\n            this.cbWholeWord.Size = new System.Drawing.Size(125, 19);\n            this.cbWholeWord.TabIndex = 2;\n            this.cbWholeWord.Text = \"Match whole word\";\n            this.cbWholeWord.UseVisualStyleBackColor = true;\n            this.cbWholeWord.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            // \n            // FindForm\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(420, 107);\n            this.Controls.Add(this.cbWholeWord);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.cbMatchCase);\n            this.Controls.Add(this.cbRegex);\n            this.Controls.Add(this.tbFind);\n            this.Controls.Add(this.btFindNext);\n            this.Controls.Add(this.btClose);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;\n            this.Name = \"FindForm\";\n            this.ShowIcon = false;\n            this.ShowInTaskbar = false;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\n            this.Text = \"Find\";\n            this.TopMost = true;\n            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FindForm_FormClosing);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.Button btClose;\n        private System.Windows.Forms.Button btFindNext;\n        private System.Windows.Forms.CheckBox cbRegex;\n        private System.Windows.Forms.CheckBox cbMatchCase;\n        private System.Windows.Forms.Label label1;\n        private System.Windows.Forms.CheckBox cbWholeWord;\n        public System.Windows.Forms.TextBox tbFind;\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/FindForm.cs",
    "content": "﻿using System;\nusing System.Windows.Forms;\nusing System.Text.RegularExpressions;\nusing System.Collections.Generic;\n\nnamespace FastColoredTextBoxNS\n{\n    public partial class FindForm : Form\n    {\n        bool firstSearch = true;\n        Place startPlace;\n        FastColoredTextBox tb;\n\n        public FindForm(FastColoredTextBox tb)\n        {\n            InitializeComponent();\n            this.tb = tb;\n        }\n\n        private void btClose_Click(object sender, EventArgs e)\n        {\n            Close();\n        }\n\n        private void btFindNext_Click(object sender, EventArgs e)\n        {\n            FindNext(tbFind.Text);\n        }\n\n        public virtual void FindNext(string pattern)\n        {\n            try\n            {\n                RegexOptions opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;\n                if (!cbRegex.Checked)\n                    pattern = Regex.Escape(pattern);\n                if (cbWholeWord.Checked)\n                    pattern = \"\\\\b\" + pattern + \"\\\\b\";\n                //\n                Range range = tb.Selection.Clone();\n                range.Normalize();\n                //\n                if (firstSearch)\n                {\n                    startPlace = range.Start;\n                    firstSearch = false;\n                }\n\n                //\n                range.Start = range.End;\n                if (range.Start >= startPlace)\n                    range.End = new Place(tb.GetLineLength(tb.LinesCount - 1), tb.LinesCount - 1);\n                else\n                    range.End = startPlace;\n                //\n                foreach (var r in range.GetRangesByLines(pattern, opt))\n                {\n                    tb.Selection = r;\n                    tb.DoSelectionVisible();\n                    tb.Invalidate();\n                    return;\n                }\n\n                //\n                if (range.Start >= startPlace && startPlace > Place.Empty)\n                {\n                    tb.Selection.Start = new Place(0, 0);\n                    FindNext(pattern);\n                    return;\n                }\n\n                MessageBox.Show(\"Not found\");\n            }\n            catch (Exception ex)\n            {\n                MessageBox.Show(ex.Message);\n            }\n        }\n\n        private void tbFind_KeyPress(object sender, KeyPressEventArgs e)\n        {\n            if (e.KeyChar == '\\r')\n            {\n                btFindNext.PerformClick();\n                e.Handled = true;\n                return;\n            }\n\n            if (e.KeyChar == '\\x1b')\n            {\n                Hide();\n                e.Handled = true;\n                return;\n            }\n        }\n\n        private void FindForm_FormClosing(object sender, FormClosingEventArgs e)\n        {\n            if (e.CloseReason == CloseReason.UserClosing)\n            {\n                e.Cancel = true;\n                Hide();\n            }\n\n            this.tb.Focus();\n        }\n\n        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)\n        {\n            if (keyData == Keys.Escape)\n            {\n                this.Close();\n                return true;\n            }\n\n            return base.ProcessCmdKey(ref msg, keyData);\n        }\n\n        protected override void OnActivated(EventArgs e)\n        {\n            tbFind.Focus();\n            ResetSerach();\n        }\n\n        void ResetSerach()\n        {\n            firstSearch = true;\n        }\n\n        private void cbMatchCase_CheckedChanged(object sender, EventArgs e)\n        {\n            ResetSerach();\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/FindForm.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "FastColoredTextBox/GoToForm.Designer.cs",
    "content": "﻿namespace FastColoredTextBoxNS\n{\n    partial class GoToForm\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.label = new System.Windows.Forms.Label();\n            this.tbLineNumber = new System.Windows.Forms.TextBox();\n            this.btnOk = new System.Windows.Forms.Button();\n            this.btnCancel = new System.Windows.Forms.Button();\n            this.SuspendLayout();\n            // \n            // label\n            // \n            this.label.AutoSize = true;\n            this.label.Location = new System.Drawing.Point(14, 10);\n            this.label.Name = \"label\";\n            this.label.Size = new System.Drawing.Size(107, 15);\n            this.label.TabIndex = 0;\n            this.label.Text = \"Line Number (1/1):\";\n            // \n            // tbLineNumber\n            // \n            this.tbLineNumber.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.tbLineNumber.Location = new System.Drawing.Point(14, 33);\n            this.tbLineNumber.Name = \"tbLineNumber\";\n            this.tbLineNumber.Size = new System.Drawing.Size(199, 23);\n            this.tbLineNumber.TabIndex = 1;\n            // \n            // btnOk\n            // \n            this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;\n            this.btnOk.Location = new System.Drawing.Point(14, 62);\n            this.btnOk.Name = \"btnOk\";\n            this.btnOk.Size = new System.Drawing.Size(87, 27);\n            this.btnOk.TabIndex = 2;\n            this.btnOk.Text = \"OK\";\n            this.btnOk.UseVisualStyleBackColor = true;\n            this.btnOk.Click += new System.EventHandler(this.btnOk_Click);\n            // \n            // btnCancel\n            // \n            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\n            this.btnCancel.Location = new System.Drawing.Point(125, 62);\n            this.btnCancel.Name = \"btnCancel\";\n            this.btnCancel.Size = new System.Drawing.Size(87, 27);\n            this.btnCancel.TabIndex = 3;\n            this.btnCancel.Text = \"Cancel\";\n            this.btnCancel.UseVisualStyleBackColor = true;\n            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);\n            // \n            // GoToForm\n            // \n            this.AcceptButton = this.btnOk;\n            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.CancelButton = this.btnCancel;\n            this.ClientSize = new System.Drawing.Size(225, 105);\n            this.Controls.Add(this.btnCancel);\n            this.Controls.Add(this.btnOk);\n            this.Controls.Add(this.tbLineNumber);\n            this.Controls.Add(this.label);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;\n            this.MaximizeBox = false;\n            this.MinimizeBox = false;\n            this.Name = \"GoToForm\";\n            this.ShowIcon = false;\n            this.ShowInTaskbar = false;\n            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\n            this.Text = \"Go To Line\";\n            this.TopMost = true;\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.Label label;\n        private System.Windows.Forms.TextBox tbLineNumber;\n        private System.Windows.Forms.Button btnOk;\n        private System.Windows.Forms.Button btnCancel;\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/GoToForm.cs",
    "content": "﻿using System;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    public partial class GoToForm : Form\n    {\n        public int SelectedLineNumber { get; set; }\n        public int TotalLineCount { get; set; }\n\n        public GoToForm()\n        {\n            InitializeComponent();\n        }\n\n        protected override void OnLoad(EventArgs e)\n        {\n            base.OnLoad(e);\n\n            this.tbLineNumber.Text = this.SelectedLineNumber.ToString();\n\n            this.label.Text = String.Format(\"Line number (1 - {0}):\", this.TotalLineCount);\n        }\n\n        protected override void OnShown(EventArgs e)\n        {\n            base.OnShown(e);\n\n            this.tbLineNumber.Focus();\n        }\n\n        private void btnOk_Click(object sender, EventArgs e)\n        {\n            int enteredLine;\n            if (int.TryParse(this.tbLineNumber.Text, out enteredLine))\n            {\n                enteredLine = Math.Min(enteredLine, this.TotalLineCount);\n                enteredLine = Math.Max(1, enteredLine);\n\n                this.SelectedLineNumber = enteredLine;\n            }\n\n            this.DialogResult = DialogResult.OK;\n            this.Close();\n        }\n\n        private void btnCancel_Click(object sender, EventArgs e)\n        {\n            this.DialogResult = DialogResult.Cancel;\n            this.Close();\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/GoToForm.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "FastColoredTextBox/Hints.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Collection of Hints.\n    /// This is temporary buffer for currently displayed hints.\n    /// </summary>\n    public class Hints : ICollection<Hint>, IDisposable\n    {\n        FastColoredTextBox tb;\n        List<Hint> items = new List<Hint>();\n\n        public Hints(FastColoredTextBox tb)\n        {\n            this.tb = tb;\n            tb.TextChanged += OnTextBoxTextChanged;\n            tb.KeyDown += OnTextBoxKeyDown;\n            tb.VisibleRangeChanged += OnTextBoxVisibleRangeChanged;\n        }\n\n        protected virtual void OnTextBoxKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)\n        {\n            if (e.KeyCode == System.Windows.Forms.Keys.Escape && e.Modifiers == System.Windows.Forms.Keys.None)\n                Clear();\n        }\n\n        protected virtual void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)\n        {\n            Clear();\n        }\n\n        public void Dispose()\n        {\n            tb.TextChanged -= OnTextBoxTextChanged;\n            tb.KeyDown -= OnTextBoxKeyDown;\n            tb.VisibleRangeChanged -= OnTextBoxVisibleRangeChanged;\n        }\n\n        void OnTextBoxVisibleRangeChanged(object sender, EventArgs e)\n        {\n            if (items.Count == 0)\n                return;\n\n            tb.NeedRecalc(true);\n            foreach (var item in items)\n            {\n                LayoutHint(item);\n                item.HostPanel.Invalidate();\n            }\n        }\n\n        private void LayoutHint(Hint hint)\n        {\n            if (hint.Inline)\n            {\n                if (hint.Range.Start.iLine < tb.LineInfos.Count - 1)\n                    hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - hint.TopPadding -\n                                         hint.HostPanel.Height - tb.VerticalScroll.Value;\n                else\n                    hint.HostPanel.Top = tb.TextHeight + tb.Paddings.Top - hint.HostPanel.Height -\n                                         tb.VerticalScroll.Value;\n            }\n            else\n            {\n                if (hint.Range.Start.iLine > tb.LinesCount - 1) return;\n                if (hint.Range.Start.iLine == tb.LinesCount - 1)\n                {\n                    var y = tb.LineInfos[hint.Range.Start.iLine].startY - tb.VerticalScroll.Value + tb.CharHeight;\n\n                    if (y + hint.HostPanel.Height + 1 > tb.ClientRectangle.Bottom)\n                    {\n                        hint.HostPanel.Top = Math.Max(0,\n                            tb.LineInfos[hint.Range.Start.iLine].startY - tb.VerticalScroll.Value -\n                            hint.HostPanel.Height);\n                    }\n                    else\n                        hint.HostPanel.Top = y;\n                }\n                else\n                {\n                    hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - tb.VerticalScroll.Value;\n                    if (hint.HostPanel.Bottom > tb.ClientRectangle.Bottom)\n                        hint.HostPanel.Top = tb.LineInfos[hint.Range.Start.iLine + 1].startY - tb.CharHeight -\n                                             hint.TopPadding - hint.HostPanel.Height - tb.VerticalScroll.Value;\n                }\n            }\n\n            if (hint.Dock == DockStyle.Fill)\n            {\n                hint.Width = tb.ClientSize.Width - tb.LeftIndent - 2;\n                hint.HostPanel.Left = tb.LeftIndent;\n            }\n            else\n            {\n                var p1 = tb.PlaceToPoint(hint.Range.Start);\n                var p2 = tb.PlaceToPoint(hint.Range.End);\n                var cx = (p1.X + p2.X) / 2;\n                var x = cx - hint.HostPanel.Width / 2;\n                hint.HostPanel.Left = Math.Max(tb.LeftIndent, x);\n                if (hint.HostPanel.Right > tb.ClientSize.Width)\n                    hint.HostPanel.Left = Math.Max(tb.LeftIndent, x - (hint.HostPanel.Right - tb.ClientSize.Width));\n            }\n        }\n\n        public IEnumerator<Hint> GetEnumerator()\n        {\n            foreach (var item in items)\n                yield return item;\n        }\n\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        /// <summary>\n        /// Clears all displayed hints\n        /// </summary>\n        public void Clear()\n        {\n            items.Clear();\n            if (tb.Controls.Count != 0)\n            {\n                var toDelete = new List<Control>();\n                foreach (Control item in tb.Controls)\n                    if (item is UnfocusablePanel)\n                        toDelete.Add(item);\n\n                foreach (var item in toDelete)\n                    tb.Controls.Remove(item);\n\n                for (int i = 0; i < tb.LineInfos.Count; i++)\n                {\n                    var li = tb.LineInfos[i];\n                    li.bottomPadding = 0;\n                    tb.LineInfos[i] = li;\n                }\n\n                tb.NeedRecalc();\n                tb.Invalidate();\n                tb.Select();\n                tb.ActiveControl = null;\n            }\n        }\n\n        /// <summary>\n        /// Add and shows the hint\n        /// </summary>\n        /// <param name=\"hint\"></param>\n        public void Add(Hint hint)\n        {\n            items.Add(hint);\n\n            if (hint.Inline /* || hint.Range.Start.iLine >= tb.LinesCount - 1*/)\n            {\n                var li = tb.LineInfos[hint.Range.Start.iLine];\n                hint.TopPadding = li.bottomPadding;\n                li.bottomPadding += hint.HostPanel.Height;\n                tb.LineInfos[hint.Range.Start.iLine] = li;\n                tb.NeedRecalc(true);\n            }\n\n            LayoutHint(hint);\n\n            tb.OnVisibleRangeChanged();\n\n            hint.HostPanel.Parent = tb;\n\n            tb.Select();\n            tb.ActiveControl = null;\n            tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Is collection contains the hint?\n        /// </summary>\n        public bool Contains(Hint item)\n        {\n            return items.Contains(item);\n        }\n\n        public void CopyTo(Hint[] array, int arrayIndex)\n        {\n            items.CopyTo(array, arrayIndex);\n        }\n\n        /// <summary>\n        /// Count of hints\n        /// </summary>\n        public int Count\n        {\n            get { return items.Count; }\n        }\n\n        public bool IsReadOnly\n        {\n            get { return false; }\n        }\n\n        public bool Remove(Hint item)\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n    /// <summary>\n    /// Hint of FastColoredTextbox\n    /// </summary>\n    public class Hint\n    {\n        /// <summary>\n        /// Text of simple hint\n        /// </summary>\n        public string Text\n        {\n            get { return HostPanel.Text; }\n            set { HostPanel.Text = value; }\n        }\n\n        /// <summary>\n        /// Linked range\n        /// </summary>\n        public Range Range { get; set; }\n\n        /// <summary>\n        /// Backcolor\n        /// </summary>\n        public Color BackColor\n        {\n            get { return HostPanel.BackColor; }\n            set { HostPanel.BackColor = value; }\n        }\n\n        /// <summary>\n        /// Second backcolor\n        /// </summary>\n        public Color BackColor2\n        {\n            get { return HostPanel.BackColor2; }\n            set { HostPanel.BackColor2 = value; }\n        }\n\n        /// <summary>\n        /// Border color\n        /// </summary>\n        public Color BorderColor\n        {\n            get { return HostPanel.BorderColor; }\n            set { HostPanel.BorderColor = value; }\n        }\n\n        /// <summary>\n        /// Fore color\n        /// </summary>\n        public Color ForeColor\n        {\n            get { return HostPanel.ForeColor; }\n            set { HostPanel.ForeColor = value; }\n        }\n\n        /// <summary>\n        /// Text alignment\n        /// </summary>\n        public StringAlignment TextAlignment\n        {\n            get { return HostPanel.TextAlignment; }\n            set { HostPanel.TextAlignment = value; }\n        }\n\n        /// <summary>\n        /// Font\n        /// </summary>\n        public Font Font\n        {\n            get { return HostPanel.Font; }\n            set { HostPanel.Font = value; }\n        }\n\n        /// <summary>\n        /// Occurs when user click on simple hint\n        /// </summary>\n        public event EventHandler Click\n        {\n            add { HostPanel.Click += value; }\n            remove { HostPanel.Click -= value; }\n        }\n\n        /// <summary>\n        /// Inner control\n        /// </summary>\n        public Control InnerControl { get; set; }\n\n        /// <summary>\n        /// Docking (allows None and Fill only)\n        /// </summary>\n        public DockStyle Dock { get; set; }\n\n        /// <summary>\n        /// Width of hint (if Dock is None)\n        /// </summary>\n        public int Width\n        {\n            get { return HostPanel.Width; }\n            set { HostPanel.Width = value; }\n        }\n\n        /// <summary>\n        /// Height of hint\n        /// </summary>\n        public int Height\n        {\n            get { return HostPanel.Height; }\n            set { HostPanel.Height = value; }\n        }\n\n        /// <summary>\n        /// Host panel\n        /// </summary>\n        public UnfocusablePanel HostPanel { get; private set; }\n\n        internal int TopPadding { get; set; }\n\n        /// <summary>\n        /// Tag\n        /// </summary>\n        public object Tag { get; set; }\n\n        /// <summary>\n        /// Cursor\n        /// </summary>\n        public Cursor Cursor\n        {\n            get { return HostPanel.Cursor; }\n            set { HostPanel.Cursor = value; }\n        }\n\n        /// <summary>\n        /// Inlining. If True then hint will moves apart text.\n        /// </summary>\n        public bool Inline { get; set; }\n\n        /// <summary>\n        /// Scroll textbox to the hint\n        /// </summary>\n        public virtual void DoVisible()\n        {\n            Range.tb.DoRangeVisible(Range, true);\n            Range.tb.DoVisibleRectangle(HostPanel.Bounds);\n\n            Range.tb.Invalidate();\n        }\n\n        private Hint(Range range, Control innerControl, string text, bool inline, bool dock)\n        {\n            this.Range = range;\n            this.Inline = inline;\n            this.InnerControl = innerControl;\n\n            Init();\n\n            Dock = dock ? DockStyle.Fill : DockStyle.None;\n            Text = text;\n        }\n\n        /// <summary>\n        /// Creates Hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"text\">Text for simple hint</param>\n        /// <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n        /// <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        public Hint(Range range, string text, bool inline, bool dock)\n            : this(range, null, text, inline, dock)\n        {\n        }\n\n        /// <summary>\n        /// Creates Hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"text\">Text for simple hint</param>\n        public Hint(Range range, string text)\n            : this(range, null, text, true, true)\n        {\n        }\n\n        /// <summary>\n        /// Creates Hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"innerControl\">Inner control</param>\n        /// <param name=\"inline\">Inlining. If True then hint will moves apart text</param>\n        /// <param name=\"dock\">Docking. If True then hint will fill whole line</param>\n        public Hint(Range range, Control innerControl, bool inline, bool dock)\n            : this(range, innerControl, null, inline, dock)\n        {\n        }\n\n        /// <summary>\n        /// Creates Hint\n        /// </summary>\n        /// <param name=\"range\">Linked range</param>\n        /// <param name=\"innerControl\">Inner control</param>\n        public Hint(Range range, Control innerControl)\n            : this(range, innerControl, null, true, true)\n        {\n        }\n\n        protected virtual void Init()\n        {\n            HostPanel = new UnfocusablePanel();\n            HostPanel.Click += OnClick;\n\n            Cursor = Cursors.Default;\n            BorderColor = Color.Silver;\n            BackColor2 = Color.White;\n            BackColor = InnerControl == null ? Color.Silver : SystemColors.Control;\n            ForeColor = Color.Black;\n            TextAlignment = StringAlignment.Near;\n            Font = Range.tb.Parent == null ? Range.tb.Font : Range.tb.Parent.Font;\n\n            if (InnerControl != null)\n            {\n                HostPanel.Controls.Add(InnerControl);\n                var size = InnerControl.GetPreferredSize(InnerControl.Size);\n                HostPanel.Width = size.Width + 2;\n                HostPanel.Height = size.Height + 2;\n                InnerControl.Dock = DockStyle.Fill;\n                InnerControl.Visible = true;\n                BackColor = SystemColors.Control;\n            }\n            else\n            {\n                HostPanel.Height = Range.tb.CharHeight + 5;\n            }\n        }\n\n        protected virtual void OnClick(object sender, EventArgs e)\n        {\n            Range.tb.OnHintClick(this);\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Hotkeys.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.ComponentModel.Design;\nusing System.Drawing;\nusing System.Drawing.Design;\nusing System.Globalization;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading;\nusing System.Windows.Forms;\nusing System.Windows.Forms.Design;\nusing KEYS = System.Windows.Forms.Keys;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Dictionary of shortcuts for FCTB\n    /// </summary>\n    public class HotkeysMapping : SortedDictionary<Keys, FCTBAction>\n    {\n        public virtual void InitDefault()\n        {\n            this[KEYS.Control | KEYS.G] = FCTBAction.GoToDialog;\n            this[KEYS.Control | KEYS.F] = FCTBAction.FindDialog;\n            this[KEYS.Alt | KEYS.F] = FCTBAction.FindChar;\n            this[KEYS.F3] = FCTBAction.FindNext;\n            this[KEYS.Control | KEYS.H] = FCTBAction.ReplaceDialog;\n            this[KEYS.Control | KEYS.C] = FCTBAction.Copy;\n            this[KEYS.Control | KEYS.Shift | KEYS.C] = FCTBAction.CommentSelected;\n            this[KEYS.Control | KEYS.X] = FCTBAction.Cut;\n            this[KEYS.Control | KEYS.V] = FCTBAction.Paste;\n            this[KEYS.Control | KEYS.A] = FCTBAction.SelectAll;\n            this[KEYS.Control | KEYS.Z] = FCTBAction.Undo;\n            this[KEYS.Control | KEYS.R] = FCTBAction.Redo;\n            this[KEYS.Control | KEYS.U] = FCTBAction.UpperCase;\n            this[KEYS.Shift | KEYS.Control | KEYS.U] = FCTBAction.LowerCase;\n            this[KEYS.Control | KEYS.OemMinus] = FCTBAction.NavigateBackward;\n            this[KEYS.Control | KEYS.Shift | KEYS.OemMinus] = FCTBAction.NavigateForward;\n            this[KEYS.Control | KEYS.B] = FCTBAction.BookmarkLine;\n            this[KEYS.Control | KEYS.Shift | KEYS.B] = FCTBAction.UnbookmarkLine;\n            this[KEYS.Control | KEYS.N] = FCTBAction.GoNextBookmark;\n            this[KEYS.Control | KEYS.Shift | KEYS.N] = FCTBAction.GoPrevBookmark;\n            this[KEYS.Alt | KEYS.Back] = FCTBAction.Undo;\n            this[KEYS.Control | KEYS.Back] = FCTBAction.ClearWordLeft;\n            this[KEYS.Insert] = FCTBAction.ReplaceMode;\n            this[KEYS.Control | KEYS.Insert] = FCTBAction.Copy;\n            this[KEYS.Shift | KEYS.Insert] = FCTBAction.Paste;\n            this[KEYS.Delete] = FCTBAction.DeleteCharRight;\n            this[KEYS.Control | KEYS.Delete] = FCTBAction.ClearWordRight;\n            this[KEYS.Shift | KEYS.Delete] = FCTBAction.Cut;\n            this[KEYS.Left] = FCTBAction.GoLeft;\n            this[KEYS.Shift | KEYS.Left] = FCTBAction.GoLeftWithSelection;\n            this[KEYS.Control | KEYS.Left] = FCTBAction.GoWordLeft;\n            this[KEYS.Control | KEYS.Shift | KEYS.Left] = FCTBAction.GoWordLeftWithSelection;\n            this[KEYS.Alt | KEYS.Shift | KEYS.Left] = FCTBAction.GoLeft_ColumnSelectionMode;\n            this[KEYS.Right] = FCTBAction.GoRight;\n            this[KEYS.Shift | KEYS.Right] = FCTBAction.GoRightWithSelection;\n            this[KEYS.Control | KEYS.Right] = FCTBAction.GoWordRight;\n            this[KEYS.Control | KEYS.Shift | KEYS.Right] = FCTBAction.GoWordRightWithSelection;\n            this[KEYS.Alt | KEYS.Shift | KEYS.Right] = FCTBAction.GoRight_ColumnSelectionMode;\n            this[KEYS.Up] = FCTBAction.GoUp;\n            this[KEYS.Shift | KEYS.Up] = FCTBAction.GoUpWithSelection;\n            this[KEYS.Alt | KEYS.Shift | KEYS.Up] = FCTBAction.GoUp_ColumnSelectionMode;\n            this[KEYS.Alt | KEYS.Up] = FCTBAction.MoveSelectedLinesUp;\n            this[KEYS.Control | KEYS.Up] = FCTBAction.ScrollUp;\n            this[KEYS.Down] = FCTBAction.GoDown;\n            this[KEYS.Shift | KEYS.Down] = FCTBAction.GoDownWithSelection;\n            this[KEYS.Alt | KEYS.Shift | KEYS.Down] = FCTBAction.GoDown_ColumnSelectionMode;\n            this[KEYS.Alt | KEYS.Down] = FCTBAction.MoveSelectedLinesDown;\n            this[KEYS.Control | KEYS.Down] = FCTBAction.ScrollDown;\n            this[KEYS.PageUp] = FCTBAction.GoPageUp;\n            this[KEYS.Shift | KEYS.PageUp] = FCTBAction.GoPageUpWithSelection;\n            this[KEYS.PageDown] = FCTBAction.GoPageDown;\n            this[KEYS.Shift | KEYS.PageDown] = FCTBAction.GoPageDownWithSelection;\n            this[KEYS.Home] = FCTBAction.GoHome;\n            this[KEYS.Shift | KEYS.Home] = FCTBAction.GoHomeWithSelection;\n            this[KEYS.Control | KEYS.Home] = FCTBAction.GoFirstLine;\n            this[KEYS.Control | KEYS.Shift | KEYS.Home] = FCTBAction.GoFirstLineWithSelection;\n            this[KEYS.End] = FCTBAction.GoEnd;\n            this[KEYS.Shift | KEYS.End] = FCTBAction.GoEndWithSelection;\n            this[KEYS.Control | KEYS.End] = FCTBAction.GoLastLine;\n            this[KEYS.Control | KEYS.Shift | KEYS.End] = FCTBAction.GoLastLineWithSelection;\n            this[KEYS.Escape] = FCTBAction.ClearHints;\n            this[KEYS.Control | KEYS.M] = FCTBAction.MacroRecord;\n            this[KEYS.Control | KEYS.E] = FCTBAction.MacroExecute;\n            this[KEYS.Control | KEYS.Space] = FCTBAction.AutocompleteMenu;\n            this[KEYS.Tab] = FCTBAction.IndentIncrease;\n            this[KEYS.Shift | KEYS.Tab] = FCTBAction.IndentDecrease;\n            this[KEYS.Control | KEYS.Subtract] = FCTBAction.ZoomOut;\n            this[KEYS.Control | KEYS.Add] = FCTBAction.ZoomIn;\n            this[KEYS.Control | KEYS.D0] = FCTBAction.ZoomNormal;\n            this[KEYS.Control | KEYS.I] = FCTBAction.AutoIndentChars;\n        }\n\n        public override string ToString()\n        {\n            var cult = Thread.CurrentThread.CurrentUICulture;\n            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;\n            StringBuilder sb = new StringBuilder();\n            var kc = new KeysConverter();\n            foreach (var pair in this)\n            {\n                sb.AppendFormat(\"{0}={1}, \", kc.ConvertToString(pair.Key), pair.Value);\n            }\n\n            if (sb.Length > 1)\n                sb.Remove(sb.Length - 2, 2);\n            Thread.CurrentThread.CurrentUICulture = cult;\n\n            return sb.ToString();\n        }\n\n        public static HotkeysMapping Parse(string s)\n        {\n            var result = new HotkeysMapping();\n            result.Clear();\n            var cult = Thread.CurrentThread.CurrentUICulture;\n            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;\n\n            var kc = new KeysConverter();\n\n            foreach (var p in s.Split(','))\n            {\n                var pp = p.Split('=');\n                var k = (Keys) kc.ConvertFromString(pp[0].Trim());\n                var a = (FCTBAction) Enum.Parse(typeof(FCTBAction), pp[1].Trim());\n                result[k] = a;\n            }\n\n            Thread.CurrentThread.CurrentUICulture = cult;\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Actions for shortcuts\n    /// </summary>\n    public enum FCTBAction\n    {\n        None,\n        AutocompleteMenu,\n        AutoIndentChars,\n        BookmarkLine,\n        ClearHints,\n        ClearWordLeft,\n        ClearWordRight,\n        CommentSelected,\n        Copy,\n        Cut,\n        DeleteCharRight,\n        FindChar,\n        FindDialog,\n        FindNext,\n        GoDown,\n        GoDownWithSelection,\n        GoDown_ColumnSelectionMode,\n        GoEnd,\n        GoEndWithSelection,\n        GoFirstLine,\n        GoFirstLineWithSelection,\n        GoHome,\n        GoHomeWithSelection,\n        GoLastLine,\n        GoLastLineWithSelection,\n        GoLeft,\n        GoLeftWithSelection,\n        GoLeft_ColumnSelectionMode,\n        GoPageDown,\n        GoPageDownWithSelection,\n        GoPageUp,\n        GoPageUpWithSelection,\n        GoRight,\n        GoRightWithSelection,\n        GoRight_ColumnSelectionMode,\n        GoToDialog,\n        GoNextBookmark,\n        GoPrevBookmark,\n        GoUp,\n        GoUpWithSelection,\n        GoUp_ColumnSelectionMode,\n        GoWordLeft,\n        GoWordLeftWithSelection,\n        GoWordRight,\n        GoWordRightWithSelection,\n        IndentIncrease,\n        IndentDecrease,\n        LowerCase,\n        MacroExecute,\n        MacroRecord,\n        MoveSelectedLinesDown,\n        MoveSelectedLinesUp,\n        NavigateBackward,\n        NavigateForward,\n        Paste,\n        Redo,\n        ReplaceDialog,\n        ReplaceMode,\n        ScrollDown,\n        ScrollUp,\n        SelectAll,\n        UnbookmarkLine,\n        Undo,\n        UpperCase,\n        ZoomIn,\n        ZoomNormal,\n        ZoomOut,\n        CustomAction1,\n        CustomAction2,\n        CustomAction3,\n        CustomAction4,\n        CustomAction5,\n        CustomAction6,\n        CustomAction7,\n        CustomAction8,\n        CustomAction9,\n        CustomAction10,\n        CustomAction11,\n        CustomAction12,\n        CustomAction13,\n        CustomAction14,\n        CustomAction15,\n        CustomAction16,\n        CustomAction17,\n        CustomAction18,\n        CustomAction19,\n        CustomAction20\n    }\n\n    internal class HotkeysEditor : UITypeEditor\n    {\n        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)\n        {\n            return UITypeEditorEditStyle.Modal;\n        }\n\n        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)\n        {\n            if ((provider != null) &&\n                (((IWindowsFormsEditorService) provider.GetService(typeof(IWindowsFormsEditorService))) != null))\n            {\n                var form = new HotkeysEditorForm(HotkeysMapping.Parse(value as string));\n\n                if (form.ShowDialog() == DialogResult.OK)\n                    value = form.GetHotkeys().ToString();\n            }\n\n            return value;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/HotkeysEditorForm.Designer.cs",
    "content": "﻿namespace FastColoredTextBoxNS\n{\n    partial class HotkeysEditorForm\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();\n            this.dgv = new System.Windows.Forms.DataGridView();\n            this.cbModifiers = new System.Windows.Forms.DataGridViewComboBoxColumn();\n            this.cbKey = new System.Windows.Forms.DataGridViewComboBoxColumn();\n            this.cbAction = new System.Windows.Forms.DataGridViewComboBoxColumn();\n            this.btAdd = new System.Windows.Forms.Button();\n            this.btRemove = new System.Windows.Forms.Button();\n            this.btCancel = new System.Windows.Forms.Button();\n            this.btOk = new System.Windows.Forms.Button();\n            this.label1 = new System.Windows.Forms.Label();\n            this.btResore = new System.Windows.Forms.Button();\n            ((System.ComponentModel.ISupportInitialize)(this.dgv)).BeginInit();\n            this.SuspendLayout();\n            // \n            // dgv\n            // \n            this.dgv.AllowUserToAddRows = false;\n            this.dgv.AllowUserToDeleteRows = false;\n            this.dgv.AllowUserToResizeColumns = false;\n            this.dgv.AllowUserToResizeRows = false;\n            this.dgv.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.dgv.BackgroundColor = System.Drawing.SystemColors.Control;\n            this.dgv.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;\n            this.dgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {\n            this.cbModifiers,\n            this.cbKey,\n            this.cbAction});\n            dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;\n            dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;\n            dataGridViewCellStyle1.Font = new System.Drawing.Font(\"Microsoft Sans Serif\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));\n            dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;\n            dataGridViewCellStyle1.SelectionBackColor = System.Drawing.Color.LightSteelBlue;\n            dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;\n            dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.False;\n            this.dgv.DefaultCellStyle = dataGridViewCellStyle1;\n            this.dgv.GridColor = System.Drawing.SystemColors.Control;\n            this.dgv.Location = new System.Drawing.Point(12, 28);\n            this.dgv.Name = \"dgv\";\n            this.dgv.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;\n            this.dgv.RowHeadersVisible = false;\n            this.dgv.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;\n            this.dgv.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;\n            this.dgv.Size = new System.Drawing.Size(525, 278);\n            this.dgv.TabIndex = 0;\n            this.dgv.RowsAdded += new System.Windows.Forms.DataGridViewRowsAddedEventHandler(this.dgv_RowsAdded);\n            // \n            // cbModifiers\n            // \n            this.cbModifiers.DataPropertyName = \"Modifiers\";\n            this.cbModifiers.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;\n            this.cbModifiers.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.cbModifiers.HeaderText = \"Modifiers\";\n            this.cbModifiers.Name = \"cbModifiers\";\n            // \n            // cbKey\n            // \n            this.cbKey.DataPropertyName = \"Key\";\n            this.cbKey.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;\n            this.cbKey.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.cbKey.HeaderText = \"Key\";\n            this.cbKey.Name = \"cbKey\";\n            this.cbKey.Resizable = System.Windows.Forms.DataGridViewTriState.True;\n            this.cbKey.Width = 120;\n            // \n            // cbAction\n            // \n            this.cbAction.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;\n            this.cbAction.DataPropertyName = \"Action\";\n            this.cbAction.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;\n            this.cbAction.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.cbAction.HeaderText = \"Action\";\n            this.cbAction.Name = \"cbAction\";\n            // \n            // btAdd\n            // \n            this.btAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.btAdd.Location = new System.Drawing.Point(13, 322);\n            this.btAdd.Name = \"btAdd\";\n            this.btAdd.Size = new System.Drawing.Size(75, 23);\n            this.btAdd.TabIndex = 1;\n            this.btAdd.Text = \"Add\";\n            this.btAdd.UseVisualStyleBackColor = true;\n            this.btAdd.Click += new System.EventHandler(this.btAdd_Click);\n            // \n            // btRemove\n            // \n            this.btRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.btRemove.Location = new System.Drawing.Point(103, 322);\n            this.btRemove.Name = \"btRemove\";\n            this.btRemove.Size = new System.Drawing.Size(75, 23);\n            this.btRemove.TabIndex = 2;\n            this.btRemove.Text = \"Remove\";\n            this.btRemove.UseVisualStyleBackColor = true;\n            this.btRemove.Click += new System.EventHandler(this.btRemove_Click);\n            // \n            // btCancel\n            // \n            this.btCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.btCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\n            this.btCancel.Location = new System.Drawing.Point(460, 322);\n            this.btCancel.Name = \"btCancel\";\n            this.btCancel.Size = new System.Drawing.Size(75, 23);\n            this.btCancel.TabIndex = 4;\n            this.btCancel.Text = \"Cancel\";\n            this.btCancel.UseVisualStyleBackColor = true;\n            // \n            // btOk\n            // \n            this.btOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.btOk.DialogResult = System.Windows.Forms.DialogResult.OK;\n            this.btOk.Location = new System.Drawing.Point(379, 322);\n            this.btOk.Name = \"btOk\";\n            this.btOk.Size = new System.Drawing.Size(75, 23);\n            this.btOk.TabIndex = 3;\n            this.btOk.Text = \"OK\";\n            this.btOk.UseVisualStyleBackColor = true;\n            // \n            // label1\n            // \n            this.label1.AutoSize = true;\n            this.label1.Font = new System.Drawing.Font(\"Microsoft Sans Serif\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));\n            this.label1.Location = new System.Drawing.Point(12, 9);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(114, 16);\n            this.label1.TabIndex = 5;\n            this.label1.Text = \"Hotkeys mapping\";\n            // \n            // btResore\n            // \n            this.btResore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.btResore.Location = new System.Drawing.Point(194, 322);\n            this.btResore.Name = \"btResore\";\n            this.btResore.Size = new System.Drawing.Size(105, 23);\n            this.btResore.TabIndex = 6;\n            this.btResore.Text = \"Restore default\";\n            this.btResore.UseVisualStyleBackColor = true;\n            this.btResore.Click += new System.EventHandler(this.btResore_Click);\n            // \n            // HotkeysEditorForm\n            // \n            this.AcceptButton = this.btOk;\n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.CancelButton = this.btCancel;\n            this.ClientSize = new System.Drawing.Size(549, 357);\n            this.Controls.Add(this.btResore);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.btCancel);\n            this.Controls.Add(this.btOk);\n            this.Controls.Add(this.btRemove);\n            this.Controls.Add(this.btAdd);\n            this.Controls.Add(this.dgv);\n            this.MaximumSize = new System.Drawing.Size(565, 700);\n            this.MinimumSize = new System.Drawing.Size(565, 395);\n            this.Name = \"HotkeysEditorForm\";\n            this.ShowIcon = false;\n            this.Text = \"Hotkeys Editor\";\n            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HotkeysEditorForm_FormClosing);\n            ((System.ComponentModel.ISupportInitialize)(this.dgv)).EndInit();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.DataGridView dgv;\n        private System.Windows.Forms.Button btAdd;\n        private System.Windows.Forms.Button btRemove;\n        private System.Windows.Forms.Button btCancel;\n        private System.Windows.Forms.Button btOk;\n        private System.Windows.Forms.Label label1;\n        private System.Windows.Forms.Button btResore;\n        private System.Windows.Forms.DataGridViewComboBoxColumn cbModifiers;\n        private System.Windows.Forms.DataGridViewComboBoxColumn cbKey;\n        private System.Windows.Forms.DataGridViewComboBoxColumn cbAction;\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/HotkeysEditorForm.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    public partial class HotkeysEditorForm : Form\n    {\n        BindingList<HotkeyWrapper> wrappers = new BindingList<HotkeyWrapper>();\n\n        public HotkeysEditorForm(HotkeysMapping hotkeys)\n        {\n            InitializeComponent();\n            BuildWrappers(hotkeys);\n            dgv.DataSource = wrappers;\n        }\n\n        int CompereKeys(Keys key1, Keys key2)\n        {\n            var res = ((int) key1 & 0xff).CompareTo((int) key2 & 0xff);\n            if (res == 0)\n                res = key1.CompareTo(key2);\n\n            return res;\n        }\n\n        private void BuildWrappers(HotkeysMapping hotkeys)\n        {\n            var keys = new List<Keys>(hotkeys.Keys);\n            keys.Sort(CompereKeys);\n\n            wrappers.Clear();\n            foreach (var k in keys)\n                wrappers.Add(new HotkeyWrapper(k, hotkeys[k]));\n        }\n\n        /// <summary>\n        /// Returns edited hotkey map\n        /// </summary>\n        /// <returns></returns>\n        public HotkeysMapping GetHotkeys()\n        {\n            var result = new HotkeysMapping();\n            foreach (var w in wrappers)\n                result[w.ToKeyData()] = w.Action;\n\n            return result;\n        }\n\n        private void btAdd_Click(object sender, EventArgs e)\n        {\n            wrappers.Add(new HotkeyWrapper(Keys.None, FCTBAction.None));\n        }\n\n        private void dgv_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)\n        {\n            var cell = (dgv[0, e.RowIndex] as DataGridViewComboBoxCell);\n            if (cell.Items.Count == 0)\n                foreach (var item in new string[]\n                    {\"\", \"Ctrl\", \"Ctrl + Shift\", \"Ctrl + Alt\", \"Shift\", \"Shift + Alt\", \"Alt\", \"Ctrl + Shift + Alt\"})\n                    cell.Items.Add(item);\n\n            cell = (dgv[1, e.RowIndex] as DataGridViewComboBoxCell);\n            if (cell.Items.Count == 0)\n                foreach (var item in Enum.GetValues(typeof(Keys)))\n                    cell.Items.Add(item);\n\n            cell = (dgv[2, e.RowIndex] as DataGridViewComboBoxCell);\n            if (cell.Items.Count == 0)\n                foreach (var item in Enum.GetValues(typeof(FCTBAction)))\n                    cell.Items.Add(item);\n        }\n\n        private void btResore_Click(object sender, EventArgs e)\n        {\n            HotkeysMapping h = new HotkeysMapping();\n            h.InitDefault();\n            BuildWrappers(h);\n        }\n\n        private void btRemove_Click(object sender, EventArgs e)\n        {\n            for (int i = dgv.RowCount - 1; i >= 0; i--)\n                if (dgv.Rows[i].Selected)\n                    dgv.Rows.RemoveAt(i);\n        }\n\n        private void HotkeysEditorForm_FormClosing(object sender, FormClosingEventArgs e)\n        {\n            if (DialogResult == System.Windows.Forms.DialogResult.OK)\n            {\n                var actions = GetUnAssignedActions();\n                if (!string.IsNullOrEmpty(actions))\n                {\n                    if (MessageBox.Show(\n                            \"Some actions are not assigned!\\r\\nActions: \" + actions +\n                            \"\\r\\nPress Yes to save and exit, press No to continue editing\",\n                            \"Some actions is not assigned\", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) ==\n                        System.Windows.Forms.DialogResult.No)\n                        e.Cancel = true;\n                }\n            }\n        }\n\n        private string GetUnAssignedActions()\n        {\n            StringBuilder sb = new StringBuilder();\n            var dic = new Dictionary<FCTBAction, FCTBAction>();\n\n            foreach (var w in wrappers)\n                dic[w.Action] = w.Action;\n\n            foreach (var item in Enum.GetValues(typeof(FCTBAction)))\n                if ((FCTBAction) item != FCTBAction.None)\n                    if (!((FCTBAction) item).ToString().StartsWith(\"CustomAction\"))\n                    {\n                        if (!dic.ContainsKey((FCTBAction) item))\n                            sb.Append(item + \", \");\n                    }\n\n            return sb.ToString().TrimEnd(' ', ',');\n        }\n    }\n\n    internal class HotkeyWrapper\n    {\n        public HotkeyWrapper(Keys keyData, FCTBAction action)\n        {\n            KeyEventArgs a = new KeyEventArgs(keyData);\n            Ctrl = a.Control;\n            Shift = a.Shift;\n            Alt = a.Alt;\n\n            Key = a.KeyCode;\n            Action = action;\n        }\n\n        public Keys ToKeyData()\n        {\n            var res = Key;\n            if (Ctrl) res |= Keys.Control;\n            if (Alt) res |= Keys.Alt;\n            if (Shift) res |= Keys.Shift;\n\n            return res;\n        }\n\n        bool Ctrl;\n        bool Shift;\n        bool Alt;\n\n        public string Modifiers\n        {\n            get\n            {\n                var res = \"\";\n                if (Ctrl) res += \"Ctrl + \";\n                if (Shift) res += \"Shift + \";\n                if (Alt) res += \"Alt + \";\n\n                return res.Trim(' ', '+');\n            }\n            set\n            {\n                if (value == null)\n                {\n                    Ctrl = Alt = Shift = false;\n                }\n                else\n                {\n                    Ctrl = value.Contains(\"Ctrl\");\n                    Shift = value.Contains(\"Shift\");\n                    Alt = value.Contains(\"Alt\");\n                }\n            }\n        }\n\n        public Keys Key { get; set; }\n        public FCTBAction Action { get; set; }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/HotkeysEditorForm.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"cbModifiers.UserAddedColumn\" type=\"System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n  <metadata name=\"cbKey.UserAddedColumn\" type=\"System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n  <metadata name=\"cbAction.UserAddedColumn\" type=\"System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n</root>"
  },
  {
    "path": "FastColoredTextBox/LimitedStack.cs",
    "content": "﻿using System;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Limited stack\n    /// </summary>\n    public class LimitedStack<T>\n    {\n        T[] items;\n        int count;\n        int start;\n\n        /// <summary>\n        /// Max stack length\n        /// </summary>\n        public int MaxItemCount\n        {\n            get { return items.Length; }\n        }\n\n        /// <summary>\n        /// Current length of stack\n        /// </summary>\n        public int Count\n        {\n            get { return count; }\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"maxItemCount\">Maximum length of stack</param>\n        public LimitedStack(int maxItemCount)\n        {\n            items = new T[maxItemCount];\n            count = 0;\n            start = 0;\n        }\n\n        /// <summary>\n        /// Pop item\n        /// </summary>\n        public T Pop()\n        {\n            if (count == 0)\n                throw new Exception(\"Stack is empty\");\n\n            int i = LastIndex;\n            T item = items[i];\n            items[i] = default(T);\n\n            count--;\n\n            return item;\n        }\n\n        int LastIndex\n        {\n            get { return (start + count - 1) % items.Length; }\n        }\n\n        /// <summary>\n        /// Peek item\n        /// </summary>\n        public T Peek()\n        {\n            if (count == 0)\n                return default(T);\n\n            return items[LastIndex];\n        }\n\n        /// <summary>\n        /// Push item\n        /// </summary>\n        public void Push(T item)\n        {\n            if (count == items.Length)\n                start = (start + 1) % items.Length;\n            else\n                count++;\n\n            items[LastIndex] = item;\n        }\n\n        /// <summary>\n        /// Clear stack\n        /// </summary>\n        public void Clear()\n        {\n            items = new T[items.Length];\n            count = 0;\n            start = 0;\n        }\n\n        public T[] ToArray()\n        {\n            T[] result = new T[count];\n            for (int i = 0; i < count; i++)\n                result[i] = items[(start + i) % items.Length];\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Line.cs",
    "content": "﻿using System.Collections.Generic;\nusing System;\nusing System.Text;\nusing System.Drawing;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Line of text\n    /// </summary>\n    public class Line : IList<Char>\n    {\n        protected List<Char> chars;\n\n        public string FoldingStartMarker { get; set; }\n        public string FoldingEndMarker { get; set; }\n\n        /// <summary>\n        /// Text of line was changed\n        /// </summary>\n        public bool IsChanged { get; set; }\n\n        /// <summary>\n        /// Time of last visit of caret in this line\n        /// </summary>\n        /// <remarks>This property can be used for forward/backward navigating</remarks>\n        public DateTime LastVisit { get; set; }\n\n        /// <summary>\n        /// Background brush.\n        /// </summary>\n        public Brush BackgroundBrush { get; set; }\n\n        /// <summary>\n        /// Unique ID\n        /// </summary>\n        public int UniqueId { get; private set; }\n\n        /// <summary>\n        /// Count of needed start spaces for AutoIndent\n        /// </summary>\n        public int AutoIndentSpacesNeededCount { get; set; }\n\n        internal Line(int uid)\n        {\n            this.UniqueId = uid;\n            chars = new List<Char>();\n        }\n\n\n        /// <summary>\n        /// Clears style of chars, delete folding markers\n        /// </summary>\n        public void ClearStyle(StyleIndex styleIndex)\n        {\n            FoldingStartMarker = null;\n            FoldingEndMarker = null;\n            for (int i = 0; i < Count; i++)\n            {\n                Char c = this[i];\n                c.style &= ~styleIndex;\n                this[i] = c;\n            }\n        }\n\n        /// <summary>\n        /// Text of the line\n        /// </summary>\n        public virtual string Text\n        {\n            get\n            {\n                StringBuilder sb = new StringBuilder(Count);\n                foreach (Char c in this)\n                    sb.Append(c.c);\n                return sb.ToString();\n            }\n        }\n\n        /// <summary>\n        /// Clears folding markers\n        /// </summary>\n        public void ClearFoldingMarkers()\n        {\n            FoldingStartMarker = null;\n            FoldingEndMarker = null;\n        }\n\n        /// <summary>\n        /// Count of start spaces\n        /// </summary>\n        public int StartSpacesCount\n        {\n            get\n            {\n                int spacesCount = 0;\n                for (int i = 0; i < Count; i++)\n                    if (this[i].c == ' ')\n                        spacesCount++;\n                    else\n                        break;\n                return spacesCount;\n            }\n        }\n\n        public int IndexOf(Char item)\n        {\n            return chars.IndexOf(item);\n        }\n\n        public void Insert(int index, Char item)\n        {\n            chars.Insert(index, item);\n        }\n\n        public void RemoveAt(int index)\n        {\n            chars.RemoveAt(index);\n        }\n\n        public Char this[int index]\n        {\n            get { return chars[index]; }\n            set { chars[index] = value; }\n        }\n\n        public void Add(Char item)\n        {\n            chars.Add(item);\n        }\n\n        public void Clear()\n        {\n            chars.Clear();\n        }\n\n        public bool Contains(Char item)\n        {\n            return chars.Contains(item);\n        }\n\n        public void CopyTo(Char[] array, int arrayIndex)\n        {\n            chars.CopyTo(array, arrayIndex);\n        }\n\n        /// <summary>\n        /// Chars count\n        /// </summary>\n        public int Count\n        {\n            get { return chars.Count; }\n        }\n\n        public bool IsReadOnly\n        {\n            get { return false; }\n        }\n\n        public bool Remove(Char item)\n        {\n            return chars.Remove(item);\n        }\n\n        public IEnumerator<Char> GetEnumerator()\n        {\n            return chars.GetEnumerator();\n        }\n\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n        {\n            return chars.GetEnumerator() as System.Collections.IEnumerator;\n        }\n\n        public virtual void RemoveRange(int index, int count)\n        {\n            if (index >= Count)\n                return;\n            chars.RemoveRange(index, Math.Min(Count - index, count));\n        }\n\n        public virtual void TrimExcess()\n        {\n            chars.TrimExcess();\n        }\n\n        public virtual void AddRange(IEnumerable<Char> collection)\n        {\n            chars.AddRange(collection);\n        }\n    }\n\n    public struct LineInfo\n    {\n        List<int> cutOffPositions;\n\n        //Y coordinate of line on screen\n        internal int startY;\n\n        internal int bottomPadding;\n\n        //indent of secondary wordwrap strings (in chars)\n        internal int wordWrapIndent;\n\n        /// <summary>\n        /// Visible state\n        /// </summary>\n        public VisibleState VisibleState;\n\n        public LineInfo(int startY)\n        {\n            cutOffPositions = null;\n            VisibleState = VisibleState.Visible;\n            this.startY = startY;\n            bottomPadding = 0;\n            wordWrapIndent = 0;\n        }\n\n        /// <summary>\n        /// Positions for wordwrap cutoffs\n        /// </summary>\n        public List<int> CutOffPositions\n        {\n            get\n            {\n                if (cutOffPositions == null)\n                    cutOffPositions = new List<int>();\n                return cutOffPositions;\n            }\n        }\n\n        /// <summary>\n        /// Count of wordwrap string count for this line\n        /// </summary>\n        public int WordWrapStringsCount\n        {\n            get\n            {\n                switch (VisibleState)\n                {\n                    case VisibleState.Visible:\n                        if (cutOffPositions == null)\n                            return 1;\n                        else\n                            return cutOffPositions.Count + 1;\n                    case VisibleState.Hidden: return 0;\n                    case VisibleState.StartOfHiddenBlock: return 1;\n                }\n\n                return 0;\n            }\n        }\n\n        internal int GetWordWrapStringStartPosition(int iWordWrapLine)\n        {\n            return iWordWrapLine == 0 ? 0 : CutOffPositions[iWordWrapLine - 1];\n        }\n\n        internal int GetWordWrapStringFinishPosition(int iWordWrapLine, Line line)\n        {\n            if (WordWrapStringsCount <= 0)\n                return 0;\n            return iWordWrapLine == WordWrapStringsCount - 1 ? line.Count - 1 : CutOffPositions[iWordWrapLine] - 1;\n        }\n\n        /// <summary>\n        /// Gets index of wordwrap string for given char position\n        /// </summary>\n        public int GetWordWrapStringIndex(int iChar)\n        {\n            if (cutOffPositions == null || cutOffPositions.Count == 0) return 0;\n            for (int i = 0; i < cutOffPositions.Count; i++)\n                if (cutOffPositions[i] > /*>=*/ iChar)\n                    return i;\n            return cutOffPositions.Count;\n        }\n    }\n\n    public enum VisibleState : byte\n    {\n        Visible,\n        StartOfHiddenBlock,\n        Hidden\n    }\n\n    public enum IndentMarker\n    {\n        None,\n        Increased,\n        Decreased\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/LinesAccessor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace FastColoredTextBoxNS\n{\n    public class LinesAccessor : IList<string>\n    {\n        IList<Line> ts;\n\n        public LinesAccessor(IList<Line> ts)\n        {\n            this.ts = ts;\n        }\n\n        public int IndexOf(string item)\n        {\n            for (int i = 0; i < ts.Count; i++)\n                if (ts[i].Text == item)\n                    return i;\n\n            return -1;\n        }\n\n        public void Insert(int index, string item)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void RemoveAt(int index)\n        {\n            throw new NotImplementedException();\n        }\n\n        public string this[int index]\n        {\n            get { return ts[index].Text; }\n            set { throw new NotImplementedException(); }\n        }\n\n        public void Add(string item)\n        {\n            throw new NotImplementedException();\n        }\n\n        public void Clear()\n        {\n            throw new NotImplementedException();\n        }\n\n        public bool Contains(string item)\n        {\n            for (int i = 0; i < ts.Count; i++)\n                if (ts[i].Text == item)\n                    return true;\n\n            return false;\n        }\n\n        public void CopyTo(string[] array, int arrayIndex)\n        {\n            for (int i = 0; i < ts.Count; i++)\n                array[i + arrayIndex] = ts[i].Text;\n        }\n\n        public int Count\n        {\n            get { return ts.Count; }\n        }\n\n        public bool IsReadOnly\n        {\n            get { return true; }\n        }\n\n        public bool Remove(string item)\n        {\n            throw new NotImplementedException();\n        }\n\n        public IEnumerator<string> GetEnumerator()\n        {\n            for (int i = 0; i < ts.Count; i++)\n                yield return ts[i].Text;\n        }\n\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/MacrosManager.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Text;\nusing System.Threading;\nusing System.Windows.Forms;\nusing System.Xml;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// This class records, stores and executes the macros.\n    /// </summary>\n    public class MacrosManager\n    {\n        private readonly List<object> macro = new List<object>();\n\n        internal MacrosManager(FastColoredTextBox ctrl)\n        {\n            UnderlayingControl = ctrl;\n            AllowMacroRecordingByUser = true;\n        }\n\n        /// <summary>\n        /// Allows to user to record macros\n        /// </summary>\n        public bool AllowMacroRecordingByUser { get; set; }\n\n        private bool isRecording;\n\n        /// <summary>\n        /// Returns current recording state. Set to True/False to start/stop recording programmatically.\n        /// </summary>\n        public bool IsRecording\n        {\n            get { return isRecording; }\n            set\n            {\n                isRecording = value;\n                UnderlayingControl.Invalidate();\n            }\n        }\n\n        /// <summary>\n        /// FCTB\n        /// </summary>\n        public FastColoredTextBox UnderlayingControl { get; private set; }\n\n        /// <summary>\n        /// Executes recorded macro\n        /// </summary>\n        /// <returns></returns>\n        public void ExecuteMacros()\n        {\n            IsRecording = false;\n            UnderlayingControl.BeginUpdate();\n            UnderlayingControl.Selection.BeginUpdate();\n            UnderlayingControl.BeginAutoUndo();\n            foreach (var item in macro)\n            {\n                if (item is Keys)\n                {\n                    UnderlayingControl.ProcessKey((Keys) item);\n                }\n\n                if (item is KeyValuePair<char, Keys>)\n                {\n                    var p = (KeyValuePair<char, Keys>) item;\n                    UnderlayingControl.ProcessKey(p.Key, p.Value);\n                }\n            }\n\n            UnderlayingControl.EndAutoUndo();\n            UnderlayingControl.Selection.EndUpdate();\n            UnderlayingControl.EndUpdate();\n        }\n\n        /// <summary>\n        /// Adds the char to current macro\n        /// </summary>\n        public void AddCharToMacros(char c, Keys modifiers)\n        {\n            macro.Add(new KeyValuePair<char, Keys>(c, modifiers));\n        }\n\n        /// <summary>\n        /// Adds keyboard key to current macro\n        /// </summary>\n        public void AddKeyToMacros(Keys keyData)\n        {\n            macro.Add(keyData);\n        }\n\n        /// <summary>\n        /// Clears last recorded macro\n        /// </summary>\n        public void ClearMacros()\n        {\n            macro.Clear();\n        }\n\n\n        internal void ProcessKey(Keys keyData)\n        {\n            if (IsRecording)\n                AddKeyToMacros(keyData);\n        }\n\n        internal void ProcessKey(char c, Keys modifiers)\n        {\n            if (IsRecording)\n                AddCharToMacros(c, modifiers);\n        }\n\n        /// <summary>\n        /// Returns True if last macro is empty\n        /// </summary>\n        public bool MacroIsEmpty\n        {\n            get { return macro.Count == 0; }\n        }\n\n        /// <summary>\n        /// Macros as string.\n        /// </summary>\n        public string Macros\n        {\n            get\n            {\n                var cult = Thread.CurrentThread.CurrentUICulture;\n                Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;\n                var kc = new KeysConverter();\n\n                StringBuilder sb = new StringBuilder();\n                sb.AppendLine(\"<macros>\");\n                foreach (var item in macro)\n                {\n                    if (item is Keys)\n                    {\n                        sb.AppendFormat(\"<item key='{0}' />\\r\\n\", kc.ConvertToString((Keys) item));\n                    }\n                    else if (item is KeyValuePair<char, Keys>)\n                    {\n                        var p = (KeyValuePair<char, Keys>) item;\n                        sb.AppendFormat(\"<item char='{0}' key='{1}' />\\r\\n\", (int) p.Key, kc.ConvertToString(p.Value));\n                    }\n                }\n\n                sb.AppendLine(\"</macros>\");\n\n                Thread.CurrentThread.CurrentUICulture = cult;\n\n                return sb.ToString();\n            }\n\n            set\n            {\n                isRecording = false;\n                ClearMacros();\n\n                if (string.IsNullOrEmpty(value))\n                    return;\n\n                var doc = new XmlDocument();\n                doc.LoadXml(value);\n                var list = doc.SelectNodes(\"./macros/item\");\n\n                var cult = Thread.CurrentThread.CurrentUICulture;\n                Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;\n                var kc = new KeysConverter();\n\n                if (list != null)\n                    foreach (XmlElement node in list)\n                    {\n                        var ca = node.GetAttributeNode(\"char\");\n                        var ka = node.GetAttributeNode(\"key\");\n                        if (ca != null)\n                        {\n                            if (ka != null)\n                                AddCharToMacros((char) int.Parse(ca.Value), (Keys) kc.ConvertFromString(ka.Value));\n                            else\n                                AddCharToMacros((char) int.Parse(ca.Value), Keys.None);\n                        }\n                        else if (ka != null)\n                            AddKeyToMacros((Keys) kc.ConvertFromString(ka.Value));\n                    }\n\n                Thread.CurrentThread.CurrentUICulture = cult;\n            }\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/NativeMethods.cs",
    "content": "using System;\nusing System.Runtime.InteropServices;\n\nnamespace FastColoredTextBoxNS\n{\n    public static class NativeMethodWrapper {\n        public static void GetNativeSystemInfo(ref Win32NativeMethods.SYSTEM_INFO sysInfo)\n        {\n             Win32NativeMethods.GetNativeSystemInfo(ref sysInfo);\n             return;\n        }\n\n        public static void GetSystemInfo(ref Win32NativeMethods.SYSTEM_INFO sysInfo)\n        {\n            Win32NativeMethods.GetSystemInfo(ref sysInfo);\n            return;        \n        }\n\n        public static void ShowCaret(IntPtr handle)\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                Win32NativeMethods.ShowCaret(handle);\n        }\n\n        public static void SetCaretPos(int carX, int carY)\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                Win32NativeMethods.SetCaretPos(carX,carY);        }\n\n        public static void CreateCaret(IntPtr handle, int i, int carWidth, int caretHeight)\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                Win32NativeMethods.CreateCaret(handle,i,carWidth,caretHeight);\n        }\n\n        public static void HideCaret(IntPtr handle)\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                Win32NativeMethods.HideCaret(handle);\n        }\n\n        public static void SendMessage(IntPtr handle, int wmSetredraw, int i, int i1)\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                Win32NativeMethods.SendMessage(handle,wmSetredraw,i,i1);\n        }\n\n        public static IntPtr ImmGetContext(IntPtr handle)\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                return Win32NativeMethods.ImmGetContext(handle);\n            return IntPtr.Zero;\n        }\n\n        public static void CloseClipboard()\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                Win32NativeMethods.CloseClipboard();        \n        }\n\n        public static void ImmAssociateContext(IntPtr handle, IntPtr mHImc)\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Unix)\n                Win32NativeMethods.ImmAssociateContext(handle,mHImc); \n        }\n    }\n    \n    public static class Win32NativeMethods\n    {\n        [DllImport(\"User32.dll\")]\n        public static extern bool CreateCaret(IntPtr hWnd, int hBitmap, int nWidth, int nHeight);\n\n        [DllImport(\"User32.dll\")]\n        public static extern bool SetCaretPos(int x, int y);\n\n        [DllImport(\"User32.dll\")]\n        public static extern bool DestroyCaret();\n\n        [DllImport(\"User32.dll\")]\n        public static extern bool ShowCaret(IntPtr hWnd);\n\n        [DllImport(\"User32.dll\")]\n        public static extern bool HideCaret(IntPtr hWnd);\n        \n        [DllImport(\"Imm32.dll\")]\n        public static extern IntPtr ImmGetContext(IntPtr hWnd);\n\n        [DllImport(\"Imm32.dll\")]\n        public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);\n        \n        [DllImport(\"user32.dll\")]\n        public static extern IntPtr GetOpenClipboardWindow();\n\n        [DllImport(\"user32.dll\")]\n        public static extern IntPtr CloseClipboard();\n        \n        [DllImport(\"user32.dll\")]\n        public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);\n        \n        [DllImport(\"kernel32.dll\")]\n        public static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);\n\n        [DllImport(\"kernel32.dll\")]\n        public static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);\n        \n        [StructLayout(LayoutKind.Sequential)]\n        public struct SYSTEM_INFO\n        {\n            public ushort wProcessorArchitecture;\n            public ushort wReserved;\n            public uint dwPageSize;\n            public IntPtr lpMinimumApplicationAddress;\n            public IntPtr lpMaximumApplicationAddress;\n            public UIntPtr dwActiveProcessorMask;\n            public uint dwNumberOfProcessors;\n            public uint dwProcessorType;\n            public uint dwAllocationGranularity;\n            public ushort wProcessorLevel;\n            public ushort wProcessorRevision;\n        };\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Place.cs",
    "content": "﻿using System;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Line index and char index\n    /// </summary>\n    public struct Place : IEquatable<Place>\n    {\n        public int iChar;\n        public int iLine;\n\n        public Place(int iChar, int iLine)\n        {\n            this.iChar = iChar;\n            this.iLine = iLine;\n        }\n\n        public void Offset(int dx, int dy)\n        {\n            iChar += dx;\n            iLine += dy;\n        }\n\n        public bool Equals(Place other)\n        {\n            return iChar == other.iChar && iLine == other.iLine;\n        }\n\n        public override bool Equals(object obj)\n        {\n            return (obj is Place) && Equals((Place) obj);\n        }\n\n        public override int GetHashCode()\n        {\n            return iChar.GetHashCode() ^ iLine.GetHashCode();\n        }\n\n        public static bool operator !=(Place p1, Place p2)\n        {\n            return !p1.Equals(p2);\n        }\n\n        public static bool operator ==(Place p1, Place p2)\n        {\n            return p1.Equals(p2);\n        }\n\n        public static bool operator <(Place p1, Place p2)\n        {\n            if (p1.iLine < p2.iLine) return true;\n            if (p1.iLine > p2.iLine) return false;\n            if (p1.iChar < p2.iChar) return true;\n            return false;\n        }\n\n        public static bool operator <=(Place p1, Place p2)\n        {\n            if (p1.Equals(p2)) return true;\n            if (p1.iLine < p2.iLine) return true;\n            if (p1.iLine > p2.iLine) return false;\n            if (p1.iChar < p2.iChar) return true;\n            return false;\n        }\n\n        public static bool operator >(Place p1, Place p2)\n        {\n            if (p1.iLine > p2.iLine) return true;\n            if (p1.iLine < p2.iLine) return false;\n            if (p1.iChar > p2.iChar) return true;\n            return false;\n        }\n\n        public static bool operator >=(Place p1, Place p2)\n        {\n            if (p1.Equals(p2)) return true;\n            if (p1.iLine > p2.iLine) return true;\n            if (p1.iLine < p2.iLine) return false;\n            if (p1.iChar > p2.iChar) return true;\n            return false;\n        }\n\n        public static Place operator +(Place p1, Place p2)\n        {\n            return new Place(p1.iChar + p2.iChar, p1.iLine + p2.iLine);\n        }\n\n        public static Place Empty\n        {\n            get { return new Place(); }\n        }\n\n        public override string ToString()\n        {\n            return \"(\" + iChar + \",\" + iLine + \")\";\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/PlatformType.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Runtime.InteropServices;\n\nnamespace FastColoredTextBoxNS\n{\n    public static class PlatformType\n    {\n        const ushort PROCESSOR_ARCHITECTURE_INTEL = 0;\n        const ushort PROCESSOR_ARCHITECTURE_IA64 = 6;\n        const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9;\n        const ushort PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF;\n        \n\n        public static Platform GetOperationSystemPlatform()\n        {\n            if (Environment.OSVersion.Platform == PlatformID.Unix)\n                return Environment.Is64BitOperatingSystem  ? Platform.X64 : Platform.X86;\n            var sysInfo = new Win32NativeMethods.SYSTEM_INFO();\n\n            // WinXP and older - use GetNativeSystemInfo\n            if (Environment.OSVersion.Version.Major > 5 ||\n                (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1))\n            {\n                NativeMethodWrapper.GetNativeSystemInfo(ref sysInfo);\n            }\n            // else use GetSystemInfo\n            else\n            {\n                NativeMethodWrapper.GetSystemInfo(ref sysInfo);\n            }\n\n            switch (sysInfo.wProcessorArchitecture)\n            {\n                case PROCESSOR_ARCHITECTURE_IA64:\n                case PROCESSOR_ARCHITECTURE_AMD64:\n                    return Platform.X64;\n\n                case PROCESSOR_ARCHITECTURE_INTEL:\n                    return Platform.X86;\n\n                default:\n                    return Platform.Unknown;\n            }\n        }\n    }\n\n    public enum Platform\n    {\n        X86,\n        X64,\n        Unknown\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"FastColoredTextBox\")]\n[assembly: AssemblyDescription(\"Fast сolored textbox control\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"Pavel Torgashov\")]\n[assembly: AssemblyProduct(\"FastColoredTextBox\")]\n[assembly: AssemblyCopyright(\"© Pavel Torgashov, 2011-2016, pavel_torgashov@ukr.net.\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"95be11b3-45bc-4512-be26-a860a78bd1f1\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"2.16.23.0\")]\n[assembly: AssemblyFileVersion(\"2.16.23.0\")]"
  },
  {
    "path": "FastColoredTextBox/Range.cs",
    "content": "﻿using System;\nusing System.Text;\nusing System.Drawing;\nusing System.Text.RegularExpressions;\nusing System.Collections.Generic;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Diapason of text chars\n    /// </summary>\n    public class Range : IEnumerable<Place>\n    {\n        Place start;\n        Place end;\n        public readonly FastColoredTextBox tb;\n        int preferedPos = -1;\n        int updating = 0;\n\n        string cachedText;\n        List<Place> cachedCharIndexToPlace;\n        int cachedTextVersion = -1;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        public Range(FastColoredTextBox tb)\n        {\n            this.tb = tb;\n        }\n\n        /// <summary>\n        /// Return true if no selected text\n        /// </summary>\n        public virtual bool IsEmpty\n        {\n            get\n            {\n                if (ColumnSelectionMode)\n                    return Start.iChar == End.iChar;\n                return Start == End;\n            }\n        }\n\n        private bool columnSelectionMode;\n\n        /// <summary>\n        /// Column selection mode\n        /// </summary>\n        public bool ColumnSelectionMode\n        {\n            get { return columnSelectionMode; }\n            set { columnSelectionMode = value; }\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        public Range(FastColoredTextBox tb, int iStartChar, int iStartLine, int iEndChar, int iEndLine)\n            : this(tb)\n        {\n            start = new Place(iStartChar, iStartLine);\n            end = new Place(iEndChar, iEndLine);\n        }\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        public Range(FastColoredTextBox tb, Place start, Place end)\n            : this(tb)\n        {\n            this.start = start;\n            this.end = end;\n        }\n\n        /// <summary>\n        /// Constructor. Creates range of the line\n        /// </summary>\n        public Range(FastColoredTextBox tb, int iLine)\n            : this(tb)\n        {\n            start = new Place(0, iLine);\n            end = new Place(tb[iLine].Count, iLine);\n        }\n\n        public bool Contains(Place place)\n        {\n            if (place.iLine < Math.Min(start.iLine, end.iLine)) return false;\n            if (place.iLine > Math.Max(start.iLine, end.iLine)) return false;\n\n            Place s = start;\n            Place e = end;\n            //normalize start and end\n            if (s.iLine > e.iLine || (s.iLine == e.iLine && s.iChar > e.iChar))\n            {\n                var temp = s;\n                s = e;\n                e = temp;\n            }\n\n            if (columnSelectionMode)\n            {\n                if (place.iChar < s.iChar || place.iChar > e.iChar) return false;\n            }\n            else\n            {\n                if (place.iLine == s.iLine && place.iChar < s.iChar) return false;\n                if (place.iLine == e.iLine && place.iChar > e.iChar) return false;\n            }\n\n            return true;\n        }\n\n        /// <summary>\n        /// Returns intersection with other range,\n        /// empty range returned otherwise\n        /// </summary>\n        /// <param name=\"range\"></param>\n        /// <returns></returns>\n        public virtual Range GetIntersectionWith(Range range)\n        {\n            if (ColumnSelectionMode)\n                return GetIntersectionWith_ColumnSelectionMode(range);\n\n            Range r1 = this.Clone();\n            Range r2 = range.Clone();\n            r1.Normalize();\n            r2.Normalize();\n            Place newStart = r1.Start > r2.Start ? r1.Start : r2.Start;\n            Place newEnd = r1.End < r2.End ? r1.End : r2.End;\n            if (newEnd < newStart)\n                return new Range(tb, start, start);\n            return tb.GetRange(newStart, newEnd);\n        }\n\n        /// <summary>\n        /// Returns union with other range.\n        /// </summary>\n        /// <param name=\"range\"></param>\n        /// <returns></returns>\n        public Range GetUnionWith(Range range)\n        {\n            Range r1 = this.Clone();\n            Range r2 = range.Clone();\n            r1.Normalize();\n            r2.Normalize();\n            Place newStart = r1.Start < r2.Start ? r1.Start : r2.Start;\n            Place newEnd = r1.End > r2.End ? r1.End : r2.End;\n\n            return tb.GetRange(newStart, newEnd);\n        }\n\n        /// <summary>\n        /// Select all chars of control\n        /// </summary>\n        public void SelectAll()\n        {\n            ColumnSelectionMode = false;\n\n            Start = new Place(0, 0);\n            if (tb.LinesCount == 0)\n                Start = new Place(0, 0);\n            else\n            {\n                end = new Place(0, 0);\n                start = new Place(tb[tb.LinesCount - 1].Count, tb.LinesCount - 1);\n            }\n\n            if (this == tb.Selection)\n                tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Start line and char position\n        /// </summary>\n        public Place Start\n        {\n            get { return start; }\n            set\n            {\n                end = start = value;\n                preferedPos = -1;\n                OnSelectionChanged();\n            }\n        }\n\n        /// <summary>\n        /// Finish line and char position\n        /// </summary>\n        public Place End\n        {\n            get { return end; }\n            set\n            {\n                end = value;\n                OnSelectionChanged();\n            }\n        }\n\n        /// <summary>\n        /// Text of range\n        /// </summary>\n        /// <remarks>This property has not 'set' accessor because undo/redo stack works only with \n        /// FastColoredTextBox.Selection range. So, if you want to set text, you need to use FastColoredTextBox.Selection\n        /// and FastColoredTextBox.InsertText() mehtod.\n        /// </remarks>\n        public virtual string Text\n        {\n            get\n            {\n                if (ColumnSelectionMode)\n                    return Text_ColumnSelectionMode;\n\n                int fromLine = Math.Min(end.iLine, start.iLine);\n                int toLine = Math.Max(end.iLine, start.iLine);\n                int fromChar = FromX;\n                int toChar = ToX;\n                if (fromLine < 0) return null;\n                //\n                StringBuilder sb = new StringBuilder();\n                for (int y = fromLine; y <= toLine; y++)\n                {\n                    int fromX = y == fromLine ? fromChar : 0;\n                    int toX = y == toLine ? Math.Min(tb[y].Count - 1, toChar - 1) : tb[y].Count - 1;\n                    for (int x = fromX; x <= toX; x++)\n                        sb.Append(tb[y][x].c);\n                    if (y != toLine && fromLine != toLine)\n                        sb.AppendLine();\n                }\n\n                return sb.ToString();\n            }\n        }\n\n        public int Length\n        {\n            get\n            {\n                if (ColumnSelectionMode)\n                    return Length_ColumnSelectionMode(false);\n\n                int fromLine = Math.Min(end.iLine, start.iLine);\n                int toLine = Math.Max(end.iLine, start.iLine);\n                int cnt = 0;\n                if (fromLine < 0) return 0;\n\n                for (int y = fromLine; y <= toLine; y++)\n                {\n                    int fromX = y == fromLine ? FromX : 0;\n                    int toX = y == toLine ? Math.Min(tb[y].Count - 1, ToX - 1) : tb[y].Count - 1;\n\n                    cnt += toX - fromX + 1;\n\n                    if (y != toLine && fromLine != toLine)\n                        cnt += Environment.NewLine.Length;\n                }\n\n                return cnt;\n            }\n        }\n\n        public int TextLength\n        {\n            get\n            {\n                if (ColumnSelectionMode)\n                    return Length_ColumnSelectionMode(true);\n                else\n                    return Length;\n            }\n        }\n\n        internal void GetText(out string text, out List<Place> charIndexToPlace)\n        {\n            //try get cached text\n            if (tb.TextVersion == cachedTextVersion)\n            {\n                text = cachedText;\n                charIndexToPlace = cachedCharIndexToPlace;\n                return;\n            }\n\n            //\n            int fromLine = Math.Min(end.iLine, start.iLine);\n            int toLine = Math.Max(end.iLine, start.iLine);\n            int fromChar = FromX;\n            int toChar = ToX;\n\n            StringBuilder sb = new StringBuilder((toLine - fromLine) * 50);\n            charIndexToPlace = new List<Place>(sb.Capacity);\n            if (fromLine >= 0)\n            {\n                for (int y = fromLine; y <= toLine; y++)\n                {\n                    int fromX = y == fromLine ? fromChar : 0;\n                    int toX = y == toLine ? Math.Min(toChar - 1, tb[y].Count - 1) : tb[y].Count - 1;\n                    for (int x = fromX; x <= toX; x++)\n                    {\n                        sb.Append(tb[y][x].c);\n                        charIndexToPlace.Add(new Place(x, y));\n                    }\n\n                    if (y != toLine && fromLine != toLine)\n                        foreach (char c in Environment.NewLine)\n                        {\n                            sb.Append(c);\n                            charIndexToPlace.Add(new Place(tb[y].Count /*???*/, y));\n                        }\n                }\n            }\n\n            text = sb.ToString();\n            charIndexToPlace.Add(End > Start ? End : Start);\n            //caching\n            cachedText = text;\n            cachedCharIndexToPlace = charIndexToPlace;\n            cachedTextVersion = tb.TextVersion;\n        }\n\n        /// <summary>\n        /// Returns first char after Start place\n        /// </summary>\n        public char CharAfterStart\n        {\n            get\n            {\n                if (Start.iChar >= tb[Start.iLine].Count)\n                    return '\\n';\n                return tb[Start.iLine][Start.iChar].c;\n            }\n        }\n\n        /// <summary>\n        /// Returns first char before Start place\n        /// </summary>\n        public char CharBeforeStart\n        {\n            get\n            {\n                if (Start.iChar > tb[Start.iLine].Count)\n                    return '\\n';\n                if (Start.iChar <= 0)\n                    return '\\n';\n                return tb[Start.iLine][Start.iChar - 1].c;\n            }\n        }\n\n        /// <summary>\n        /// Returns required char's number before start of the Range\n        /// </summary>\n        public string GetCharsBeforeStart(int charsCount)\n        {\n            var pos = tb.PlaceToPosition(Start) - charsCount;\n            if (pos < 0) pos = 0;\n\n            return new Range(tb, tb.PositionToPlace(pos), Start).Text;\n        }\n\n        /// <summary>\n        /// Returns required char's number after start of the Range\n        /// </summary>\n        public string GetCharsAfterStart(int charsCount)\n        {\n            return GetCharsBeforeStart(-charsCount);\n        }\n\n        /// <summary>\n        /// Clone range\n        /// </summary>\n        /// <returns></returns>\n        public Range Clone()\n        {\n            return (Range) MemberwiseClone();\n        }\n\n        /// <summary>\n        /// Return minimum of end.X and start.X\n        /// </summary>\n        internal int FromX\n        {\n            get\n            {\n                if (end.iLine < start.iLine) return end.iChar;\n                if (end.iLine > start.iLine) return start.iChar;\n                return Math.Min(end.iChar, start.iChar);\n            }\n        }\n\n        /// <summary>\n        /// Return maximum of end.X and start.X\n        /// </summary>\n        internal int ToX\n        {\n            get\n            {\n                if (end.iLine < start.iLine) return start.iChar;\n                if (end.iLine > start.iLine) return end.iChar;\n                return Math.Max(end.iChar, start.iChar);\n            }\n        }\n\n        public int FromLine\n        {\n            get { return Math.Min(Start.iLine, End.iLine); }\n        }\n\n        public int ToLine\n        {\n            get { return Math.Max(Start.iLine, End.iLine); }\n        }\n\n        /// <summary>\n        /// Move range right\n        /// </summary>\n        /// <remarks>This method jump over folded blocks</remarks>\n        public bool GoRight()\n        {\n            Place prevStart = start;\n            GoRight(false);\n            return prevStart != start;\n        }\n\n        /// <summary>\n        /// Move range left\n        /// </summary>\n        /// <remarks>This method can to go inside folded blocks</remarks>\n        public virtual bool GoRightThroughFolded()\n        {\n            if (ColumnSelectionMode)\n                return GoRightThroughFolded_ColumnSelectionMode();\n\n            if (start.iLine >= tb.LinesCount - 1 && start.iChar >= tb[tb.LinesCount - 1].Count)\n                return false;\n\n            if (start.iChar < tb[start.iLine].Count)\n                start.Offset(1, 0);\n            else\n                start = new Place(0, start.iLine + 1);\n\n            preferedPos = -1;\n            end = start;\n            OnSelectionChanged();\n            return true;\n        }\n\n        /// <summary>\n        /// Move range left\n        /// </summary>\n        /// <remarks>This method jump over folded blocks</remarks>\n        public bool GoLeft()\n        {\n            ColumnSelectionMode = false;\n\n            Place prevStart = start;\n            GoLeft(false);\n            return prevStart != start;\n        }\n\n        /// <summary>\n        /// Move range left\n        /// </summary>\n        /// <remarks>This method can to go inside folded blocks</remarks>\n        public bool GoLeftThroughFolded()\n        {\n            ColumnSelectionMode = false;\n\n            if (start.iChar == 0 && start.iLine == 0)\n                return false;\n\n            if (start.iChar > 0)\n                start.Offset(-1, 0);\n            else\n                start = new Place(tb[start.iLine - 1].Count, start.iLine - 1);\n\n            preferedPos = -1;\n            end = start;\n            OnSelectionChanged();\n            return true;\n        }\n\n        public void GoLeft(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (!shift)\n                if (start > end)\n                {\n                    Start = End;\n                    return;\n                }\n\n            if (start.iChar != 0 || start.iLine != 0)\n            {\n                if (start.iChar > 0 && tb.LineInfos[start.iLine].VisibleState == VisibleState.Visible)\n                    start.Offset(-1, 0);\n                else\n                {\n                    int i = tb.FindPrevVisibleLine(start.iLine);\n                    if (i == start.iLine) return;\n                    start = new Place(tb[i].Count, i);\n                }\n            }\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n\n            preferedPos = -1;\n        }\n\n        public void GoRight(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (!shift)\n                if (start < end)\n                {\n                    Start = End;\n                    return;\n                }\n\n            if (start.iLine < tb.LinesCount - 1 || start.iChar < tb[tb.LinesCount - 1].Count)\n            {\n                if (start.iChar < tb[start.iLine].Count &&\n                    tb.LineInfos[start.iLine].VisibleState == VisibleState.Visible)\n                    start.Offset(1, 0);\n                else\n                {\n                    int i = tb.FindNextVisibleLine(start.iLine);\n                    if (i == start.iLine) return;\n                    start = new Place(0, i);\n                }\n            }\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n\n            preferedPos = -1;\n        }\n\n        internal void GoUp(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (!shift)\n                if (start.iLine > end.iLine)\n                {\n                    Start = End;\n                    return;\n                }\n\n            if (preferedPos < 0)\n                preferedPos = start.iChar - tb.LineInfos[start.iLine]\n                                  .GetWordWrapStringStartPosition(tb.LineInfos[start.iLine]\n                                      .GetWordWrapStringIndex(start.iChar));\n\n            int iWW = tb.LineInfos[start.iLine].GetWordWrapStringIndex(start.iChar);\n            if (iWW == 0)\n            {\n                if (start.iLine <= 0) return;\n                int i = tb.FindPrevVisibleLine(start.iLine);\n                if (i == start.iLine) return;\n                start.iLine = i;\n                iWW = tb.LineInfos[start.iLine].WordWrapStringsCount;\n            }\n\n            if (iWW > 0)\n            {\n                int finish = tb.LineInfos[start.iLine].GetWordWrapStringFinishPosition(iWW - 1, tb[start.iLine]);\n                start.iChar = tb.LineInfos[start.iLine].GetWordWrapStringStartPosition(iWW - 1) + preferedPos;\n                if (start.iChar > finish + 1)\n                    start.iChar = finish + 1;\n            }\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n        }\n\n        internal void GoPageUp(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (preferedPos < 0)\n                preferedPos = start.iChar - tb.LineInfos[start.iLine]\n                                  .GetWordWrapStringStartPosition(tb.LineInfos[start.iLine]\n                                      .GetWordWrapStringIndex(start.iChar));\n\n            int pageHeight = tb.ClientRectangle.Height / tb.CharHeight - 1;\n\n            for (int i = 0; i < pageHeight; i++)\n            {\n                int iWW = tb.LineInfos[start.iLine].GetWordWrapStringIndex(start.iChar);\n                if (iWW == 0)\n                {\n                    if (start.iLine <= 0) break;\n                    //pass hidden\n                    int newLine = tb.FindPrevVisibleLine(start.iLine);\n                    if (newLine == start.iLine) break;\n                    start.iLine = newLine;\n                    iWW = tb.LineInfos[start.iLine].WordWrapStringsCount;\n                }\n\n                if (iWW > 0)\n                {\n                    int finish = tb.LineInfos[start.iLine].GetWordWrapStringFinishPosition(iWW - 1, tb[start.iLine]);\n                    start.iChar = tb.LineInfos[start.iLine].GetWordWrapStringStartPosition(iWW - 1) + preferedPos;\n                    if (start.iChar > finish + 1)\n                        start.iChar = finish + 1;\n                }\n            }\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n        }\n\n        internal void GoDown(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (!shift)\n                if (start.iLine < end.iLine)\n                {\n                    Start = End;\n                    return;\n                }\n\n            if (preferedPos < 0)\n                preferedPos = start.iChar - tb.LineInfos[start.iLine]\n                                  .GetWordWrapStringStartPosition(tb.LineInfos[start.iLine]\n                                      .GetWordWrapStringIndex(start.iChar));\n\n            int iWW = tb.LineInfos[start.iLine].GetWordWrapStringIndex(start.iChar);\n            if (iWW >= tb.LineInfos[start.iLine].WordWrapStringsCount - 1)\n            {\n                if (start.iLine >= tb.LinesCount - 1) return;\n                //pass hidden\n                int i = tb.FindNextVisibleLine(start.iLine);\n                if (i == start.iLine) return;\n                start.iLine = i;\n                iWW = -1;\n            }\n\n            if (iWW < tb.LineInfos[start.iLine].WordWrapStringsCount - 1)\n            {\n                int finish = tb.LineInfos[start.iLine].GetWordWrapStringFinishPosition(iWW + 1, tb[start.iLine]);\n                start.iChar = tb.LineInfos[start.iLine].GetWordWrapStringStartPosition(iWW + 1) + preferedPos;\n                if (start.iChar > finish + 1)\n                    start.iChar = finish + 1;\n            }\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n        }\n\n        internal void GoPageDown(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (preferedPos < 0)\n                preferedPos = start.iChar - tb.LineInfos[start.iLine]\n                                  .GetWordWrapStringStartPosition(tb.LineInfos[start.iLine]\n                                      .GetWordWrapStringIndex(start.iChar));\n\n            int pageHeight = tb.ClientRectangle.Height / tb.CharHeight - 1;\n\n            for (int i = 0; i < pageHeight; i++)\n            {\n                int iWW = tb.LineInfos[start.iLine].GetWordWrapStringIndex(start.iChar);\n                if (iWW >= tb.LineInfos[start.iLine].WordWrapStringsCount - 1)\n                {\n                    if (start.iLine >= tb.LinesCount - 1) break;\n                    //pass hidden\n                    int newLine = tb.FindNextVisibleLine(start.iLine);\n                    if (newLine == start.iLine) break;\n                    start.iLine = newLine;\n                    iWW = -1;\n                }\n\n                if (iWW < tb.LineInfos[start.iLine].WordWrapStringsCount - 1)\n                {\n                    int finish = tb.LineInfos[start.iLine].GetWordWrapStringFinishPosition(iWW + 1, tb[start.iLine]);\n                    start.iChar = tb.LineInfos[start.iLine].GetWordWrapStringStartPosition(iWW + 1) + preferedPos;\n                    if (start.iChar > finish + 1)\n                        start.iChar = finish + 1;\n                }\n            }\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n        }\n\n        internal void GoHome(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (start.iLine < 0)\n                return;\n\n            if (tb.LineInfos[start.iLine].VisibleState != VisibleState.Visible)\n                return;\n\n            start = new Place(0, start.iLine);\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n\n            preferedPos = -1;\n        }\n\n        internal void GoEnd(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (start.iLine < 0)\n                return;\n            if (tb.LineInfos[start.iLine].VisibleState != VisibleState.Visible)\n                return;\n\n            start = new Place(tb[start.iLine].Count, start.iLine);\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n\n            preferedPos = -1;\n        }\n\n        /// <summary>\n        /// Set style for range\n        /// </summary>\n        public void SetStyle(Style style)\n        {\n            //search code for style\n            int code = tb.GetOrSetStyleLayerIndex(style);\n            //set code to chars\n            SetStyle(ToStyleIndex(code));\n            //\n            tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Set style for given regex pattern\n        /// </summary>\n        public void SetStyle(Style style, string regexPattern)\n        {\n            //search code for style\n            StyleIndex layer = ToStyleIndex(tb.GetOrSetStyleLayerIndex(style));\n            SetStyle(layer, regexPattern, RegexOptions.None);\n        }\n\n        /// <summary>\n        /// Set style for given regex\n        /// </summary>\n        public void SetStyle(Style style, Regex regex)\n        {\n            //search code for style\n            StyleIndex layer = ToStyleIndex(tb.GetOrSetStyleLayerIndex(style));\n            SetStyle(layer, regex);\n        }\n\n\n        /// <summary>\n        /// Set style for given regex pattern\n        /// </summary>\n        public void SetStyle(Style style, string regexPattern, RegexOptions options)\n        {\n            //search code for style\n            StyleIndex layer = ToStyleIndex(tb.GetOrSetStyleLayerIndex(style));\n            SetStyle(layer, regexPattern, options);\n        }\n\n        /// <summary>\n        /// Set style for given regex pattern\n        /// </summary>\n        public void SetStyle(StyleIndex styleLayer, string regexPattern, RegexOptions options)\n        {\n            if (Math.Abs(Start.iLine - End.iLine) > 1000)\n                options |= SyntaxHighlighter.RegexCompiledOption;\n            //\n            foreach (var range in GetRanges(regexPattern, options))\n                range.SetStyle(styleLayer);\n            //\n            tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Set style for given regex pattern\n        /// </summary>\n        public void SetStyle(StyleIndex styleLayer, Regex regex)\n        {\n            foreach (var range in GetRanges(regex))\n                range.SetStyle(styleLayer);\n            //\n            tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Appends style to chars of range\n        /// </summary>\n        public void SetStyle(StyleIndex styleIndex)\n        {\n            //set code to chars\n            int fromLine = Math.Min(End.iLine, Start.iLine);\n            int toLine = Math.Max(End.iLine, Start.iLine);\n            int fromChar = FromX;\n            int toChar = ToX;\n            if (fromLine < 0) return;\n            //\n            for (int y = fromLine; y <= toLine; y++)\n            {\n                int fromX = y == fromLine ? fromChar : 0;\n                int toX = y == toLine ? Math.Min(toChar - 1, tb[y].Count - 1) : tb[y].Count - 1;\n                for (int x = fromX; x <= toX; x++)\n                {\n                    Char c = tb[y][x];\n                    c.style |= styleIndex;\n                    tb[y][x] = c;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Sets folding markers\n        /// </summary>\n        /// <param name=\"startFoldingPattern\">Pattern for start folding line</param>\n        /// <param name=\"finishFoldingPattern\">Pattern for finish folding line</param>\n        public void SetFoldingMarkers(string startFoldingPattern, string finishFoldingPattern)\n        {\n            SetFoldingMarkers(startFoldingPattern, finishFoldingPattern, SyntaxHighlighter.RegexCompiledOption);\n        }\n\n        /// <summary>\n        /// Sets folding markers\n        /// </summary>\n        /// <param name=\"startFoldingPattern\">Pattern for start folding line</param>\n        /// <param name=\"finishFoldingPattern\">Pattern for finish folding line</param>\n        public void SetFoldingMarkers(string startFoldingPattern, string finishFoldingPattern, RegexOptions options)\n        {\n            if (startFoldingPattern == finishFoldingPattern)\n            {\n                SetFoldingMarkers(startFoldingPattern, options);\n                return;\n            }\n\n            foreach (var range in GetRanges(startFoldingPattern, options))\n                tb[range.Start.iLine].FoldingStartMarker = startFoldingPattern;\n\n            foreach (var range in GetRanges(finishFoldingPattern, options))\n                tb[range.Start.iLine].FoldingEndMarker = startFoldingPattern;\n            //\n            tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Sets folding markers\n        /// </summary>\n        /// <param name=\"startEndFoldingPattern\">Pattern for start and end folding line</param>\n        public void SetFoldingMarkers(string foldingPattern, RegexOptions options)\n        {\n            foreach (var range in GetRanges(foldingPattern, options))\n            {\n                if (range.Start.iLine > 0)\n                    tb[range.Start.iLine - 1].FoldingEndMarker = foldingPattern;\n                tb[range.Start.iLine].FoldingStartMarker = foldingPattern;\n            }\n\n            tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex pattern\n        /// </summary>\n        /// <param name=\"regexPattern\">Regex pattern</param>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRanges(string regexPattern)\n        {\n            return GetRanges(regexPattern, RegexOptions.None);\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex pattern\n        /// </summary>\n        /// <param name=\"regexPattern\">Regex pattern</param>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRanges(string regexPattern, RegexOptions options)\n        {\n            //get text\n            string text;\n            List<Place> charIndexToPlace;\n            GetText(out text, out charIndexToPlace);\n            //create regex\n            Regex regex = new Regex(regexPattern, options);\n            //\n            foreach (Match m in regex.Matches(text))\n            {\n                Range r = new Range(this.tb);\n                //try get 'range' group, otherwise use group 0\n                Group group = m.Groups[\"range\"];\n                if (!group.Success)\n                    group = m.Groups[0];\n                //\n                r.Start = charIndexToPlace[group.Index];\n                r.End = charIndexToPlace[group.Index + group.Length];\n                yield return r;\n            }\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex pattern.\n        /// Search is separately in each line.\n        /// This method requires less memory than GetRanges().\n        /// </summary>\n        /// <param name=\"regexPattern\">Regex pattern</param>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRangesByLines(string regexPattern, RegexOptions options)\n        {\n            var regex = new Regex(regexPattern, options);\n            foreach (var r in GetRangesByLines(regex))\n                yield return r;\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex.\n        /// Search is separately in each line.\n        /// This method requires less memory than GetRanges().\n        /// </summary>\n        /// <param name=\"regex\">Regex</param>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRangesByLines(Regex regex)\n        {\n            Normalize();\n\n            var fts = tb.TextSource as FileTextSource; //<----!!!! ugly\n\n            //enumaerate lines\n            for (int iLine = Start.iLine; iLine <= End.iLine; iLine++)\n            {\n                //\n                bool isLineLoaded = fts != null ? fts.IsLineLoaded(iLine) : true;\n                //\n                var r = new Range(tb, new Place(0, iLine), new Place(tb[iLine].Count, iLine));\n                if (iLine == Start.iLine || iLine == End.iLine)\n                    r = r.GetIntersectionWith(this);\n\n                foreach (var foundRange in r.GetRanges(regex))\n                    yield return foundRange;\n\n                if (!isLineLoaded)\n                    fts.UnloadLine(iLine);\n            }\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex pattern.\n        /// Search is separately in each line (order of lines is reversed).\n        /// This method requires less memory than GetRanges().\n        /// </summary>\n        /// <param name=\"regexPattern\">Regex pattern</param>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRangesByLinesReversed(string regexPattern, RegexOptions options)\n        {\n            Normalize();\n            //create regex\n            Regex regex = new Regex(regexPattern, options);\n            //\n            var fts = tb.TextSource as FileTextSource; //<----!!!! ugly\n\n            //enumaerate lines\n            for (int iLine = End.iLine; iLine >= Start.iLine; iLine--)\n            {\n                //\n                bool isLineLoaded = fts != null ? fts.IsLineLoaded(iLine) : true;\n                //\n                var r = new Range(tb, new Place(0, iLine), new Place(tb[iLine].Count, iLine));\n                if (iLine == Start.iLine || iLine == End.iLine)\n                    r = r.GetIntersectionWith(this);\n\n                var list = new List<Range>();\n\n                foreach (var foundRange in r.GetRanges(regex))\n                    list.Add(foundRange);\n\n                for (int i = list.Count - 1; i >= 0; i--)\n                    yield return list[i];\n\n                if (!isLineLoaded)\n                    fts.UnloadLine(iLine);\n            }\n        }\n\n        /// <summary>\n        /// Finds ranges for given regex\n        /// </summary>\n        /// <returns>Enumeration of ranges</returns>\n        public IEnumerable<Range> GetRanges(Regex regex)\n        {\n            //get text\n            string text;\n            List<Place> charIndexToPlace;\n            GetText(out text, out charIndexToPlace);\n            //\n            foreach (Match m in regex.Matches(text))\n            {\n                Range r = new Range(this.tb);\n                //try get 'range' group, otherwise use group 0\n                Group group = m.Groups[\"range\"];\n                if (!group.Success)\n                    group = m.Groups[0];\n                //\n                r.Start = charIndexToPlace[group.Index];\n                r.End = charIndexToPlace[group.Index + group.Length];\n                yield return r;\n            }\n        }\n\n        /// <summary>\n        /// Clear styles of range\n        /// </summary>\n        public void ClearStyle(params Style[] styles)\n        {\n            try\n            {\n                ClearStyle(tb.GetStyleIndexMask(styles));\n            }\n            catch\n            {\n                ;\n            }\n        }\n\n        /// <summary>\n        /// Clear styles of range\n        /// </summary>\n        public void ClearStyle(StyleIndex styleIndex)\n        {\n            //set code to chars\n            int fromLine = Math.Min(End.iLine, Start.iLine);\n            int toLine = Math.Max(End.iLine, Start.iLine);\n            int fromChar = FromX;\n            int toChar = ToX;\n            if (fromLine < 0) return;\n            //\n            for (int y = fromLine; y <= toLine; y++)\n            {\n                int fromX = y == fromLine ? fromChar : 0;\n                int toX = y == toLine ? Math.Min(toChar - 1, tb[y].Count - 1) : tb[y].Count - 1;\n                for (int x = fromX; x <= toX; x++)\n                {\n                    Char c = tb[y][x];\n                    c.style &= ~styleIndex;\n                    tb[y][x] = c;\n                }\n            }\n\n            //\n            tb.Invalidate();\n        }\n\n        /// <summary>\n        /// Clear folding markers of all lines of range\n        /// </summary>\n        public void ClearFoldingMarkers()\n        {\n            //set code to chars\n            int fromLine = Math.Min(End.iLine, Start.iLine);\n            int toLine = Math.Max(End.iLine, Start.iLine);\n            if (fromLine < 0) return;\n            //\n            for (int y = fromLine; y <= toLine; y++)\n                tb[y].ClearFoldingMarkers();\n            //\n            tb.Invalidate();\n        }\n\n        void OnSelectionChanged()\n        {\n            //clear cache\n            cachedTextVersion = -1;\n            cachedText = null;\n            cachedCharIndexToPlace = null;\n            //\n            if (tb.Selection == this)\n                if (updating == 0)\n                    tb.OnSelectionChanged();\n        }\n\n        /// <summary>\n        /// Starts selection position updating\n        /// </summary>\n        public void BeginUpdate()\n        {\n            updating++;\n        }\n\n        /// <summary>\n        /// Ends selection position updating\n        /// </summary>\n        public void EndUpdate()\n        {\n            updating--;\n            if (updating == 0)\n                OnSelectionChanged();\n        }\n\n        public override string ToString()\n        {\n            return \"Start: \" + Start + \" End: \" + End;\n        }\n\n        /// <summary>\n        /// Exchanges Start and End if End appears before Start\n        /// </summary>\n        public void Normalize()\n        {\n            if (Start > End)\n                Inverse();\n        }\n\n        /// <summary>\n        /// Exchanges Start and End\n        /// </summary>\n        public void Inverse()\n        {\n            var temp = start;\n            start = end;\n            end = temp;\n        }\n\n        /// <summary>\n        /// Expands range from first char of Start line to last char of End line\n        /// </summary>\n        public void Expand()\n        {\n            Normalize();\n            start = new Place(0, start.iLine);\n            end = new Place(tb.GetLineLength(end.iLine), end.iLine);\n        }\n\n        IEnumerator<Place> IEnumerable<Place>.GetEnumerator()\n        {\n            if (ColumnSelectionMode)\n            {\n                foreach (var p in GetEnumerator_ColumnSelectionMode())\n                    yield return p;\n                yield break;\n            }\n\n            int fromLine = Math.Min(end.iLine, start.iLine);\n            int toLine = Math.Max(end.iLine, start.iLine);\n            int fromChar = FromX;\n            int toChar = ToX;\n            if (fromLine < 0) yield break;\n            //\n            for (int y = fromLine; y <= toLine; y++)\n            {\n                int fromX = y == fromLine ? fromChar : 0;\n                int toX = y == toLine ? Math.Min(toChar - 1, tb[y].Count - 1) : tb[y].Count - 1;\n                for (int x = fromX; x <= toX; x++)\n                    yield return new Place(x, y);\n            }\n        }\n\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n        {\n            return (this as IEnumerable<Place>).GetEnumerator();\n        }\n\n        /// <summary>\n        /// Chars of range (exclude \\n)\n        /// </summary>\n        public IEnumerable<Char> Chars\n        {\n            get\n            {\n                if (ColumnSelectionMode)\n                {\n                    foreach (var p in GetEnumerator_ColumnSelectionMode())\n                        yield return tb[p];\n                    yield break;\n                }\n\n                int fromLine = Math.Min(end.iLine, start.iLine);\n                int toLine = Math.Max(end.iLine, start.iLine);\n                int fromChar = FromX;\n                int toChar = ToX;\n                if (fromLine < 0) yield break;\n                //\n                for (int y = fromLine; y <= toLine; y++)\n                {\n                    int fromX = y == fromLine ? fromChar : 0;\n                    int toX = y == toLine ? Math.Min(toChar - 1, tb[y].Count - 1) : tb[y].Count - 1;\n                    var line = tb[y];\n                    for (int x = fromX; x <= toX; x++)\n                        yield return line[x];\n                }\n            }\n        }\n\n        /// <summary>\n        /// Get fragment of text around Start place. Returns maximal matched to pattern fragment.\n        /// </summary>\n        /// <param name=\"allowedSymbolsPattern\">Allowed chars pattern for fragment</param>\n        /// <returns>Range of found fragment</returns>\n        public Range GetFragment(string allowedSymbolsPattern)\n        {\n            return GetFragment(allowedSymbolsPattern, RegexOptions.None);\n        }\n\n        /// <summary>\n        /// Get fragment of text around Start place. Returns maximal matched to given Style.\n        /// </summary>\n        /// <param name=\"style\">Allowed style for fragment</param>\n        /// <returns>Range of found fragment</returns>\n        public Range GetFragment(Style style, bool allowLineBreaks)\n        {\n            var mask = tb.GetStyleIndexMask(new Style[] {style});\n            //\n            Range r = new Range(tb);\n            r.Start = Start;\n            //go left, check style\n            while (r.GoLeftThroughFolded())\n            {\n                if (!allowLineBreaks && r.CharAfterStart == '\\n')\n                    break;\n                if (r.Start.iChar < tb.GetLineLength(r.Start.iLine))\n                    if ((tb[r.Start].style & mask) == 0)\n                    {\n                        r.GoRightThroughFolded();\n                        break;\n                    }\n            }\n\n            Place startFragment = r.Start;\n\n            r.Start = Start;\n            //go right, check style\n            do\n            {\n                if (!allowLineBreaks && r.CharAfterStart == '\\n')\n                    break;\n                if (r.Start.iChar < tb.GetLineLength(r.Start.iLine))\n                    if ((tb[r.Start].style & mask) == 0)\n                        break;\n            } while (r.GoRightThroughFolded());\n\n            Place endFragment = r.Start;\n\n            return new Range(tb, startFragment, endFragment);\n        }\n\n        /// <summary>\n        /// Get fragment of text around Start place. Returns maximal mathed to pattern fragment.\n        /// </summary>\n        /// <param name=\"allowedSymbolsPattern\">Allowed chars pattern for fragment</param>\n        /// <returns>Range of found fragment</returns>\n        public Range GetFragment(string allowedSymbolsPattern, RegexOptions options)\n        {\n            Range r = new Range(tb);\n            r.Start = Start;\n            Regex regex = new Regex(allowedSymbolsPattern, options);\n            //go left, check symbols\n            while (r.GoLeftThroughFolded())\n            {\n                if (!regex.IsMatch(r.CharAfterStart.ToString()))\n                {\n                    r.GoRightThroughFolded();\n                    break;\n                }\n            }\n\n            Place startFragment = r.Start;\n\n            r.Start = Start;\n            //go right, check symbols\n            do\n            {\n                if (!regex.IsMatch(r.CharAfterStart.ToString()))\n                    break;\n            } while (r.GoRightThroughFolded());\n\n            Place endFragment = r.Start;\n\n            return new Range(tb, startFragment, endFragment);\n        }\n\n        bool IsIdentifierChar(char c)\n        {\n            return char.IsLetterOrDigit(c) || c == '_';\n        }\n\n        bool IsSpaceChar(char c)\n        {\n            return c == ' ' || c == '\\t';\n        }\n\n        public void GoWordLeft(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            if (!shift && start > end)\n            {\n                Start = End;\n                return;\n            }\n\n            Range range = this.Clone(); //to OnSelectionChanged disable\n            bool wasSpace = false;\n            while (IsSpaceChar(range.CharBeforeStart))\n            {\n                wasSpace = true;\n                range.GoLeft(shift);\n            }\n\n            bool wasIdentifier = false;\n            while (IsIdentifierChar(range.CharBeforeStart))\n            {\n                wasIdentifier = true;\n                range.GoLeft(shift);\n            }\n\n            if (!wasIdentifier && (!wasSpace || range.CharBeforeStart != '\\n'))\n                range.GoLeft(shift);\n            this.Start = range.Start;\n            this.End = range.End;\n\n            if (tb.LineInfos[Start.iLine].VisibleState != VisibleState.Visible)\n                GoRight(shift);\n        }\n\n        public void GoWordRight(bool shift, bool goToStartOfNextWord = false)\n        {\n            ColumnSelectionMode = false;\n\n            if (!shift && start < end)\n            {\n                Start = End;\n                return;\n            }\n\n            Range range = this.Clone(); //to OnSelectionChanged disable\n\n            bool wasNewLine = false;\n\n\n            if (range.CharAfterStart == '\\n')\n            {\n                range.GoRight(shift);\n                wasNewLine = true;\n            }\n\n            bool wasSpace = false;\n            while (IsSpaceChar(range.CharAfterStart))\n            {\n                wasSpace = true;\n                range.GoRight(shift);\n            }\n\n            if (!((wasSpace || wasNewLine) && goToStartOfNextWord))\n            {\n                bool wasIdentifier = false;\n                while (IsIdentifierChar(range.CharAfterStart))\n                {\n                    wasIdentifier = true;\n                    range.GoRight(shift);\n                }\n\n                if (!wasIdentifier)\n                    range.GoRight(shift);\n\n                if (goToStartOfNextWord && !wasSpace)\n                    while (IsSpaceChar(range.CharAfterStart))\n                        range.GoRight(shift);\n            }\n\n            this.Start = range.Start;\n            this.End = range.End;\n\n            if (tb.LineInfos[Start.iLine].VisibleState != VisibleState.Visible)\n                GoLeft(shift);\n        }\n\n        internal void GoFirst(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            start = new Place(0, 0);\n            if (tb.LineInfos[Start.iLine].VisibleState != VisibleState.Visible)\n                tb.ExpandBlock(Start.iLine);\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n        }\n\n        internal void GoLast(bool shift)\n        {\n            ColumnSelectionMode = false;\n\n            start = new Place(tb[tb.LinesCount - 1].Count, tb.LinesCount - 1);\n            if (tb.LineInfos[Start.iLine].VisibleState != VisibleState.Visible)\n                tb.ExpandBlock(Start.iLine);\n\n            if (!shift)\n                end = start;\n\n            OnSelectionChanged();\n        }\n\n        public static StyleIndex ToStyleIndex(int i)\n        {\n            return (StyleIndex) (1 << i);\n        }\n\n        public RangeRect Bounds\n        {\n            get\n            {\n                int minX = Math.Min(Start.iChar, End.iChar);\n                int minY = Math.Min(Start.iLine, End.iLine);\n                int maxX = Math.Max(Start.iChar, End.iChar);\n                int maxY = Math.Max(Start.iLine, End.iLine);\n                return new RangeRect(minY, minX, maxY, maxX);\n            }\n        }\n\n        public IEnumerable<Range> GetSubRanges(bool includeEmpty)\n        {\n            if (!ColumnSelectionMode)\n            {\n                yield return this;\n                yield break;\n            }\n\n            var rect = Bounds;\n            for (int y = rect.iStartLine; y <= rect.iEndLine; y++)\n            {\n                if (rect.iStartChar > tb[y].Count && !includeEmpty)\n                    continue;\n\n                var r = new Range(tb, rect.iStartChar, y, Math.Min(rect.iEndChar, tb[y].Count), y);\n                yield return r;\n            }\n        }\n\n        /// <summary>\n        /// Range is readonly?\n        /// This property return True if any char of the range contains ReadOnlyStyle.\n        /// Set this property to True/False to mark chars of the range as Readonly/Writable.\n        /// </summary>\n        public bool ReadOnly\n        {\n            get\n            {\n                if (tb.ReadOnly) return true;\n\n                ReadOnlyStyle readonlyStyle = null;\n                foreach (var style in tb.Styles)\n                    if (style is ReadOnlyStyle)\n                    {\n                        readonlyStyle = (ReadOnlyStyle) style;\n                        break;\n                    }\n\n                if (readonlyStyle != null)\n                {\n                    var si = ToStyleIndex(tb.GetStyleIndex(readonlyStyle));\n\n                    if (IsEmpty)\n                    {\n                        //check previous and next chars\n                        var line = tb[start.iLine];\n                        if (columnSelectionMode)\n                        {\n                            foreach (var sr in GetSubRanges(false))\n                            {\n                                line = tb[sr.start.iLine];\n                                if (sr.start.iChar < line.Count && sr.start.iChar > 0)\n                                {\n                                    var left = line[sr.start.iChar - 1];\n                                    var right = line[sr.start.iChar];\n                                    if ((left.style & si) != 0 &&\n                                        (right.style & si) != 0) return true; //we are between readonly chars\n                                }\n                            }\n                        }\n                        else if (start.iChar < line.Count && start.iChar > 0)\n                        {\n                            var left = line[start.iChar - 1];\n                            var right = line[start.iChar];\n                            if ((left.style & si) != 0 &&\n                                (right.style & si) != 0) return true; //we are between readonly chars\n                        }\n                    }\n                    else\n                        foreach (Char c in Chars)\n                            if ((c.style & si) != 0) //found char with ReadonlyStyle\n                                return true;\n                }\n\n                return false;\n            }\n\n            set\n            {\n                //find exists ReadOnlyStyle of style buffer\n                ReadOnlyStyle readonlyStyle = null;\n                foreach (var style in tb.Styles)\n                    if (style is ReadOnlyStyle)\n                    {\n                        readonlyStyle = (ReadOnlyStyle) style;\n                        break;\n                    }\n\n                //create ReadOnlyStyle\n                if (readonlyStyle == null)\n                    readonlyStyle = new ReadOnlyStyle();\n\n                //set/clear style\n                if (value)\n                    SetStyle(readonlyStyle);\n                else\n                    ClearStyle(readonlyStyle);\n            }\n        }\n\n        /// <summary>\n        /// Is char before range readonly\n        /// </summary>\n        /// <returns></returns>\n        public bool IsReadOnlyLeftChar()\n        {\n            if (tb.ReadOnly) return true;\n\n            var r = Clone();\n\n            r.Normalize();\n            if (r.start.iChar == 0) return false;\n            if (ColumnSelectionMode)\n                r.GoLeft_ColumnSelectionMode();\n            else\n                r.GoLeft(true);\n\n            return r.ReadOnly;\n        }\n\n        /// <summary>\n        /// Is char after range readonly\n        /// </summary>\n        /// <returns></returns>\n        public bool IsReadOnlyRightChar()\n        {\n            if (tb.ReadOnly) return true;\n\n            var r = Clone();\n\n            r.Normalize();\n            if (r.end.iChar >= tb[end.iLine].Count) return false;\n            if (ColumnSelectionMode)\n                r.GoRight_ColumnSelectionMode();\n            else\n                r.GoRight(true);\n\n            return r.ReadOnly;\n        }\n\n        public IEnumerable<Place> GetPlacesCyclic(Place startPlace, bool backward = false)\n        {\n            if (backward)\n            {\n                var r = new Range(this.tb, startPlace, startPlace);\n                while (r.GoLeft() && r.start >= Start)\n                {\n                    if (r.Start.iChar < tb[r.Start.iLine].Count)\n                        yield return r.Start;\n                }\n\n                r = new Range(this.tb, End, End);\n                while (r.GoLeft() && r.start >= startPlace)\n                {\n                    if (r.Start.iChar < tb[r.Start.iLine].Count)\n                        yield return r.Start;\n                }\n            }\n            else\n            {\n                var r = new Range(this.tb, startPlace, startPlace);\n                if (startPlace < End)\n                    do\n                    {\n                        if (r.Start.iChar < tb[r.Start.iLine].Count)\n                            yield return r.Start;\n                    } while (r.GoRight());\n\n                r = new Range(this.tb, Start, Start);\n                if (r.Start < startPlace)\n                    do\n                    {\n                        if (r.Start.iChar < tb[r.Start.iLine].Count)\n                            yield return r.Start;\n                    } while (r.GoRight() && r.Start < startPlace);\n            }\n        }\n\n        #region ColumnSelectionMode\n\n        private Range GetIntersectionWith_ColumnSelectionMode(Range range)\n        {\n            if (range.Start.iLine != range.End.iLine)\n                return new Range(tb, Start, Start);\n            var rect = Bounds;\n            if (range.Start.iLine < rect.iStartLine || range.Start.iLine > rect.iEndLine)\n                return new Range(tb, Start, Start);\n\n            return new Range(tb, rect.iStartChar, range.Start.iLine, rect.iEndChar, range.Start.iLine)\n                .GetIntersectionWith(range);\n        }\n\n        private bool GoRightThroughFolded_ColumnSelectionMode()\n        {\n            var boundes = Bounds;\n            var endOfLines = true;\n            for (int iLine = boundes.iStartLine; iLine <= boundes.iEndLine; iLine++)\n                if (boundes.iEndChar < tb[iLine].Count)\n                {\n                    endOfLines = false;\n                    break;\n                }\n\n            if (endOfLines)\n                return false;\n\n            var start = Start;\n            var end = End;\n            start.Offset(1, 0);\n            end.Offset(1, 0);\n            BeginUpdate();\n            Start = start;\n            End = end;\n            EndUpdate();\n\n            return true;\n        }\n\n        private IEnumerable<Place> GetEnumerator_ColumnSelectionMode()\n        {\n            var bounds = Bounds;\n            if (bounds.iStartLine < 0) yield break;\n            //\n            for (int y = bounds.iStartLine; y <= bounds.iEndLine; y++)\n            {\n                for (int x = bounds.iStartChar; x < bounds.iEndChar; x++)\n                {\n                    if (x < tb[y].Count)\n                        yield return new Place(x, y);\n                }\n            }\n        }\n\n        private string Text_ColumnSelectionMode\n        {\n            get\n            {\n                StringBuilder sb = new StringBuilder();\n                var bounds = Bounds;\n                if (bounds.iStartLine < 0) return \"\";\n                //\n                for (int y = bounds.iStartLine; y <= bounds.iEndLine; y++)\n                {\n                    for (int x = bounds.iStartChar; x < bounds.iEndChar; x++)\n                    {\n                        if (x < tb[y].Count)\n                            sb.Append(tb[y][x].c);\n                    }\n\n                    if (bounds.iEndLine != bounds.iStartLine && y != bounds.iEndLine)\n                        sb.AppendLine();\n                }\n\n                return sb.ToString();\n            }\n        }\n\n        private int Length_ColumnSelectionMode(bool withNewLines)\n        {\n            var bounds = Bounds;\n            if (bounds.iStartLine < 0) return 0;\n            int cnt = 0;\n            //\n            for (int y = bounds.iStartLine; y <= bounds.iEndLine; y++)\n            {\n                for (int x = bounds.iStartChar; x < bounds.iEndChar; x++)\n                {\n                    if (x < tb[y].Count)\n                        cnt++;\n                }\n\n                if (withNewLines && bounds.iEndLine != bounds.iStartLine && y != bounds.iEndLine)\n                    cnt += Environment.NewLine.Length;\n            }\n\n            return cnt;\n        }\n\n        internal void GoDown_ColumnSelectionMode()\n        {\n            var iLine = tb.FindNextVisibleLine(End.iLine);\n            End = new Place(End.iChar, iLine);\n        }\n\n        internal void GoUp_ColumnSelectionMode()\n        {\n            var iLine = tb.FindPrevVisibleLine(End.iLine);\n            End = new Place(End.iChar, iLine);\n        }\n\n        internal void GoRight_ColumnSelectionMode()\n        {\n            End = new Place(End.iChar + 1, End.iLine);\n        }\n\n        internal void GoLeft_ColumnSelectionMode()\n        {\n            if (End.iChar > 0)\n                End = new Place(End.iChar - 1, End.iLine);\n        }\n\n        #endregion\n    }\n\n    public struct RangeRect\n    {\n        public RangeRect(int iStartLine, int iStartChar, int iEndLine, int iEndChar)\n        {\n            this.iStartLine = iStartLine;\n            this.iStartChar = iStartChar;\n            this.iEndLine = iEndLine;\n            this.iEndChar = iEndChar;\n        }\n\n        public int iStartLine;\n        public int iStartChar;\n        public int iEndLine;\n        public int iEndChar;\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/ReplaceForm.Designer.cs",
    "content": "﻿namespace FastColoredTextBoxNS\n{\n    partial class ReplaceForm\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.btClose = new System.Windows.Forms.Button();\n            this.btFindNext = new System.Windows.Forms.Button();\n            this.tbFind = new System.Windows.Forms.TextBox();\n            this.cbRegex = new System.Windows.Forms.CheckBox();\n            this.cbMatchCase = new System.Windows.Forms.CheckBox();\n            this.label1 = new System.Windows.Forms.Label();\n            this.cbWholeWord = new System.Windows.Forms.CheckBox();\n            this.btReplace = new System.Windows.Forms.Button();\n            this.btReplaceAll = new System.Windows.Forms.Button();\n            this.label2 = new System.Windows.Forms.Label();\n            this.tbReplace = new System.Windows.Forms.TextBox();\n            this.SuspendLayout();\n            // \n            // btClose\n            // \n            this.btClose.Location = new System.Drawing.Point(273, 153);\n            this.btClose.Name = \"btClose\";\n            this.btClose.Size = new System.Drawing.Size(75, 23);\n            this.btClose.TabIndex = 8;\n            this.btClose.Text = \"Close\";\n            this.btClose.UseVisualStyleBackColor = true;\n            this.btClose.Click += new System.EventHandler(this.btClose_Click);\n            // \n            // btFindNext\n            // \n            this.btFindNext.Location = new System.Drawing.Point(111, 124);\n            this.btFindNext.Name = \"btFindNext\";\n            this.btFindNext.Size = new System.Drawing.Size(75, 23);\n            this.btFindNext.TabIndex = 5;\n            this.btFindNext.Text = \"Find next\";\n            this.btFindNext.UseVisualStyleBackColor = true;\n            this.btFindNext.Click += new System.EventHandler(this.btFindNext_Click);\n            // \n            // tbFind\n            // \n            this.tbFind.Location = new System.Drawing.Point(62, 12);\n            this.tbFind.Name = \"tbFind\";\n            this.tbFind.Size = new System.Drawing.Size(286, 20);\n            this.tbFind.TabIndex = 0;\n            this.tbFind.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            this.tbFind.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);\n            // \n            // cbRegex\n            // \n            this.cbRegex.AutoSize = true;\n            this.cbRegex.Location = new System.Drawing.Point(273, 38);\n            this.cbRegex.Name = \"cbRegex\";\n            this.cbRegex.Size = new System.Drawing.Size(57, 17);\n            this.cbRegex.TabIndex = 3;\n            this.cbRegex.Text = \"Regex\";\n            this.cbRegex.UseVisualStyleBackColor = true;\n            this.cbRegex.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            // \n            // cbMatchCase\n            // \n            this.cbMatchCase.AutoSize = true;\n            this.cbMatchCase.Location = new System.Drawing.Point(66, 38);\n            this.cbMatchCase.Name = \"cbMatchCase\";\n            this.cbMatchCase.Size = new System.Drawing.Size(82, 17);\n            this.cbMatchCase.TabIndex = 1;\n            this.cbMatchCase.Text = \"Match case\";\n            this.cbMatchCase.UseVisualStyleBackColor = true;\n            this.cbMatchCase.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            // \n            // label1\n            // \n            this.label1.AutoSize = true;\n            this.label1.Location = new System.Drawing.Point(23, 14);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(33, 13);\n            this.label1.TabIndex = 5;\n            this.label1.Text = \"Find: \";\n            // \n            // cbWholeWord\n            // \n            this.cbWholeWord.AutoSize = true;\n            this.cbWholeWord.Location = new System.Drawing.Point(154, 38);\n            this.cbWholeWord.Name = \"cbWholeWord\";\n            this.cbWholeWord.Size = new System.Drawing.Size(113, 17);\n            this.cbWholeWord.TabIndex = 2;\n            this.cbWholeWord.Text = \"Match whole word\";\n            this.cbWholeWord.UseVisualStyleBackColor = true;\n            this.cbWholeWord.CheckedChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            // \n            // btReplace\n            // \n            this.btReplace.Location = new System.Drawing.Point(192, 124);\n            this.btReplace.Name = \"btReplace\";\n            this.btReplace.Size = new System.Drawing.Size(75, 23);\n            this.btReplace.TabIndex = 6;\n            this.btReplace.Text = \"Replace\";\n            this.btReplace.UseVisualStyleBackColor = true;\n            this.btReplace.Click += new System.EventHandler(this.btReplace_Click);\n            // \n            // btReplaceAll\n            // \n            this.btReplaceAll.Location = new System.Drawing.Point(273, 124);\n            this.btReplaceAll.Name = \"btReplaceAll\";\n            this.btReplaceAll.Size = new System.Drawing.Size(75, 23);\n            this.btReplaceAll.TabIndex = 7;\n            this.btReplaceAll.Text = \"Replace all\";\n            this.btReplaceAll.UseVisualStyleBackColor = true;\n            this.btReplaceAll.Click += new System.EventHandler(this.btReplaceAll_Click);\n            // \n            // label2\n            // \n            this.label2.AutoSize = true;\n            this.label2.Location = new System.Drawing.Point(6, 81);\n            this.label2.Name = \"label2\";\n            this.label2.Size = new System.Drawing.Size(50, 13);\n            this.label2.TabIndex = 9;\n            this.label2.Text = \"Replace:\";\n            // \n            // tbReplace\n            // \n            this.tbReplace.Location = new System.Drawing.Point(62, 78);\n            this.tbReplace.Name = \"tbReplace\";\n            this.tbReplace.Size = new System.Drawing.Size(286, 20);\n            this.tbReplace.TabIndex = 0;\n            this.tbReplace.TextChanged += new System.EventHandler(this.cbMatchCase_CheckedChanged);\n            this.tbReplace.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbFind_KeyPress);\n            // \n            // ReplaceForm\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(360, 191);\n            this.Controls.Add(this.tbFind);\n            this.Controls.Add(this.label2);\n            this.Controls.Add(this.tbReplace);\n            this.Controls.Add(this.btReplaceAll);\n            this.Controls.Add(this.btReplace);\n            this.Controls.Add(this.cbWholeWord);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.cbMatchCase);\n            this.Controls.Add(this.cbRegex);\n            this.Controls.Add(this.btFindNext);\n            this.Controls.Add(this.btClose);\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;\n            this.Name = \"ReplaceForm\";\n            this.ShowIcon = false;\n            this.ShowInTaskbar = false;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\n            this.Text = \"Find and replace\";\n            this.TopMost = true;\n            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ReplaceForm_FormClosing);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.Button btClose;\n        private System.Windows.Forms.Button btFindNext;\n        private System.Windows.Forms.CheckBox cbRegex;\n        private System.Windows.Forms.CheckBox cbMatchCase;\n        private System.Windows.Forms.Label label1;\n        private System.Windows.Forms.CheckBox cbWholeWord;\n        private System.Windows.Forms.Button btReplace;\n        private System.Windows.Forms.Button btReplaceAll;\n        private System.Windows.Forms.Label label2;\n        public System.Windows.Forms.TextBox tbFind;\n        public System.Windows.Forms.TextBox tbReplace;\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/ReplaceForm.cs",
    "content": "﻿using System;\nusing System.Windows.Forms;\nusing System.Text.RegularExpressions;\nusing System.Collections.Generic;\n\nnamespace FastColoredTextBoxNS\n{\n    public partial class ReplaceForm : Form\n    {\n        FastColoredTextBox tb;\n        bool firstSearch = true;\n        Place startPlace;\n\n        public ReplaceForm(FastColoredTextBox tb)\n        {\n            InitializeComponent();\n            this.tb = tb;\n        }\n\n        private void btClose_Click(object sender, EventArgs e)\n        {\n            Close();\n        }\n\n        private void btFindNext_Click(object sender, EventArgs e)\n        {\n            try\n            {\n                if (!Find(tbFind.Text))\n                    MessageBox.Show(\"Not found\");\n            }\n            catch (Exception ex)\n            {\n                MessageBox.Show(ex.Message);\n            }\n        }\n\n        public List<Range> FindAll(string pattern)\n        {\n            var opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;\n            if (!cbRegex.Checked)\n                pattern = Regex.Escape(pattern);\n            if (cbWholeWord.Checked)\n                pattern = \"\\\\b\" + pattern + \"\\\\b\";\n            //\n            var range = tb.Selection.IsEmpty ? tb.Range.Clone() : tb.Selection.Clone();\n            //\n            var list = new List<Range>();\n            foreach (var r in range.GetRangesByLines(pattern, opt))\n                list.Add(r);\n\n            return list;\n        }\n\n        public bool Find(string pattern)\n        {\n            RegexOptions opt = cbMatchCase.Checked ? RegexOptions.None : RegexOptions.IgnoreCase;\n            if (!cbRegex.Checked)\n                pattern = Regex.Escape(pattern);\n            if (cbWholeWord.Checked)\n                pattern = \"\\\\b\" + pattern + \"\\\\b\";\n            //\n            Range range = tb.Selection.Clone();\n            range.Normalize();\n            //\n            if (firstSearch)\n            {\n                startPlace = range.Start;\n                firstSearch = false;\n            }\n\n            //\n            range.Start = range.End;\n            if (range.Start >= startPlace)\n                range.End = new Place(tb.GetLineLength(tb.LinesCount - 1), tb.LinesCount - 1);\n            else\n                range.End = startPlace;\n            //\n            foreach (var r in range.GetRangesByLines(pattern, opt))\n            {\n                tb.Selection.Start = r.Start;\n                tb.Selection.End = r.End;\n                tb.DoSelectionVisible();\n                tb.Invalidate();\n                return true;\n            }\n\n            if (range.Start >= startPlace && startPlace > Place.Empty)\n            {\n                tb.Selection.Start = new Place(0, 0);\n                return Find(pattern);\n            }\n\n            return false;\n        }\n\n        private void tbFind_KeyPress(object sender, KeyPressEventArgs e)\n        {\n            if (e.KeyChar == '\\r')\n                btFindNext_Click(sender, null);\n            if (e.KeyChar == '\\x1b')\n                Hide();\n        }\n\n        protected override bool ProcessCmdKey(ref Message msg, Keys keyData) // David\n        {\n            if (keyData == Keys.Escape)\n            {\n                this.Close();\n                return true;\n            }\n\n            return base.ProcessCmdKey(ref msg, keyData);\n        }\n\n        private void ReplaceForm_FormClosing(object sender, FormClosingEventArgs e)\n        {\n            if (e.CloseReason == CloseReason.UserClosing)\n            {\n                e.Cancel = true;\n                Hide();\n            }\n\n            this.tb.Focus();\n        }\n\n        private void btReplace_Click(object sender, EventArgs e)\n        {\n            try\n            {\n                if (tb.SelectionLength != 0)\n                    if (!tb.Selection.ReadOnly)\n                        tb.InsertText(tbReplace.Text);\n                btFindNext_Click(sender, null);\n            }\n            catch (Exception ex)\n            {\n                MessageBox.Show(ex.Message);\n            }\n        }\n\n        private void btReplaceAll_Click(object sender, EventArgs e)\n        {\n            try\n            {\n                tb.Selection.BeginUpdate();\n\n                //search\n                var ranges = FindAll(tbFind.Text);\n                //check readonly\n                var ro = false;\n                foreach (var r in ranges)\n                    if (r.ReadOnly)\n                    {\n                        ro = true;\n                        break;\n                    }\n\n                //replace\n                if (!ro)\n                    if (ranges.Count > 0)\n                    {\n                        tb.TextSource.Manager.ExecuteCommand(new ReplaceTextCommand(tb.TextSource, ranges,\n                            tbReplace.Text));\n                        tb.Selection.Start = new Place(0, 0);\n                    }\n\n                //\n                tb.Invalidate();\n                MessageBox.Show(ranges.Count + \" occurrence(s) replaced\");\n            }\n            catch (Exception ex)\n            {\n                MessageBox.Show(ex.Message);\n            }\n\n            tb.Selection.EndUpdate();\n        }\n\n        protected override void OnActivated(EventArgs e)\n        {\n            tbFind.Focus();\n            ResetSerach();\n        }\n\n        void ResetSerach()\n        {\n            firstSearch = true;\n        }\n\n        private void cbMatchCase_CheckedChanged(object sender, EventArgs e)\n        {\n            ResetSerach();\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/ReplaceForm.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "FastColoredTextBox/Ruler.Designer.cs",
    "content": "﻿namespace FastColoredTextBoxNS\n{\n    partial class Ruler\n    {\n        /// <summary> \n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary> \n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Component Designer generated code\n\n        /// <summary> \n        /// Required method for Designer support - do not modify \n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            components = new System.ComponentModel.Container();\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "FastColoredTextBox/Ruler.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Drawing;\nusing System.Data;\nusing System.Drawing.Drawing2D;\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    public partial class Ruler : UserControl\n    {\n        public EventHandler TargetChanged;\n\n        [DefaultValue(typeof(Color), \"ControlLight\")]\n        public Color BackColor2 { get; set; }\n\n        [DefaultValue(typeof(Color), \"DarkGray\")]\n        public Color TickColor { get; set; }\n\n        [DefaultValue(typeof(Color), \"Black\")] public Color CaretTickColor { get; set; }\n\n        FastColoredTextBox target;\n\n        [Description(\"Target FastColoredTextBox\")]\n        public FastColoredTextBox Target\n        {\n            get { return target; }\n            set\n            {\n                if (target != null)\n                    UnSubscribe(target);\n                target = value;\n                Subscribe(target);\n                OnTargetChanged();\n            }\n        }\n\n        public Ruler()\n        {\n            InitializeComponent();\n\n            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint,\n                true);\n            MinimumSize = new Size(0, 24);\n            MaximumSize = new Size(int.MaxValue / 2, 24);\n\n            BackColor2 = SystemColors.ControlLight;\n            TickColor = Color.DarkGray;\n            CaretTickColor = Color.Black;\n        }\n\n\n        protected virtual void OnTargetChanged()\n        {\n            if (TargetChanged != null)\n                TargetChanged(this, EventArgs.Empty);\n        }\n\n        protected virtual void UnSubscribe(FastColoredTextBox target)\n        {\n            target.Scroll -= new ScrollEventHandler(target_Scroll);\n            target.SelectionChanged -= new EventHandler(target_SelectionChanged);\n            target.VisibleRangeChanged -= new EventHandler(target_VisibleRangeChanged);\n        }\n\n        protected virtual void Subscribe(FastColoredTextBox target)\n        {\n            target.Scroll += new ScrollEventHandler(target_Scroll);\n            target.SelectionChanged += new EventHandler(target_SelectionChanged);\n            target.VisibleRangeChanged += new EventHandler(target_VisibleRangeChanged);\n        }\n\n        void target_VisibleRangeChanged(object sender, EventArgs e)\n        {\n            Invalidate();\n        }\n\n        void target_SelectionChanged(object sender, EventArgs e)\n        {\n            Invalidate();\n        }\n\n        protected virtual void target_Scroll(object sender, ScrollEventArgs e)\n        {\n            Invalidate();\n        }\n\n        protected override void OnResize(EventArgs e)\n        {\n            base.OnResize(e);\n            Invalidate();\n        }\n\n        protected override void OnPaint(PaintEventArgs e)\n        {\n            if (target == null)\n                return;\n\n            Point car = PointToClient(target.PointToScreen(target.PlaceToPoint(target.Selection.Start)));\n\n            Size fontSize = TextRenderer.MeasureText(\"W\", Font);\n\n            int column = 0;\n            e.Graphics.FillRectangle(\n                new LinearGradientBrush(new Rectangle(0, 0, Width, Height), BackColor, BackColor2, 270),\n                new Rectangle(0, 0, Width, Height));\n\n            float columnWidth = target.CharWidth;\n            var sf = new StringFormat();\n            sf.Alignment = StringAlignment.Center;\n            sf.LineAlignment = StringAlignment.Near;\n\n            var zeroPoint = target.PositionToPoint(0);\n            zeroPoint = PointToClient(target.PointToScreen(zeroPoint));\n\n            using (var pen = new Pen(TickColor))\n            using (var textBrush = new SolidBrush(ForeColor))\n                for (float x = zeroPoint.X; x < Right; x += columnWidth, ++column)\n                {\n                    if (column % 10 == 0)\n                        e.Graphics.DrawString(column.ToString(), Font, textBrush, x, 0f, sf);\n\n                    e.Graphics.DrawLine(pen, (int) x, fontSize.Height + (column % 5 == 0 ? 1 : 3), (int) x, Height - 4);\n                }\n\n            using (var pen = new Pen(TickColor))\n                e.Graphics.DrawLine(pen, new Point(car.X - 3, Height - 3), new Point(car.X + 3, Height - 3));\n\n            using (var pen = new Pen(CaretTickColor))\n            {\n                e.Graphics.DrawLine(pen, new Point(car.X - 2, fontSize.Height + 3), new Point(car.X - 2, Height - 4));\n                e.Graphics.DrawLine(pen, new Point(car.X, fontSize.Height + 1), new Point(car.X, Height - 4));\n                e.Graphics.DrawLine(pen, new Point(car.X + 2, fontSize.Height + 3), new Point(car.X + 2, Height - 4));\n            }\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/Style.cs",
    "content": "﻿using System.Drawing;\nusing System;\nusing System.Drawing.Drawing2D;\nusing System.Collections.Generic;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// Style of chars\n    /// </summary>\n    /// <remarks>This is base class for all text and design renderers</remarks>\n    public abstract class Style : IDisposable\n    {\n        /// <summary>\n        /// This style is exported to outer formats (HTML for example)\n        /// </summary>\n        public virtual bool IsExportable { get; set; }\n\n        /// <summary>\n        /// Occurs when user click on StyleVisualMarker joined to this style \n        /// </summary>\n        public event EventHandler<VisualMarkerEventArgs> VisualMarkerClick;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        public Style()\n        {\n            IsExportable = true;\n        }\n\n        /// <summary>\n        /// Renders given range of text\n        /// </summary>\n        /// <param name=\"gr\">Graphics object</param>\n        /// <param name=\"position\">Position of the range in absolute control coordinates</param>\n        /// <param name=\"range\">Rendering range of text</param>\n        public abstract void Draw(Graphics gr, Point position, Range range);\n\n        /// <summary>\n        /// Occurs when user click on StyleVisualMarker joined to this style \n        /// </summary>\n        public virtual void OnVisualMarkerClick(FastColoredTextBox tb, VisualMarkerEventArgs args)\n        {\n            if (VisualMarkerClick != null)\n                VisualMarkerClick(tb, args);\n        }\n\n        /// <summary>\n        /// Shows VisualMarker\n        /// Call this method in Draw method, when you need to show VisualMarker for your style\n        /// </summary>\n        protected virtual void AddVisualMarker(FastColoredTextBox tb, StyleVisualMarker marker)\n        {\n            tb.AddVisualMarker(marker);\n        }\n\n        public static Size GetSizeOfRange(Range range)\n        {\n            return new Size((range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);\n        }\n\n        public static GraphicsPath GetRoundedRectangle(Rectangle rect, int d)\n        {\n            GraphicsPath gp = new GraphicsPath();\n\n            gp.AddArc(rect.X, rect.Y, d, d, 180, 90);\n            gp.AddArc(rect.X + rect.Width - d, rect.Y, d, d, 270, 90);\n            gp.AddArc(rect.X + rect.Width - d, rect.Y + rect.Height - d, d, d, 0, 90);\n            gp.AddArc(rect.X, rect.Y + rect.Height - d, d, d, 90, 90);\n            gp.AddLine(rect.X, rect.Y + rect.Height - d, rect.X, rect.Y + d / 2);\n\n            return gp;\n        }\n\n        public virtual void Dispose()\n        {\n            ;\n        }\n\n        /// <summary>\n        /// Returns CSS for export to HTML\n        /// </summary>\n        /// <returns></returns>\n        public virtual string GetCSS()\n        {\n            return \"\";\n        }\n\n        /// <summary>\n        /// Returns RTF descriptor for export to RTF\n        /// </summary>\n        /// <returns></returns>\n        public virtual RTFStyleDescriptor GetRTF()\n        {\n            return new RTFStyleDescriptor();\n        }\n    }\n\n    /// <summary>\n    /// Style for chars rendering\n    /// This renderer can draws chars, with defined fore and back colors\n    /// </summary>\n    public class TextStyle : Style\n    {\n        public Brush ForeBrush { get; set; }\n        public Brush BackgroundBrush { get; set; }\n\n        public FontStyle FontStyle { get; set; }\n\n        //public readonly Font Font;\n        public StringFormat stringFormat;\n\n        public TextStyle(Brush foreBrush, Brush backgroundBrush, FontStyle fontStyle)\n        {\n            this.ForeBrush = foreBrush;\n            this.BackgroundBrush = backgroundBrush;\n            this.FontStyle = fontStyle;\n            stringFormat = new StringFormat(StringFormatFlags.MeasureTrailingSpaces);\n        }\n\n        public override void Draw(Graphics gr, Point position, Range range)\n        {\n            //draw background\n            if (BackgroundBrush != null)\n                gr.FillRectangle(BackgroundBrush, position.X, position.Y,\n                    (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);\n            //draw chars\n            using (var f = new Font(range.tb.Font, FontStyle))\n            {\n                Line line = range.tb[range.Start.iLine];\n                float dx = range.tb.CharWidth;\n                float y = position.Y + range.tb.LineInterval / 2;\n                float x = position.X - range.tb.CharWidth / 3;\n\n                if (ForeBrush == null)\n                    ForeBrush = new SolidBrush(range.tb.ForeColor);\n\n                if (range.tb.ImeAllowed)\n                {\n                    //IME mode\n                    for (int i = range.Start.iChar; i < range.End.iChar; i++)\n                    {\n                        SizeF size = FastColoredTextBox.GetCharSize(f, line[i].c);\n\n                        var gs = gr.Save();\n                        float k = size.Width > range.tb.CharWidth + 1 ? range.tb.CharWidth / size.Width : 1;\n                        gr.TranslateTransform(x, y + (1 - k) * range.tb.CharHeight / 2);\n                        gr.ScaleTransform(k, (float) Math.Sqrt(k));\n                        gr.DrawString(line[i].c.ToString(), f, ForeBrush, 0, 0, stringFormat);\n                        gr.Restore(gs);\n                        x += dx;\n                    }\n                }\n                else\n                {\n                    //classic mode \n                    for (int i = range.Start.iChar; i < range.End.iChar; i++)\n                    {\n                        //draw char\n                        gr.DrawString(line[i].c.ToString(), f, ForeBrush, x, y, stringFormat);\n                        x += dx;\n                    }\n                }\n            }\n        }\n\n        public override string GetCSS()\n        {\n            string result = \"\";\n\n            if (BackgroundBrush is SolidBrush)\n            {\n                var s = ExportToHTML.GetColorAsString((BackgroundBrush as SolidBrush).Color);\n                if (s != \"\")\n                    result += \"background-color:\" + s + \";\";\n            }\n\n            if (ForeBrush is SolidBrush)\n            {\n                var s = ExportToHTML.GetColorAsString((ForeBrush as SolidBrush).Color);\n                if (s != \"\")\n                    result += \"color:\" + s + \";\";\n            }\n\n            if ((FontStyle & FontStyle.Bold) != 0)\n                result += \"font-weight:bold;\";\n            if ((FontStyle & FontStyle.Italic) != 0)\n                result += \"font-style:oblique;\";\n            if ((FontStyle & FontStyle.Strikeout) != 0)\n                result += \"text-decoration:line-through;\";\n            if ((FontStyle & FontStyle.Underline) != 0)\n                result += \"text-decoration:underline;\";\n\n            return result;\n        }\n\n        public override RTFStyleDescriptor GetRTF()\n        {\n            var result = new RTFStyleDescriptor();\n\n            if (BackgroundBrush is SolidBrush)\n                result.BackColor = (BackgroundBrush as SolidBrush).Color;\n\n            if (ForeBrush is SolidBrush)\n                result.ForeColor = (ForeBrush as SolidBrush).Color;\n\n            if ((FontStyle & FontStyle.Bold) != 0)\n                result.AdditionalTags += @\"\\b\";\n            if ((FontStyle & FontStyle.Italic) != 0)\n                result.AdditionalTags += @\"\\i\";\n            if ((FontStyle & FontStyle.Strikeout) != 0)\n                result.AdditionalTags += @\"\\strike\";\n            if ((FontStyle & FontStyle.Underline) != 0)\n                result.AdditionalTags += @\"\\ul\";\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Renderer for folded block\n    /// </summary>\n    public class FoldedBlockStyle : TextStyle\n    {\n        public FoldedBlockStyle(Brush foreBrush, Brush backgroundBrush, FontStyle fontStyle) :\n            base(foreBrush, backgroundBrush, fontStyle)\n        {\n        }\n\n        public override void Draw(Graphics gr, Point position, Range range)\n        {\n            if (range.End.iChar > range.Start.iChar)\n            {\n                base.Draw(gr, position, range);\n\n                int firstNonSpaceSymbolX = position.X;\n\n                //find first non space symbol\n                for (int i = range.Start.iChar; i < range.End.iChar; i++)\n                    if (range.tb[range.Start.iLine][i].c != ' ')\n                        break;\n                    else\n                        firstNonSpaceSymbolX += range.tb.CharWidth;\n\n                //create marker\n                range.tb.AddVisualMarker(new FoldedAreaMarker(range.Start.iLine,\n                    new Rectangle(firstNonSpaceSymbolX, position.Y,\n                        position.X + (range.End.iChar - range.Start.iChar) * range.tb.CharWidth - firstNonSpaceSymbolX,\n                        range.tb.CharHeight)));\n            }\n            else\n            {\n                //draw '...'\n                using (Font f = new Font(range.tb.Font, FontStyle))\n                    gr.DrawString(\"...\", f, ForeBrush, range.tb.LeftIndent, position.Y - 2);\n                //create marker\n                range.tb.AddVisualMarker(new FoldedAreaMarker(range.Start.iLine,\n                    new Rectangle(range.tb.LeftIndent + 2, position.Y, 2 * range.tb.CharHeight, range.tb.CharHeight)));\n            }\n        }\n    }\n\n    /// <summary>\n    /// Renderer for selected area\n    /// </summary>\n    public class SelectionStyle : Style\n    {\n        public Brush BackgroundBrush { get; set; }\n        public Brush ForegroundBrush { get; private set; }\n\n        public override bool IsExportable\n        {\n            get { return false; }\n            set { }\n        }\n\n        public SelectionStyle(Brush backgroundBrush, Brush foregroundBrush = null)\n        {\n            this.BackgroundBrush = backgroundBrush;\n            this.ForegroundBrush = foregroundBrush;\n        }\n\n        public override void Draw(Graphics gr, Point position, Range range)\n        {\n            //draw background\n            if (BackgroundBrush != null)\n            {\n                gr.SmoothingMode = SmoothingMode.None;\n                var rect = new Rectangle(position.X, position.Y,\n                    (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);\n                if (rect.Width == 0)\n                    return;\n                gr.FillRectangle(BackgroundBrush, rect);\n                //\n                if (ForegroundBrush != null)\n                {\n                    //draw text\n                    gr.SmoothingMode = SmoothingMode.AntiAlias;\n\n                    var r = new Range(range.tb, range.Start.iChar, range.Start.iLine,\n                        Math.Min(range.tb[range.End.iLine].Count, range.End.iChar), range.End.iLine);\n                    using (var style = new TextStyle(ForegroundBrush, null, FontStyle.Regular))\n                        style.Draw(gr, new Point(position.X, position.Y - 1), r);\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Marker style\n    /// Draws background color for text\n    /// </summary>\n    public class MarkerStyle : Style\n    {\n        public Brush BackgroundBrush { get; set; }\n\n        public MarkerStyle(Brush backgroundBrush)\n        {\n            this.BackgroundBrush = backgroundBrush;\n            IsExportable = true;\n        }\n\n        public override void Draw(Graphics gr, Point position, Range range)\n        {\n            //draw background\n            if (BackgroundBrush != null)\n            {\n                Rectangle rect = new Rectangle(position.X, position.Y,\n                    (range.End.iChar - range.Start.iChar) * range.tb.CharWidth, range.tb.CharHeight);\n                if (rect.Width == 0)\n                    return;\n                gr.FillRectangle(BackgroundBrush, rect);\n            }\n        }\n\n        public override string GetCSS()\n        {\n            string result = \"\";\n\n            if (BackgroundBrush is SolidBrush)\n            {\n                var s = ExportToHTML.GetColorAsString((BackgroundBrush as SolidBrush).Color);\n                if (s != \"\")\n                    result += \"background-color:\" + s + \";\";\n            }\n\n            return result;\n        }\n    }\n\n    /// <summary>\n    /// Draws small rectangle for popup menu\n    /// </summary>\n    public class ShortcutStyle : Style\n    {\n        public Pen borderPen;\n\n        public ShortcutStyle(Pen borderPen)\n        {\n            this.borderPen = borderPen;\n        }\n\n        public override void Draw(Graphics gr, Point position, Range range)\n        {\n            //get last char coordinates\n            Point p = range.tb.PlaceToPoint(range.End);\n            //draw small square under char\n            Rectangle rect = new Rectangle(p.X - 5, p.Y + range.tb.CharHeight - 2, 4, 3);\n            gr.FillPath(Brushes.White, GetRoundedRectangle(rect, 1));\n            gr.DrawPath(borderPen, GetRoundedRectangle(rect, 1));\n            //add visual marker for handle mouse events\n            AddVisualMarker(range.tb,\n                new StyleVisualMarker(\n                    new Rectangle(p.X - range.tb.CharWidth, p.Y, range.tb.CharWidth, range.tb.CharHeight), this));\n        }\n    }\n\n    /// <summary>\n    /// This style draws a wavy line below a given text range.\n    /// </summary>\n    /// <remarks>Thanks for Yallie</remarks>\n    public class WavyLineStyle : Style\n    {\n        private Pen Pen { get; set; }\n\n        public WavyLineStyle(int alpha, Color color)\n        {\n            Pen = new Pen(Color.FromArgb(alpha, color));\n        }\n\n        public override void Draw(Graphics gr, Point pos, Range range)\n        {\n            var size = GetSizeOfRange(range);\n            var start = new Point(pos.X, pos.Y + size.Height - 1);\n            var end = new Point(pos.X + size.Width, pos.Y + size.Height - 1);\n            DrawWavyLine(gr, start, end);\n        }\n\n        private void DrawWavyLine(Graphics graphics, Point start, Point end)\n        {\n            if (end.X - start.X < 2)\n            {\n                graphics.DrawLine(Pen, start, end);\n                return;\n            }\n\n            var offset = -1;\n            var points = new List<Point>();\n\n            for (int i = start.X; i <= end.X; i += 2)\n            {\n                points.Add(new Point(i, start.Y + offset));\n                offset = -offset;\n            }\n\n            graphics.DrawLines(Pen, points.ToArray());\n        }\n\n        public override void Dispose()\n        {\n            base.Dispose();\n\n            if (Pen != null)\n                Pen.Dispose();\n        }\n    }\n\n    /// <summary>\n    /// This style is used to mark range of text as ReadOnly block\n    /// </summary>\n    /// <remarks>You can inherite this style to add visual effects of readonly text</remarks>\n    public class ReadOnlyStyle : Style\n    {\n        public ReadOnlyStyle()\n        {\n            IsExportable = false;\n        }\n\n        public override void Draw(Graphics gr, Point position, Range range)\n        {\n            //\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/SyntaxDescriptor.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Text.RegularExpressions;\nusing System;\n\nnamespace FastColoredTextBoxNS\n{\n    public class SyntaxDescriptor : IDisposable\n    {\n        public char leftBracket = '(';\n        public char rightBracket = ')';\n        public char leftBracket2 = '{';\n        public char rightBracket2 = '}';\n        public BracketsHighlightStrategy bracketsHighlightStrategy = BracketsHighlightStrategy.Strategy2;\n        public readonly List<Style> styles = new List<Style>();\n        public readonly List<RuleDesc> rules = new List<RuleDesc>();\n        public readonly List<FoldingDesc> foldings = new List<FoldingDesc>();\n\n        public void Dispose()\n        {\n            foreach (var style in styles)\n                style.Dispose();\n        }\n    }\n\n    public class RuleDesc\n    {\n        Regex regex;\n        public string pattern;\n        public RegexOptions options = RegexOptions.None;\n        public Style style;\n\n        public Regex Regex\n        {\n            get\n            {\n                if (regex == null)\n                {\n                    regex = new Regex(pattern, SyntaxHighlighter.RegexCompiledOption | options);\n                }\n\n                return regex;\n            }\n        }\n    }\n\n    public class FoldingDesc\n    {\n        public string startMarkerRegex;\n        public string finishMarkerRegex;\n        public RegexOptions options = RegexOptions.None;\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/SyntaxHighlighter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Globalization;\nusing System.IO;\nusing System.Text.RegularExpressions;\nusing System.Xml;\n\nnamespace FastColoredTextBoxNS\n{\n    public class SyntaxHighlighter : IDisposable\n    {\n        //styles\n        protected static readonly Platform platformType = PlatformType.GetOperationSystemPlatform();\n        public readonly Style BlueBoldStyle = new TextStyle(Brushes.Blue, null, FontStyle.Bold);\n        public readonly Style BlueStyle = new TextStyle(Brushes.Blue, null, FontStyle.Regular);\n        public readonly Style BoldStyle = new TextStyle(null, null, FontStyle.Bold | FontStyle.Underline);\n        public readonly Style BrownStyle = new TextStyle(Brushes.Brown, null, FontStyle.Italic);\n        public readonly Style GrayStyle = new TextStyle(Brushes.Gray, null, FontStyle.Regular);\n        public readonly Style GreenStyle = new TextStyle(Brushes.Green, null, FontStyle.Italic);\n        public readonly Style MagentaStyle = new TextStyle(Brushes.Magenta, null, FontStyle.Regular);\n        public readonly Style MaroonStyle = new TextStyle(Brushes.Maroon, null, FontStyle.Regular);\n        public readonly Style RedStyle = new TextStyle(Brushes.Red, null, FontStyle.Regular);\n        public readonly Style BlackStyle = new TextStyle(Brushes.Black, null, FontStyle.Regular);\n        public readonly Style CrimsonStyle = new TextStyle(Brushes.Crimson, null, FontStyle.Regular);\n        public readonly Style DarkOrangeStyle = new TextStyle(Brushes.DarkOrange, null, FontStyle.Regular);\n        public readonly Style DodgerBlueStyle = new TextStyle(Brushes.DodgerBlue, null, FontStyle.Regular);\n\n        public readonly Style DarkOrangeBoldStyle =\n            new TextStyle(Brushes.DarkOrange, null, FontStyle.Bold | FontStyle.Regular);\n\n        public readonly Style RazorDarkKeywords =\n            new TextStyle(new SolidBrush(Color.FromArgb(255, 253, 134, 30)), null, FontStyle.Regular);\n\n        public readonly Style RazorDarkCommands =\n            new TextStyle(new SolidBrush(Color.FromArgb(255, 43, 144, 175)), null, FontStyle.Regular);\n\n        public readonly Style RazorDarkStrings =\n            new TextStyle(new SolidBrush(Color.FromArgb(255, 181, 241, 9)), null, FontStyle.Regular);\n\n        public readonly Style RazorDarkOperators =\n            new TextStyle(new SolidBrush(Color.FromArgb(255, 253, 134, 30)), null, FontStyle.Regular);\n\n        public readonly Style RazorDarkNumbers =\n            new TextStyle(new SolidBrush(Color.FromArgb(255, 174, 129, 255)), null, FontStyle.Regular);\n\n        public readonly Style RazorDarkComments =\n            new TextStyle(new SolidBrush(Color.FromArgb(255, 150, 150, 150)), null, FontStyle.Regular);\n\n        public readonly Style RazorDarkSerial =\n            new TextStyle(new SolidBrush(Color.FromArgb(255, 249, 37, 77)), null, FontStyle.Regular);\n\n\n        //\n        protected readonly Dictionary<string, SyntaxDescriptor> descByXMLfileNames =\n            new Dictionary<string, SyntaxDescriptor>();\n\n        protected readonly List<Style> resilientStyles = new List<Style>(5);\n\n        protected Regex RazorCommentRegex;\n        protected Regex RazorSerialRegex;\n        protected Regex RazorOperatorRegex;\n        protected Regex RazorLayerRegex;\n        protected Regex RazorExpressionRegex;\n        protected Regex RazorCommandRegex;\n        protected Regex RazorKeywordRegex;\n        protected Regex RazorNumberRegex;\n        protected Regex RazorStringRegex1;\n        protected Regex RazorStringRegex2;\n\n        protected FastColoredTextBox currentTb;\n\n        public static RegexOptions RegexCompiledOption\n        {\n            get\n            {\n                if (platformType == Platform.X86)\n                    return RegexOptions.Compiled;\n                else\n                    return RegexOptions.None;\n            }\n        }\n\n        public SyntaxHighlighter(FastColoredTextBox currentTb)\n        {\n            this.currentTb = currentTb;\n        }\n\n        #region IDisposable Members\n\n        public void Dispose()\n        {\n            foreach (SyntaxDescriptor desc in descByXMLfileNames.Values)\n                desc.Dispose();\n        }\n\n        #endregion\n\n        /// <summary>\n        /// Highlights syntax for given language\n        /// </summary>\n        public virtual void HighlightSyntax(Language language, Range range)\n        {\n            RazorSyntaxHighlight(range);\n        }\n\n        /// <summary>\n        /// Highlights syntax for given XML description file\n        /// </summary>\n        public virtual void HighlightSyntax(string XMLdescriptionFile, Range range)\n        {\n            SyntaxDescriptor desc = null;\n            if (!descByXMLfileNames.TryGetValue(XMLdescriptionFile, out desc))\n            {\n                var doc = new XmlDocument();\n                string file = XMLdescriptionFile;\n                if (!File.Exists(file))\n                    file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.GetFileName(file));\n\n                doc.LoadXml(File.ReadAllText(file));\n                desc = ParseXmlDescription(doc);\n                descByXMLfileNames[XMLdescriptionFile] = desc;\n            }\n\n            HighlightSyntax(desc, range);\n        }\n\n        public virtual void AutoIndentNeeded(object sender, AutoIndentEventArgs args)\n        {\n            RazorAutoIndentNeeded(sender, args);\n        }\n\n        /// <summary>\n        /// Uses the given <paramref name=\"doc\"/> to parse a XML description and adds it as syntax descriptor. \n        /// The syntax descriptor is used for highlighting when \n        /// <list type=\"bullet\">\n        ///     <item>Language property of FCTB is set to <see cref=\"Language.Custom\"/></item>\n        ///     <item>DescriptionFile property of FCTB has the same value as the method parameter <paramref name=\"descriptionFileName\"/></item>\n        /// </list>\n        /// </summary>\n        /// <param name=\"descriptionFileName\">Name of the description file</param>\n        /// <param name=\"doc\">XmlDocument to parse</param>\n        public virtual void AddXmlDescription(string descriptionFileName, XmlDocument doc)\n        {\n            SyntaxDescriptor desc = ParseXmlDescription(doc);\n            descByXMLfileNames[descriptionFileName] = desc;\n        }\n\n        /// <summary>\n        /// Adds the given <paramref name=\"style\"/> as resilient style. A resilient style is additionally available when highlighting is \n        /// based on a syntax descriptor that has been derived from a XML description file. In the run of the highlighting routine \n        /// the styles used by the FCTB are always dropped and replaced with the (initial) ones from the syntax descriptor. Resilient styles are \n        /// added afterwards and can be used anyway. \n        /// </summary>\n        /// <param name=\"style\">Style to add</param>\n        public virtual void AddResilientStyle(Style style)\n        {\n            if (resilientStyles.Contains(style)) return;\n            currentTb.CheckStylesBufferSize(); // Prevent buffer overflow\n            resilientStyles.Add(style);\n        }\n\n        public static SyntaxDescriptor ParseXmlDescription(XmlDocument doc)\n        {\n            var desc = new SyntaxDescriptor();\n            XmlNode brackets = doc.SelectSingleNode(\"doc/brackets\");\n            if (brackets != null)\n            {\n                if (brackets.Attributes[\"left\"] == null || brackets.Attributes[\"right\"] == null ||\n                    brackets.Attributes[\"left\"].Value == \"\" || brackets.Attributes[\"right\"].Value == \"\")\n                {\n                    desc.leftBracket = '\\x0';\n                    desc.rightBracket = '\\x0';\n                }\n                else\n                {\n                    desc.leftBracket = brackets.Attributes[\"left\"].Value[0];\n                    desc.rightBracket = brackets.Attributes[\"right\"].Value[0];\n                }\n\n                if (brackets.Attributes[\"left2\"] == null || brackets.Attributes[\"right2\"] == null ||\n                    brackets.Attributes[\"left2\"].Value == \"\" || brackets.Attributes[\"right2\"].Value == \"\")\n                {\n                    desc.leftBracket2 = '\\x0';\n                    desc.rightBracket2 = '\\x0';\n                }\n                else\n                {\n                    desc.leftBracket2 = brackets.Attributes[\"left2\"].Value[0];\n                    desc.rightBracket2 = brackets.Attributes[\"right2\"].Value[0];\n                }\n\n                if (brackets.Attributes[\"strategy\"] == null || brackets.Attributes[\"strategy\"].Value == \"\")\n                    desc.bracketsHighlightStrategy = BracketsHighlightStrategy.Strategy2;\n                else\n                    desc.bracketsHighlightStrategy =\n                        (BracketsHighlightStrategy) Enum.Parse(typeof(BracketsHighlightStrategy),\n                            brackets.Attributes[\"strategy\"].Value);\n            }\n\n            var styleByName = new Dictionary<string, Style>();\n\n            foreach (XmlNode style in doc.SelectNodes(\"doc/style\"))\n            {\n                Style s = ParseStyle(style);\n                styleByName[style.Attributes[\"name\"].Value] = s;\n                desc.styles.Add(s);\n            }\n\n            foreach (XmlNode rule in doc.SelectNodes(\"doc/rule\"))\n                desc.rules.Add(ParseRule(rule, styleByName));\n            foreach (XmlNode folding in doc.SelectNodes(\"doc/folding\"))\n                desc.foldings.Add(ParseFolding(folding));\n\n            return desc;\n        }\n\n        protected static FoldingDesc ParseFolding(XmlNode foldingNode)\n        {\n            var folding = new FoldingDesc();\n            //regex\n            folding.startMarkerRegex = foldingNode.Attributes[\"start\"].Value;\n            folding.finishMarkerRegex = foldingNode.Attributes[\"finish\"].Value;\n            //options\n            XmlAttribute optionsA = foldingNode.Attributes[\"options\"];\n            if (optionsA != null)\n                folding.options = (RegexOptions) Enum.Parse(typeof(RegexOptions), optionsA.Value);\n\n            return folding;\n        }\n\n        protected static RuleDesc ParseRule(XmlNode ruleNode, Dictionary<string, Style> styles)\n        {\n            var rule = new RuleDesc();\n            rule.pattern = ruleNode.InnerText;\n            //\n            XmlAttribute styleA = ruleNode.Attributes[\"style\"];\n            XmlAttribute optionsA = ruleNode.Attributes[\"options\"];\n            //Style\n            if (styleA == null)\n                throw new Exception(\"Rule must contain style name.\");\n            if (!styles.ContainsKey(styleA.Value))\n                throw new Exception(\"Style '\" + styleA.Value + \"' is not found.\");\n            rule.style = styles[styleA.Value];\n            //options\n            if (optionsA != null)\n                rule.options = (RegexOptions) Enum.Parse(typeof(RegexOptions), optionsA.Value);\n\n            return rule;\n        }\n\n        protected static Style ParseStyle(XmlNode styleNode)\n        {\n            XmlAttribute typeA = styleNode.Attributes[\"type\"];\n            XmlAttribute colorA = styleNode.Attributes[\"color\"];\n            XmlAttribute backColorA = styleNode.Attributes[\"backColor\"];\n            XmlAttribute fontStyleA = styleNode.Attributes[\"fontStyle\"];\n            XmlAttribute nameA = styleNode.Attributes[\"name\"];\n            //colors\n            SolidBrush foreBrush = null;\n            if (colorA != null)\n                foreBrush = new SolidBrush(ParseColor(colorA.Value));\n            SolidBrush backBrush = null;\n            if (backColorA != null)\n                backBrush = new SolidBrush(ParseColor(backColorA.Value));\n            //fontStyle\n            FontStyle fontStyle = FontStyle.Regular;\n            if (fontStyleA != null)\n                fontStyle = (FontStyle) Enum.Parse(typeof(FontStyle), fontStyleA.Value);\n\n            return new TextStyle(foreBrush, backBrush, fontStyle);\n        }\n\n        protected static Color ParseColor(string s)\n        {\n            if (s.StartsWith(\"#\"))\n            {\n                if (s.Length <= 7)\n                    return Color.FromArgb(255,\n                        Color.FromArgb(Int32.Parse(s.Substring(1), NumberStyles.AllowHexSpecifier)));\n                else\n                    return Color.FromArgb(Int32.Parse(s.Substring(1), NumberStyles.AllowHexSpecifier));\n            }\n            else\n                return Color.FromName(s);\n        }\n\n        public void HighlightSyntax(SyntaxDescriptor desc, Range range)\n        {\n            //set style order\n            range.tb.ClearStylesBuffer();\n            for (int i = 0; i < desc.styles.Count; i++)\n                range.tb.Styles[i] = desc.styles[i];\n            // add resilient styles\n            int l = desc.styles.Count;\n            for (int i = 0; i < resilientStyles.Count; i++)\n                range.tb.Styles[l + i] = resilientStyles[i];\n            //brackets\n            char[] oldBrackets = RememberBrackets(range.tb);\n            range.tb.LeftBracket = desc.leftBracket;\n            range.tb.RightBracket = desc.rightBracket;\n            range.tb.LeftBracket2 = desc.leftBracket2;\n            range.tb.RightBracket2 = desc.rightBracket2;\n            //clear styles of range\n            range.ClearStyle(desc.styles.ToArray());\n            //highlight syntax\n            foreach (RuleDesc rule in desc.rules)\n                range.SetStyle(rule.style, rule.Regex);\n            //clear folding\n            range.ClearFoldingMarkers();\n            //folding markers\n            foreach (FoldingDesc folding in desc.foldings)\n                range.SetFoldingMarkers(folding.startMarkerRegex, folding.finishMarkerRegex, folding.options);\n\n            //\n            RestoreBrackets(range.tb, oldBrackets);\n        }\n\n        protected void RestoreBrackets(FastColoredTextBox tb, char[] oldBrackets)\n        {\n            tb.LeftBracket = oldBrackets[0];\n            tb.RightBracket = oldBrackets[1];\n            tb.LeftBracket2 = oldBrackets[2];\n            tb.RightBracket2 = oldBrackets[3];\n        }\n\n        protected char[] RememberBrackets(FastColoredTextBox tb)\n        {\n            return new[] {tb.LeftBracket, tb.RightBracket, tb.LeftBracket2, tb.RightBracket2};\n        }\n\n        public void InitStyleSchema(Language lang)\n        {\n            CommentStyle = RazorDarkComments;\n            StringStyle = RazorDarkStrings;\n            NumberStyle = RazorDarkNumbers;\n            KeywordStyle = RazorDarkKeywords;\n            FunctionsStyle = RedStyle;\n            RazorCommandStyle = RazorDarkCommands;\n            RazorSerialStyle = RazorDarkSerial;\n            RazorLayerStyle = RazorDarkNumbers;\n            RazorExpressionStyle = RazorDarkSerial;\n        }\n\n        protected void InitRazorRegex()\n        {\n            RazorStringRegex1 = new Regex(\"([\\\"'])(?:(?=(\\\\\\\\?))\\\\2.)*?\\\\1\", RegexCompiledOption);\n\n            RazorStringRegex2 = new Regex(\"'[^'\\\\\\\\]*(\\\\\\\\.[^'\\\\\\\\]*)*'\", RegexCompiledOption);\n\n            RazorCommentRegex = new Regex(\"(//.*$|#.*$)\", RegexOptions.Multiline | RegexCompiledOption);\n\n            RazorSerialRegex = new Regex(@\"0x[\\da-fA-F]*\");\n\n            RazorNumberRegex = new Regex(@\"\\b[+-]?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b\", RegexCompiledOption);\n            RazorKeywordRegex =\n                new Regex(\n                    @\"\\b(if|elseif|else|endif|while|endwhile|for|foreach|endfor|break|continue|not|and|or|stop|replay|loop|as|in)\\b\",\n                    RegexCompiledOption);\n\n            RazorCommandRegex =\n                new Regex(\n                    @\"\\b(attack|cast|dress|undress|dressconfig|target|targettype|targetloc|targetrelloc|dress|drop|waitfortarget|wft|dclick|dclicktype|dclickvar|usetype|useobject|droprelloc|lift|lifttype|waitforgump|gumpresponse|gumpclose|menu|menuresponse|waitformenu|promptresponse|waitforprompt|hotkey|say|msg|overhead|sysmsg|wait|pause|waitforstat|setability|setlasttarget|lasttarget|setvar|unsetvar|skill|useskill|walk|script|useonce|organizer|organize|org|restock|scav|scavenger|potion|clearsysmsg|clearjournal|whisper|yell|guild|alliance|emote|waitforsysmsg|wfsysmsg|clearall|virtue|interrupt|sound|music|classicuo|cuo|rename|getlabel|ignore|unignore|clearignore|cooldown|settimer|removetimer|createtimer|poplist|pushlist|removelist|createlist|clearlist|cleardragdrop|clearhands|sell)\\b\",\n                    RegexCompiledOption);\n\n            RazorLayerRegex =\n                new Regex(\n                    @\"\\b(RightHand|LeftHand|Shoes|Pants|Shirt|Head|Gloves|Ring|Talisman|Neck|Hair|Waist|InnerTorso|Bracelet|FacialHair|MiddleTorso|Earrings|Arms|Cloak|Backpack|OuterTorso|OuterLegs|InnerLegs|backpack|true|false|criminal|enemy|friend|friendly|grey|gray|innocent|murderer|red|blue|nonfriendly|cancel|clear|minutes|minute|min|seconds|second|sec)\\b\",\n                    RegexCompiledOption);\n\n            RazorExpressionRegex =\n                new Regex(\n                    @\"\\b(queued|position|insysmsg|insysmessage|findtype|findbuff|finddebuff|stam|maxstam|hp|maxhp|maxhits|hits|mana|maxmana|str|dex|int|poisoned|hidden|mounted|rhandempty|lhandempty|skill|count|counter|weight|dead|closest|close|rand|random|next|prev|previous|human|humanoid|monster|varexist|varexist|followers|maxfollowers|maxweight|targetexists|diffmana|diffstam|diffhits|diffhp|diffweight|blessed|invul|invuln|warmode|name|paralyzed|itemcount|poplist|atlist|listexists|list|inlist|timer|timerexists)\\b\",\n                    RegexCompiledOption);\n        }\n\n        public virtual void RazorSyntaxHighlight(Range range)\n        {\n            range.tb.CommentPrefix = \"//\";\n\n            range.tb.LeftBracket = '(';\n            range.tb.RightBracket = ')';\n            range.tb.LeftBracket2 = '[';\n            range.tb.RightBracket2 = ']';\n            range.tb.BracketsHighlightStrategy = BracketsHighlightStrategy.Strategy1;\n\n            //range.tb.AutoIndentCharsPatterns = @\"^\\s*[\\w\\.]+(\\s\\w+)?\\s*(?<range>=)\\s*(?<range>.+)\";\n\n            //clear style of changed range\n            range.ClearStyle(StringStyle, CommentStyle, NumberStyle, KeywordStyle, FunctionsStyle);\n\n            InitRazorRegex();\n\n            //string highlighting\n            range.SetStyle(StringStyle, RazorStringRegex1);\n            range.SetStyle(StringStyle, RazorStringRegex2);\n\n            //comment highlighting\n            range.SetStyle(CommentStyle, RazorCommentRegex);\n\n            //number highlighting\n            range.SetStyle(NumberStyle, RazorNumberRegex);\n\n            //keyword highlighting\n            range.SetStyle(KeywordStyle, RazorKeywordRegex);\n\n            // Razor highlight\n            range.SetStyle(RazorCommandStyle, RazorCommandRegex);\n            range.SetStyle(RazorSerialStyle, RazorSerialRegex);\n            range.SetStyle(RazorLayerStyle, RazorLayerRegex);\n            range.SetStyle(RazorExpressionStyle, RazorExpressionRegex);\n            //range.SetStyle(RazorOperatorStyle, RazorOperatorsRegEx);\n\n            //clear folding markers\n            range.ClearFoldingMarkers();\n        }\n\n        protected void RazorAutoIndentNeeded(object sender, AutoIndentEventArgs args)\n        {\n            if (Regex.IsMatch(args.LineText, @\"^[^\"\"']*\\:\"))\n            {\n                args.ShiftNextLines = args.TabLength;\n            }\n\n            if (Regex.IsMatch(args.PrevLineText, @\"^\\s*(if|for|while|elseif|[\\}\\s]*else)\\b[^{]*$\"))\n                if (!Regex.IsMatch(args.PrevLineText, @\"(;\\s*$)|(;\\s*//)\")) //operator is unclosed\n                {\n                    args.Shift = args.TabLength;\n                }\n        }\n\n        #region Styles\n\n        /// <summary>\n        /// String style\n        /// </summary>\n        public Style StringStyle { get; set; }\n\n        /// <summary>\n        /// Comment style\n        /// </summary>\n        public Style CommentStyle { get; set; }\n\n        /// <summary>\n        /// Number style\n        /// </summary>\n        public Style NumberStyle { get; set; }\n\n        /// <summary>\n        /// Keyword style\n        /// </summary>\n        public Style KeywordStyle { get; set; }\n\n      \n        /// <summary>\n        /// SQL Functions style\n        /// </summary>\n        public Style FunctionsStyle { get; set; }\n\n        public Style RazorCommandStyle { get; set; }\n        public Style RazorSerialStyle { get; set; }\n        public Style RazorLayerStyle { get; set; }\n        public Style RazorExpressionStyle { get; set; }\n        public Style RazorOperatorStyle { get; set; }\n\n        #endregion\n    }\n\n    /// <summary>\n    /// Language\n    /// </summary>\n    public enum Language\n    {\n        Razor\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/TextSource.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Collections;\nusing System.Drawing;\nusing System.IO;\n\nnamespace FastColoredTextBoxNS\n{\n    /// <summary>\n    /// This class contains the source text (chars and styles).\n    /// It stores a text lines, the manager of commands, undo/redo stack, styles.\n    /// </summary>\n    public class TextSource : IList<Line>, IDisposable\n    {\n        readonly protected List<Line> lines = new List<Line>();\n        protected LinesAccessor linesAccessor;\n        int lastLineUniqueId;\n        public CommandManager Manager { get; set; }\n        FastColoredTextBox currentTB;\n\n        /// <summary>\n        /// Styles\n        /// </summary>\n        public readonly Style[] Styles;\n\n        /// <summary>\n        /// Occurs when line was inserted/added\n        /// </summary>\n        public event EventHandler<LineInsertedEventArgs> LineInserted;\n\n        /// <summary>\n        /// Occurs when line was removed\n        /// </summary>\n        public event EventHandler<LineRemovedEventArgs> LineRemoved;\n\n        /// <summary>\n        /// Occurs when text was changed\n        /// </summary>\n        public event EventHandler<TextChangedEventArgs> TextChanged;\n\n        /// <summary>\n        /// Occurs when recalc is needed\n        /// </summary>\n        public event EventHandler<TextChangedEventArgs> RecalcNeeded;\n\n        /// <summary>\n        /// Occurs when recalc wordwrap is needed\n        /// </summary>\n        public event EventHandler<TextChangedEventArgs> RecalcWordWrap;\n\n        /// <summary>\n        /// Occurs before text changing\n        /// </summary>\n        public event EventHandler<TextChangingEventArgs> TextChanging;\n\n        /// <summary>\n        /// Occurs after CurrentTB was changed\n        /// </summary>\n        public event EventHandler CurrentTBChanged;\n\n        /// <summary>\n        /// Current focused FastColoredTextBox\n        /// </summary>\n        public FastColoredTextBox CurrentTB\n        {\n            get { return currentTB; }\n            set\n            {\n                if (currentTB == value)\n                    return;\n                currentTB = value;\n                OnCurrentTBChanged();\n            }\n        }\n\n        public virtual void ClearIsChanged()\n        {\n            foreach (var line in lines)\n                line.IsChanged = false;\n        }\n\n        public virtual Line CreateLine()\n        {\n            return new Line(GenerateUniqueLineId());\n        }\n\n        private void OnCurrentTBChanged()\n        {\n            if (CurrentTBChanged != null)\n                CurrentTBChanged(this, EventArgs.Empty);\n        }\n\n        /// <summary>\n        /// Default text style\n        /// This style is using when no one other TextStyle is not defined in Char.style\n        /// </summary>\n        public TextStyle DefaultStyle { get; set; }\n\n        public TextSource(FastColoredTextBox currentTB)\n        {\n            this.CurrentTB = currentTB;\n            linesAccessor = new LinesAccessor(this);\n            Manager = new CommandManager(this);\n\n            if (Enum.GetUnderlyingType(typeof(StyleIndex)) == typeof(UInt32))\n                Styles = new Style[32];\n            else\n                Styles = new Style[16];\n\n            InitDefaultStyle();\n        }\n\n        public virtual void InitDefaultStyle()\n        {\n            DefaultStyle = new TextStyle(null, null, FontStyle.Regular);\n        }\n\n        public virtual Line this[int i]\n        {\n            get { return lines[i]; }\n            set { throw new NotImplementedException(); }\n        }\n\n        public virtual bool IsLineLoaded(int iLine)\n        {\n            return lines[iLine] != null;\n        }\n\n        /// <summary>\n        /// Text lines\n        /// </summary>\n        public virtual IList<string> GetLines()\n        {\n            return linesAccessor;\n        }\n\n        public IEnumerator<Line> GetEnumerator()\n        {\n            return lines.GetEnumerator();\n        }\n\n        IEnumerator System.Collections.IEnumerable.GetEnumerator()\n        {\n            return (lines as IEnumerator);\n        }\n\n        public virtual int BinarySearch(Line item, IComparer<Line> comparer)\n        {\n            return lines.BinarySearch(item, comparer);\n        }\n\n        public virtual int GenerateUniqueLineId()\n        {\n            return lastLineUniqueId++;\n        }\n\n        public virtual void InsertLine(int index, Line line)\n        {\n            lines.Insert(index, line);\n            OnLineInserted(index);\n        }\n\n        public virtual void OnLineInserted(int index)\n        {\n            OnLineInserted(index, 1);\n        }\n\n        public virtual void OnLineInserted(int index, int count)\n        {\n            if (LineInserted != null)\n                LineInserted(this, new LineInsertedEventArgs(index, count));\n        }\n\n        public virtual void RemoveLine(int index)\n        {\n            RemoveLine(index, 1);\n        }\n\n        public virtual bool IsNeedBuildRemovedLineIds\n        {\n            get { return LineRemoved != null; }\n        }\n\n        public virtual void RemoveLine(int index, int count)\n        {\n            List<int> removedLineIds = new List<int>();\n            //\n            if (count > 0)\n                if (IsNeedBuildRemovedLineIds)\n                    for (int i = 0; i < count; i++)\n                        removedLineIds.Add(this[index + i].UniqueId);\n            //\n            lines.RemoveRange(index, count);\n\n            OnLineRemoved(index, count, removedLineIds);\n        }\n\n        public virtual void OnLineRemoved(int index, int count, List<int> removedLineIds)\n        {\n            if (count > 0)\n                if (LineRemoved != null)\n                    LineRemoved(this, new LineRemovedEventArgs(index, count, removedLineIds));\n        }\n\n        public virtual void OnTextChanged(int fromLine, int toLine)\n        {\n            if (TextChanged != null)\n                TextChanged(this, new TextChangedEventArgs(Math.Min(fromLine, toLine), Math.Max(fromLine, toLine)));\n        }\n\n        public class TextChangedEventArgs : EventArgs\n        {\n            public int iFromLine;\n            public int iToLine;\n\n            public TextChangedEventArgs(int iFromLine, int iToLine)\n            {\n                this.iFromLine = iFromLine;\n                this.iToLine = iToLine;\n            }\n        }\n\n        public virtual int IndexOf(Line item)\n        {\n            return lines.IndexOf(item);\n        }\n\n        public virtual void Insert(int index, Line item)\n        {\n            InsertLine(index, item);\n        }\n\n        public virtual void RemoveAt(int index)\n        {\n            RemoveLine(index);\n        }\n\n        public virtual void Add(Line item)\n        {\n            InsertLine(Count, item);\n        }\n\n        public virtual void Clear()\n        {\n            RemoveLine(0, Count);\n        }\n\n        public virtual bool Contains(Line item)\n        {\n            return lines.Contains(item);\n        }\n\n        public virtual void CopyTo(Line[] array, int arrayIndex)\n        {\n            lines.CopyTo(array, arrayIndex);\n        }\n\n        /// <summary>\n        /// Lines count\n        /// </summary>\n        public virtual int Count\n        {\n            get { return lines.Count; }\n        }\n\n        public virtual bool IsReadOnly\n        {\n            get { return false; }\n        }\n\n        public virtual bool Remove(Line item)\n        {\n            int i = IndexOf(item);\n            if (i >= 0)\n            {\n                RemoveLine(i);\n                return true;\n            }\n            else\n                return false;\n        }\n\n        public virtual void NeedRecalc(TextChangedEventArgs args)\n        {\n            if (RecalcNeeded != null)\n                RecalcNeeded(this, args);\n        }\n\n        public virtual void OnRecalcWordWrap(TextChangedEventArgs args)\n        {\n            if (RecalcWordWrap != null)\n                RecalcWordWrap(this, args);\n        }\n\n        public virtual void OnTextChanging()\n        {\n            string temp = null;\n            OnTextChanging(ref temp);\n        }\n\n        public virtual void OnTextChanging(ref string text)\n        {\n            if (TextChanging != null)\n            {\n                var args = new TextChangingEventArgs() {InsertingText = text};\n                TextChanging(this, args);\n                text = args.InsertingText;\n                if (args.Cancel)\n                    text = string.Empty;\n            }\n\n            ;\n        }\n\n        public virtual int GetLineLength(int i)\n        {\n            return lines[i].Count;\n        }\n\n        public virtual bool LineHasFoldingStartMarker(int iLine)\n        {\n            return !string.IsNullOrEmpty(lines[iLine].FoldingStartMarker);\n        }\n\n        public virtual bool LineHasFoldingEndMarker(int iLine)\n        {\n            return !string.IsNullOrEmpty(lines[iLine].FoldingEndMarker);\n        }\n\n        public virtual void Dispose()\n        {\n            ;\n        }\n\n        public virtual void SaveToFile(string fileName, Encoding enc)\n        {\n            using (StreamWriter sw = new StreamWriter(fileName, false, enc))\n            {\n                for (int i = 0; i < Count - 1; i++)\n                    sw.WriteLine(lines[i].Text);\n\n                sw.Write(lines[Count - 1].Text);\n            }\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/TypeDescriptor.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    ///\n    /// These classes are required for correct data binding to Text property of FastColoredTextbox\n    /// \n    class FCTBDescriptionProvider : TypeDescriptionProvider\n    {\n        public FCTBDescriptionProvider(Type type)\n            : base(GetDefaultTypeProvider(type))\n        {\n        }\n\n        private static TypeDescriptionProvider GetDefaultTypeProvider(Type type)\n        {\n            return TypeDescriptor.GetProvider(type);\n        }\n\n\n        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)\n        {\n            ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);\n            return new FCTBTypeDescriptor(defaultDescriptor, instance);\n        }\n    }\n\n    class FCTBTypeDescriptor : CustomTypeDescriptor\n    {\n        ICustomTypeDescriptor parent;\n        object instance;\n\n        public FCTBTypeDescriptor(ICustomTypeDescriptor parent, object instance)\n            : base(parent)\n        {\n            this.parent = parent;\n            this.instance = instance;\n        }\n\n        public override string GetComponentName()\n        {\n            var ctrl = (instance as Control);\n            return ctrl == null ? null : ctrl.Name;\n        }\n\n        public override EventDescriptorCollection GetEvents()\n        {\n            var coll = base.GetEvents();\n            var list = new EventDescriptor[coll.Count];\n\n            for (int i = 0; i < coll.Count; i++)\n                if (coll[i].Name == \"TextChanged\") //instead of TextChanged slip BindingTextChanged for binding\n                    list[i] = new FooTextChangedDescriptor(coll[i]);\n                else\n                    list[i] = coll[i];\n\n            return new EventDescriptorCollection(list);\n        }\n    }\n\n    class FooTextChangedDescriptor : EventDescriptor\n    {\n        public FooTextChangedDescriptor(MemberDescriptor desc)\n            : base(desc)\n        {\n        }\n\n        public override void AddEventHandler(object component, Delegate value)\n        {\n            (component as FastColoredTextBox).BindingTextChanged += value as EventHandler;\n        }\n\n        public override Type ComponentType\n        {\n            get { return typeof(FastColoredTextBox); }\n        }\n\n        public override Type EventType\n        {\n            get { return typeof(EventHandler); }\n        }\n\n        public override bool IsMulticast\n        {\n            get { return true; }\n        }\n\n        public override void RemoveEventHandler(object component, Delegate value)\n        {\n            (component as FastColoredTextBox).BindingTextChanged -= value as EventHandler;\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/UnfocusablePanel.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    [System.ComponentModel.ToolboxItem(false)]\n    public class UnfocusablePanel : UserControl\n    {\n        public Color BackColor2 { get; set; }\n        public Color BorderColor { get; set; }\n        public new string Text { get; set; }\n        public StringAlignment TextAlignment { get; set; }\n\n        public UnfocusablePanel()\n        {\n            SetStyle(ControlStyles.Selectable, false);\n            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint,\n                true);\n        }\n\n        protected override void OnPaint(PaintEventArgs e)\n        {\n            using (var brush = new LinearGradientBrush(ClientRectangle, BackColor2, BackColor, 90))\n                e.Graphics.FillRectangle(brush, 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);\n            using (var pen = new Pen(BorderColor))\n                e.Graphics.DrawRectangle(pen, 0, 0, ClientSize.Width - 1, ClientSize.Height - 1);\n\n            if (!string.IsNullOrEmpty(Text))\n            {\n                StringFormat sf = new StringFormat();\n                sf.Alignment = TextAlignment;\n                sf.LineAlignment = StringAlignment.Center;\n                using (var brush = new SolidBrush(ForeColor))\n                    e.Graphics.DrawString(Text, Font, brush,\n                        new RectangleF(1, 1, ClientSize.Width - 2, ClientSize.Height - 2), sf);\n            }\n        }\n    }\n}"
  },
  {
    "path": "FastColoredTextBox/VisualMarker.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Drawing;\nusing System.Windows.Forms;\n\nnamespace FastColoredTextBoxNS\n{\n    public class VisualMarker\n    {\n        public readonly Rectangle rectangle;\n\n        public VisualMarker(Rectangle rectangle)\n        {\n            this.rectangle = rectangle;\n        }\n\n        public virtual void Draw(Graphics gr, Pen pen)\n        {\n        }\n\n        public virtual Cursor Cursor\n        {\n            get { return Cursors.Hand; }\n        }\n    }\n\n    public class CollapseFoldingMarker : VisualMarker\n    {\n        public readonly int iLine;\n\n        public CollapseFoldingMarker(int iLine, Rectangle rectangle)\n            : base(rectangle)\n        {\n            this.iLine = iLine;\n        }\n\n        public void Draw(Graphics gr, Pen pen, Brush backgroundBrush, Pen forePen)\n        {\n            //draw minus\n            gr.FillRectangle(backgroundBrush, rectangle);\n            gr.DrawRectangle(pen, rectangle);\n            gr.DrawLine(forePen, rectangle.Left + 2, rectangle.Top + rectangle.Height / 2, rectangle.Right - 2,\n                rectangle.Top + rectangle.Height / 2);\n        }\n    }\n\n    public class ExpandFoldingMarker : VisualMarker\n    {\n        public readonly int iLine;\n\n        public ExpandFoldingMarker(int iLine, Rectangle rectangle)\n            : base(rectangle)\n        {\n            this.iLine = iLine;\n        }\n\n        public void Draw(Graphics gr, Pen pen, Brush backgroundBrush, Pen forePen)\n        {\n            //draw plus\n            gr.FillRectangle(backgroundBrush, rectangle);\n            gr.DrawRectangle(pen, rectangle);\n            gr.DrawLine(forePen, rectangle.Left + 2, rectangle.Top + rectangle.Height / 2, rectangle.Right - 2,\n                rectangle.Top + rectangle.Height / 2);\n            gr.DrawLine(forePen, rectangle.Left + rectangle.Width / 2, rectangle.Top + 2,\n                rectangle.Left + rectangle.Width / 2, rectangle.Bottom - 2);\n        }\n    }\n\n    public class FoldedAreaMarker : VisualMarker\n    {\n        public readonly int iLine;\n\n        public FoldedAreaMarker(int iLine, Rectangle rectangle)\n            : base(rectangle)\n        {\n            this.iLine = iLine;\n        }\n\n        public override void Draw(Graphics gr, Pen pen)\n        {\n            gr.DrawRectangle(pen, rectangle);\n        }\n    }\n\n    public class StyleVisualMarker : VisualMarker\n    {\n        public Style Style { get; private set; }\n\n        public StyleVisualMarker(Rectangle rectangle, Style style)\n            : base(rectangle)\n        {\n            this.Style = style;\n        }\n    }\n\n    public class VisualMarkerEventArgs : MouseEventArgs\n    {\n        public Style Style { get; private set; }\n        public StyleVisualMarker Marker { get; private set; }\n\n        public VisualMarkerEventArgs(Style style, StyleVisualMarker marker, MouseEventArgs args)\n            : base(args.Button, args.Clicks, args.X, args.Y, args.Delta)\n        {\n            this.Style = style;\n            this.Marker = marker;\n        }\n    }\n}"
  },
  {
    "path": "INSTALL.md",
    "content": "# Installation\n\nThese steps assume that you already have obtained and installed the Ultima Online game asset files in the local system and want to install ClassicUO and Razor for the first time.\n\nFor information on installing Razor on Windows, [please read this guide](https://www.razorce.com/install/windows/).\n\nFor information on installing Razor on Linux, [please read this guide](https://www.razorce.com/install/linux/)."
  },
  {
    "path": "LICENSE.md",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "Loader/Loader.cpp",
    "content": "\r\n#include \"stdafx.h\"\r\n\r\nBOOL APIENTRY DllMain( HANDLE hModule, DWORD dwReason, LPVOID lpReserved )\r\n{\r\n\tswitch ( dwReason )\r\n\t{\r\n\tcase DLL_PROCESS_ATTACH:\r\n\t\tDisableThreadLibraryCalls( (HMODULE)hModule );\r\n\t\tbreak;\r\n\t}\r\n\r\n    return TRUE;\r\n}\r\n\r\nenum ERROR_TYPE\r\n{\r\n\tSUCCESS = 0,\r\n\tNO_OPEN_EXE,\r\n\tNO_MAP_EXE,\r\n\tNO_READ_EXE_DATA,\r\n\r\n\tNO_RUN_EXE,\r\n\tNO_ALLOC_MEM,\r\n\r\n\tNO_WRITE,\r\n\tNO_VPROTECT,\r\n\tNO_READ,\r\n\r\n\tUNKNOWN_ERROR = 99\r\n};\r\n\r\nextern \"C\" __declspec(dllexport) DWORD __stdcall Load( const char *exe, const char *dll, const char *func, const void *dllData, int dataLen, DWORD *pid )\r\n{\r\n\tSIZE_T Num;\r\n\tchar buff[MAX_PATH];\r\n\tLPVOID Entry;\r\n\tSTARTUPINFO StartInfo;\r\n\tPROCESS_INFORMATION ProcInfo;\r\n\tIMAGE_DOS_HEADER idh;\r\n\tIMAGE_OPTIONAL_HEADER32 ioh;\r\n\r\n\tFILE* pExe;\r\n\tif (fopen_s(&pExe, exe, \"rb\") != 0)\r\n\t{\r\n\t    buff[0] = 0;\r\n\t    if (GetShortPathName(exe, buff, MAX_PATH) >= MAX_PATH)\r\n\t\t   buff[0] = 0;\r\n\t    if (fopen_s(&pExe, buff, \"rb\") != 0)\r\n\t\t   return NO_OPEN_EXE;\r\n\t}\r\n\r\n\tif ( fread( &idh, 1, sizeof(IMAGE_DOS_HEADER), pExe ) != sizeof(IMAGE_DOS_HEADER) )\r\n\t{\r\n\t\tfclose( pExe );\r\n\t\treturn NO_READ_EXE_DATA;\r\n\t}\r\n\r\n\tfseek( pExe, idh.e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER), SEEK_SET );\r\n\tif ( fread( &ioh, 1, sizeof(IMAGE_OPTIONAL_HEADER32), pExe ) != sizeof(IMAGE_OPTIONAL_HEADER32) )\r\n\t{\r\n\t\tfclose( pExe );\r\n\t\treturn NO_READ_EXE_DATA;\r\n\t}\r\n\r\n\tEntry = (LPVOID)(ioh.ImageBase + ioh.AddressOfEntryPoint);\r\n\t\r\n\t//sprintf( buff, \"magic: %X\\nlfanew: %X\\nimg_base: %X\\naoep: %X\\nmagic2: %X\", idh.e_magic, idh.e_lfanew, ioh.ImageBase, ioh.AddressOfEntryPoint, ioh.Magic );\r\n\t//MessageBox( NULL, buff, \"Error\", MB_OK );\r\n\r\n\tfclose( pExe );\r\n\r\n\t// find the exe's working directory\r\n\tstrcpy_s(buff, exe);\r\n\r\n\tint i=(int)strlen(buff);\r\n\twhile ( buff[i] != '\\\\' && buff[i] != '/' && i > 0 )\r\n\t\ti--;\r\n\tbuff[i] = 0;\r\n\r\n\t//GetStartupInfo( &StartInfo );\r\n\tmemset( &StartInfo, 0, sizeof(STARTUPINFO) );\r\n\tStartInfo.cb = sizeof(STARTUPINFO);\r\n\r\n\t// launch the exe\r\n\tif ( !CreateProcess( exe, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, buff, &StartInfo, &ProcInfo ) )\r\n\t\treturn NO_RUN_EXE;\r\n\r\n\t*pid = ProcInfo.dwProcessId;\r\n\r\n\tint dllNameLen = (int)strlen(dll)+1;\r\n\tint funcNameLen = (int)strlen(func)+1;\r\n\tconst int LoadAsmSize = 60;\r\n\tSIZE_T allocSize = dllNameLen + funcNameLen + dataLen + LoadAsmSize;\r\n\r\n\t// allocate some space in the exe for our memory\r\n\tDWORD ProcMem = 0;\r\n\t\r\n\tProcMem = (DWORD)VirtualAllocEx( ProcInfo.hProcess, NULL, allocSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE );\r\n\tif ( !ProcMem )\r\n\t{\r\n\t\tProcMem = 0x00700000;\r\n\t\tif ( !VirtualProtectEx( ProcInfo.hProcess, (LPVOID)ProcMem, allocSize, PAGE_EXECUTE_READWRITE, (PDWORD)&Num ) )\r\n\t\t{\r\n\t\t\tTerminateProcess( ProcInfo.hProcess, 0 );\r\n\t\t\treturn NO_ALLOC_MEM;\r\n\t\t}\r\n\t}\r\n\r\n\tchar *toWrite = new char[allocSize];\r\n\tif ( !toWrite )\r\n\t{\r\n\t\tTerminateProcess( ProcInfo.hProcess, 0 );\r\n\t\treturn NO_ALLOC_MEM;\r\n\t}\r\n\r\n\t// change protection to allow us to read/write the entry point (note: the old protection is not restored (so that we can change this space again later...)\r\n\tif ( !VirtualProtectEx( ProcInfo.hProcess, Entry, 8, PAGE_EXECUTE_READWRITE, (PDWORD)&Num ) )\r\n\t{\r\n\t\tTerminateProcess( ProcInfo.hProcess, 0 );\r\n\t\treturn NO_VPROTECT;\r\n\t}\r\n\t\r\n\t// read the old code at the entry point\r\n\tif ( !ReadProcessMemory( ProcInfo.hProcess, Entry, buff, 8, &Num ) || Num != 8 )\r\n\t{\r\n\t\tTerminateProcess( ProcInfo.hProcess, 0 );\r\n\t\treturn NO_READ;\r\n\t}\r\n\r\n\t// note if you change this size you must rewrite the LoadAsm to copy back the original code properly\r\n\tunsigned char EntryAsm[] = {\r\n\t\t0xE9, 0,0,0,0,\t\t\t// jmp (offset)\r\n\t\t0x90,0x90,0x90,\t\t\t// nop (for 4 byte alignment)\r\n\t};\r\n\r\n\t*((DWORD*)&EntryAsm[1]) = ProcMem - ((DWORD)Entry + 5);\r\n\r\n\t// write the new code at the entry point\r\n\tif ( !WriteProcessMemory( ProcInfo.hProcess, Entry, EntryAsm, 8, &Num ) || Num != 8 )\r\n\t{\r\n\t\tTerminateProcess( ProcInfo.hProcess, 0 );\r\n\t\treturn NO_WRITE;\r\n\t}\r\n\r\n\t// this asm section does everything\r\n\tunsigned char LoadAsm[LoadAsmSize] = {\r\n\t\t// restore the original entry point bytes\r\n\t\t0xB8, 0,0,0,0,\t\t\t// mov     eax, (number)\r\n\t\t0xC7, 0x00, 0,0,0,0,\t// mov     dword ptr [eax], (num)\r\n\t\t0xC7, 0x40, 4, 0,0,0,0, // mov     dword ptr [eax+4], (num)\r\n\r\n\t\t// LoadLibrary( name )\r\n\t\t0x68, 0,0,0,0,\t\t\t// push (num)\r\n\t\t0xE8, 0,0,0,0,\t\t\t// call (offset)\r\n\r\n\t\t// GetProcAddress( lib, name )\r\n\t\t0x68, 0,0,0,0,\t\t\t// push (num)\r\n\t\t0x50,\t\t\t\t\t// push eax\r\n\t\t0xE8, 0,0,0,0,\t\t\t// call (offset)\r\n\r\n\t\t// name( data, dataLen )\r\n\t\t0x68, 0,0,0,0,\t\t\t// push (num)\r\n\t\t0x68, 0,0,0,0,\t\t\t// push (num)\r\n\t\t0xFF, 0xD0,\t\t\t\t// call eax\r\n\r\n\t\t// go back to the original entry point\r\n\t\t0xE9, 0,0,0,0,\t\t\t// jmp  (offset)\r\n\t\t\r\n\t\t0x90, 0x90, 0x90, 0x90,\t// nop (padding)\r\n\t};\r\n\r\n\t*((DWORD*)(LoadAsm+ 1)) = (DWORD)Entry; // data dest\r\n\t*((DWORD*)(LoadAsm+ 7)) = *((DWORD*)&buff[0]); // 1st data \r\n\t*((DWORD*)(LoadAsm+14)) = *((DWORD*)&buff[4]); // 2nd data\r\n\r\n\tHMODULE hKernel = LoadLibrary( \"Kernel32\" );\r\n\r\n\t*((DWORD*)(LoadAsm+19)) = (ProcMem + LoadAsmSize); // begining of dll name\r\n\t*((DWORD*)(LoadAsm+24)) = ((DWORD)GetProcAddress( hKernel, \"LoadLibraryA\" )) - (ProcMem + 28); // offset to LoadLibraryA\r\n\t\r\n\t*((DWORD*)(LoadAsm+29)) = (ProcMem + LoadAsmSize + dllNameLen); // begining of function name\r\n\t*((DWORD*)(LoadAsm+35)) = ((DWORD)GetProcAddress( hKernel, \"GetProcAddress\" )) - (ProcMem + 39); // offset to GetProcAddress\r\n\r\n\tFreeLibrary( hKernel );\r\n\r\n\t*((DWORD*)(LoadAsm+40)) = dataLen; // user data Length\r\n\t*((DWORD*)(LoadAsm+45)) = ProcMem + LoadAsmSize + dllNameLen + funcNameLen; // begining of user data\r\n\t*((DWORD*)(LoadAsm+52)) = (DWORD)Entry - (ProcMem + 56); // entry points\r\n\r\n\tmemcpy( toWrite, LoadAsm, LoadAsmSize );\r\n\tmemcpy( &toWrite[LoadAsmSize], dll, dllNameLen );\r\n\tmemcpy( &toWrite[LoadAsmSize+dllNameLen], func, funcNameLen );\r\n\r\n\tif ( dataLen > 0 )\r\n\t\tmemcpy( &toWrite[LoadAsmSize+dllNameLen+funcNameLen], dllData, dataLen );\r\n\r\n\tif ( !WriteProcessMemory( ProcInfo.hProcess, (void*)ProcMem, toWrite, allocSize, &Num ) || Num != allocSize )\r\n\t{\r\n\t\tTerminateProcess( ProcInfo.hProcess, 0 );\r\n\t\treturn NO_WRITE;\r\n\t}\r\n\r\n\tdelete[] toWrite;\r\n\r\n\t*pid = ProcInfo.dwProcessId;\r\n\r\n\tResumeThread( ProcInfo.hThread );\r\n\r\n\tCloseHandle( ProcInfo.hProcess );\r\n\tCloseHandle( ProcInfo.hThread );\r\n\r\n\treturn SUCCESS;\r\n}\r\n"
  },
  {
    "path": "Loader/Loader.def",
    "content": "LIBRARY\tLoader\r\n\r\nEXPORTS\r\n\tLoad\r\n"
  },
  {
    "path": "Loader/Loader.h",
    "content": "// The following ifdef block is the standard way of creating macros which make exporting \r\n// from a DLL simpler. All files within this DLL are compiled with the LOADER_EXPORTS\r\n// symbol defined on the command line. this symbol should not be defined on any project\r\n// that uses this DLL. This way any other project whose source files include this file see \r\n// LOADER_API functions as being imported from a DLL, whereas this DLL sees symbols\r\n// defined with this macro as being exported.\r\n#ifdef LOADER_EXPORTS\r\n#define LOADER_API __declspec(dllexport)\r\n#else\r\n#define LOADER_API __declspec(dllimport)\r\n#endif\r\n\r\n// This class is exported from the Loader.dll\r\nclass LOADER_API CLoader {\r\npublic:\r\n\tCLoader(void);\r\n\t// TODO: add your methods here.\r\n};\r\n\r\nextern LOADER_API int nLoader;\r\n\r\nLOADER_API int fnLoader(void);\r\n"
  },
  {
    "path": "Loader/Loader.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}</ProjectGuid>\r\n    <RootNamespace>Loader</RootNamespace>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <CharacterSet>MultiByte</CharacterSet>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\r\n    <CharacterSet>MultiByte</CharacterSet>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup>\r\n    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <OutDir>$(SolutionDir)bin\\$(Platform)\\$(Configuration)\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <OutDir>$(SolutionDir)bin\\$(Platform)\\$(Configuration)\\</OutDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <Optimization>Disabled</Optimization>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LOADER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <MinimalRebuild>\r\n      </MinimalRebuild>\r\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r\n    </ClCompile>\r\n    <Link>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <TargetMachine>MachineX86</TargetMachine>\r\n      <ModuleDefinitionFile>Loader.def</ModuleDefinitionFile>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\r\n      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;LOADER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n      <BufferSecurityCheck>false</BufferSecurityCheck>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <DebugInformationFormat>\r\n      </DebugInformationFormat>\r\n    </ClCompile>\r\n    <Link>\r\n      <ModuleDefinitionFile>Loader.def</ModuleDefinitionFile>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <TargetMachine>MachineX86</TargetMachine>\r\n    </Link>\r\n    <PreBuildEvent>\r\n      <Command>\r\n      </Command>\r\n    </PreBuildEvent>\r\n    <PostBuildEvent />\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"Loader.cpp\" />\r\n    <ClCompile Include=\"stdafx.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"resource.h\" />\r\n    <ClInclude Include=\"stdafx.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"Loader.rc\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "Loader/Loader.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r\n      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"Loader.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"stdafx.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"stdafx.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"resource.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"Loader.rc\">\r\n      <Filter>Resource Files</Filter>\r\n    </ResourceCompile>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "Loader/stdafx.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\r\n// Loader.pch will be the pre-compiled header\r\n// stdafx.obj will contain the pre-compiled type information\r\n\r\n#include \"stdafx.h\"\r\n\r\n// TODO: reference any additional headers you need in STDAFX.H\r\n// and not in this file\r\n"
  },
  {
    "path": "Loader/stdafx.h",
    "content": "// stdafx.h : include file for standard system include files,\r\n// or project specific include files that are used frequently, but\r\n// are changed infrequently\r\n//\r\n\r\n#pragma once\r\n#pragma warning(disable: 4309)\r\n#pragma warning(disable: 4311)\r\n#pragma warning(disable: 4312)\r\n#pragma warning(disable: 4800)\r\n#pragma warning(disable: 4530)\r\n\r\n#define WIN32_LEAN_AND_MEAN\t\t// Exclude rarely-used stuff from Windows headers\r\n// Windows Header Files:\r\n#include <windows.h>\r\n\r\n#pragma pack(1)\r\n\r\n#include <stdio.h>\r\n"
  },
  {
    "path": "Notepad++UDL.xml",
    "content": "<NotepadPlus>\n    <UserLang name=\"Razor\" ext=\"\" udlVersion=\"2.1\">\n        <Settings>\n            <Global caseIgnored=\"no\" allowFoldOfComments=\"no\" foldCompact=\"no\" forcePureLC=\"0\" decimalSeparator=\"0\" />\n            <Prefix Keywords1=\"no\" Keywords2=\"no\" Keywords3=\"no\" Keywords4=\"no\" Keywords5=\"no\" Keywords6=\"no\" Keywords7=\"no\" Keywords8=\"no\" />\n        </Settings>\n        <KeywordLists>\n            <Keywords name=\"Comments\">00// 00# 01 02 03/* 04*/</Keywords>\n            <Keywords name=\"Numbers, prefix1\">0x</Keywords>\n            <Keywords name=\"Numbers, prefix2\"></Keywords>\n            <Keywords name=\"Numbers, extras1\"></Keywords>\n            <Keywords name=\"Numbers, extras2\"></Keywords>\n            <Keywords name=\"Numbers, suffix1\"></Keywords>\n            <Keywords name=\"Numbers, suffix2\"></Keywords>\n            <Keywords name=\"Numbers, range\"></Keywords>\n            <Keywords name=\"Operators1\">= == != &lt; &lt;= &gt; &gt;= + - / * ( ) @ , !</Keywords>\n            <Keywords name=\"Operators2\"></Keywords>\n            <Keywords name=\"Folders in code1, open\"></Keywords>\n            <Keywords name=\"Folders in code1, middle\"></Keywords>\n            <Keywords name=\"Folders in code1, close\"></Keywords>\n            <Keywords name=\"Folders in code2, open\"></Keywords>\n            <Keywords name=\"Folders in code2, middle\"></Keywords>\n            <Keywords name=\"Folders in code2, close\"></Keywords>\n            <Keywords name=\"Folders in comment, open\"></Keywords>\n            <Keywords name=\"Folders in comment, middle\"></Keywords>\n            <Keywords name=\"Folders in comment, close\"></Keywords>\n            <Keywords name=\"Keywords1\">if else elseif endif for endfor while endwhile and break continue loop replay not or stop</Keywords>\n            <Keywords name=\"Keywords2\">alliance attack cast clearall clearhands clearsysmsg dclick dclicktype dress drop droprelloc emote guild gumpresponse gumpclose hotkey lasttarget lift lifttype menu menuresponse organizer overhead potion promptresponse random restock say script scavenger sell setability setlasttarget setvar skill sysmsg target targetrelloc targetloc targettype undress useonce virtue walk wait &amp; pause waitforgump waitformenu waitforprompt waitforsysmsg waitfortarget whisper yell</Keywords>\n            <Keywords name=\"Keywords3\">count counter findbuff findtype hidden hp maxhp hits maxhits insysmsg insysmessage lhandempty&#x000D;&#x000A;mana maxmana mounted poisoned position&#x000D;&#x000A;queued rhandempty skill stam maxstam str dex int weight</Keywords>\n            <Keywords name=\"Keywords4\">true false</Keywords>\n            <Keywords name=\"Keywords5\">backpack self anatomy animallore itemidentification itemid armslore begging peacemaking peace cartography detectinghidden discord discordance evaluatingintelligence evalint forensicevaluation forensiceval hiding provocation provo inscription poisoning spiritspeak stealing taming tasteidentification tasteid tracking meditation stealth removetrap imbuing nonfriendly friendly enemy red murderer gray grey criminal blue innocent friend RightHand LeftHand Shoes Pants Shirt Head Gloves Ring Talisman Neck Hair Waist InnerTorso Face Bracelet FacialHair MiddleTorso Earrings Arms Cloak Backpack OuterTorso OuterLegs InnerLegs</Keywords>\n            <Keywords name=\"Keywords6\"></Keywords>\n            <Keywords name=\"Keywords7\"></Keywords>\n            <Keywords name=\"Keywords8\"></Keywords>\n            <Keywords name=\"Delimiters\">00&apos; 01\\ 02&apos; 03 04 05 06&quot; 07\\ 08&quot; 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords>\n        </KeywordLists>\n        <Styles>\n            <WordsStyle name=\"DEFAULT\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"COMMENTS\" fgColor=\"808080\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"LINE COMMENTS\" fgColor=\"808080\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"NUMBERS\" fgColor=\"0080C0\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS1\" fgColor=\"DD4800\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS2\" fgColor=\"000080\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS3\" fgColor=\"830E11\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS4\" fgColor=\"0080C0\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS5\" fgColor=\"AE00AE\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS6\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS7\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"KEYWORDS8\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"OPERATORS\" fgColor=\"FF0000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"FOLDER IN CODE1\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"FOLDER IN CODE2\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"FOLDER IN COMMENT\" fgColor=\"8080FF\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS1\" fgColor=\"008000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS2\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS3\" fgColor=\"008000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS4\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS5\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS6\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS7\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n            <WordsStyle name=\"DELIMITERS8\" fgColor=\"000000\" bgColor=\"FFFFFF\" fontName=\"\" fontStyle=\"0\" nesting=\"0\" />\n        </Styles>\n    </UserLang>\n</NotepadPlus>\n"
  },
  {
    "path": "Platform/Platform.cpp",
    "content": "#include \"Platform.h\"\n\nHINSTANCE hInstance = NULL;\nHICON hRazorIcon = NULL;\nHFONT hRazorFont = NULL;\n\nBOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID)\n{\n\thInstance = (HMODULE)hModule;\n\n\tswitch (dwReason) {\n\tcase DLL_PROCESS_ATTACH:\n\t\tDisableThreadLibraryCalls(hInstance);\n\t\tbreak;\n\n\tcase DLL_PROCESS_DETACH:\n\t\tbreak;\n\n\tcase DLL_THREAD_ATTACH:\n\tcase DLL_THREAD_DETACH:\n\t\tbreak;\n\t}\n\n\treturn TRUE;\n}\n\nDLLFUNCTION HBITMAP CaptureScreen(HWND hUOWindow, BOOL full, const char *msg)\n{\n\tHDC hScreen = NULL;\n\tint destWidth, destHeight;\n\tRECT rect;\n\n\tif (!hRazorFont)\n\t\thRazorFont = CreateFont(-10, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, FIXED_PITCH, \"Comic Sans MS\");\n\n\tUpdateWindow(hUOWindow);\n\n\tif (full)\n\t{\n\t\thScreen = GetDC(NULL);\n\t\trect.left = 0;\n\t\trect.top = 0;\n\t\tdestWidth = GetDeviceCaps(hScreen, HORZRES);\n\t\tdestHeight = GetDeviceCaps(hScreen, VERTRES);\n\t}\n\telse\n\t{\n\t\thScreen = GetWindowDC(hUOWindow);\n\t\tGetWindowRect(hUOWindow, &rect);\n\t\tdestWidth = rect.right - rect.left;\n\t\tdestHeight = rect.bottom - rect.top;\n\t}\n\n\tHDC hCap = CreateCompatibleDC(hScreen);\n\tHBITMAP hBMP = CreateCompatibleBitmap(hScreen, destWidth, destHeight);\n\tSelectObject(hCap, hBMP);\n\n\tBitBlt(hCap, 0, 0, destWidth, destHeight, hScreen, 0, 0, SRCCOPY);\n\n\tif (msg != NULL && msg[0] != 0)\n\t{\n\t\tSIZE text;\n\t\tint len = (int)strlen(msg);\n\t\tSelectObject(hCap, hRazorFont);\n\t\tSetTextColor(hCap, RGB(255, 255, 255));\n\t\tSetBkMode(hCap, TRANSPARENT);\n\n\t\tGetTextExtentPoint32(hCap, msg, len, &text);\n\n\t\trect.top = 0;\n\t\trect.bottom = text.cy + 4;\n\t\trect.right = destWidth - 32;\n\t\trect.left = destWidth - 32 - text.cx - 4;\n\t\tFillRect(hCap, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));\n\n\t\tTextOut(hCap, rect.left + 2, 2, msg, len);\n\t}\n\n\tReleaseDC(full ? NULL : hUOWindow, hScreen);\n\tDeleteDC(hCap);\n\n\treturn hBMP;\n}\n\nDLLFUNCTION void BringToFront(HWND hWnd)\n{\n\tSetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);\n\tShowWindow(hWnd, SW_SHOW);\n\tSetForegroundWindow(hWnd);\n\tSetFocus(hWnd);\n}"
  },
  {
    "path": "Platform/Platform.def",
    "content": "LIBRARY\tPlatform\n\nEXPORTS\n\tCaptureScreen\n\tBringToFront"
  },
  {
    "path": "Platform/Platform.h",
    "content": "#pragma once\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n#include <winsock2.h>\n#include <time.h>\n#include <zmouse.h>\n\n#define DLLFUNCTION __declspec(dllexport)\n\nDLLFUNCTION HBITMAP CaptureScreen(HWND hUOWindow, BOOL full, const char *msg);\nDLLFUNCTION void BringToFront(HWND hWnd);"
  },
  {
    "path": "Platform/Platform.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{DB18390C-8AD4-4E69-8A5A-171260F7D74A}</ProjectGuid>\n    <RootNamespace>Platform</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n    <ProjectName>Platform</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>$(SolutionDir)bin\\$(Platform)\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>$(SolutionDir)bin\\Win32\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>$(SolutionDir)bin\\$(Platform)\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>$(SolutionDir)bin\\Win32\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <CallingConvention>StdCall</CallingConvention>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n      <ExceptionHandling>Async</ExceptionHandling>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n    </ClCompile>\n    <Link>\n      <ModuleDefinitionFile>Platform.def</ModuleDefinitionFile>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <CallingConvention>StdCall</CallingConvention>\n      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\n      <ExceptionHandling>Async</ExceptionHandling>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n    </ClCompile>\n    <Link>\n      <ModuleDefinitionFile>Platform.def</ModuleDefinitionFile>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <CallingConvention>StdCall</CallingConvention>\n      <ExceptionHandling>Async</ExceptionHandling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <ModuleDefinitionFile>Platform.def</ModuleDefinitionFile>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <CallingConvention>StdCall</CallingConvention>\n      <ExceptionHandling>Async</ExceptionHandling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <BufferSecurityCheck>false</BufferSecurityCheck>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <ModuleDefinitionFile>Platform.def</ModuleDefinitionFile>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Platform.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Platform.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Platform.def\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Platform/Platform.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Platform.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"Platform.def\">\n      <Filter>Source Files</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Platform.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "README.md",
    "content": "# Razor: An Ultima Online Assistant\n\n![Razor Logo](https://imgur.com/jTtHLVF.png)\n\nRazor is a free tool designed to help with simple tasks while playing Ultima Online.\n\n[![Build](https://github.com/markdwags/Razor/actions/workflows/build.yml/badge.svg)](https://github.com/markdwags/Razor/actions/workflows/build.yml) [![Chat on Discord status](https://img.shields.io/discord/458277173208547350.svg?logo=discord)](https://discord.gg/VdyCpjQ)\n\n## Community Edition (CE)\n\nThe goal of this project is to revive and continue development and maintenance of the abandoned Razor project, focusing on \"quality of life\" improvements while attempting to keep the spirit and vision the original developers had for Razor and not driving down the path of advanced automation and scripting that's found in other UO assistants.\n\nIt's recommended that you use the [ClassicUO](https://github.com/ClassicUO/ClassicUO) client with this version of Razor, however it should will work with the original 5.x and 7.x clients though support for any bugs may be limited.\n\nLearn more about this version of Razor by exploring the links below.\n\n- [Home](https://www.razorce.com)\n- [Download](https://www.razorce.com/download/)\n- [Release Notes](https://www.razorce.com/releasenotes/)\n- [Project History](https://www.razorce.com/history/)\n- [Help Overview](https://www.razorce.com/help/)\n- [Scripting Guide](https://www.razorce.com/guide/)\n\n## Installation & Help\n\n- [Installing Razor on Windows](https://www.razorce.com/install/windows/)\n- [Installing Razor on Linux](https://www.razorce.com/install/linux/)\n\nIf you need more help, [please go here](https://www.razorce.com/help) and review the documentation and/or join Discord and ask there.\n\n[![Chat on Discord status](https://img.shields.io/discord/458277173208547350.svg?logo=discord)](https://discord.gg/VdyCpjQ)\n\n## Razor Scripting Engine\n\nIntroduced in 1.6.4.2, Razor supports a command-based script language. For a comprehensive guide on the language and syntax, visit the [Razor Scripting Guide](https://www.razorce.com/guide/).\n\n## Contributing & Code of Conduct\n\nPlease read [CONTRIBUTING](CONTRIBUTING.md) for more information on how to contribute to this project.\n\nPlease note we have a [Code of Conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with this project.\n\n## License\n\nThis work is released under the GPLv3 license. This project does not distribute any copyrighted game assets. In order to run this application you'll need to legally obtain a copy of the Ultima Online Classic Client.\n\nSee the [LICENSE](LICENSE.md) file for details.\n"
  },
  {
    "path": "Razor/Agents/Agents.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public abstract class Agent\n    {\n        public static List<Agent> List { get; } = new List<Agent>();\n\n        public delegate void ItemCreatedEventHandler(Item item);\n\n        public delegate void MobileCreatedEventHandler(Mobile m);\n\n        public static event ItemCreatedEventHandler OnItemCreated;\n        public static event MobileCreatedEventHandler OnMobileCreated;\n\n        public static void InvokeMobileCreated(Mobile m)\n        {\n            if (OnMobileCreated != null)\n            {\n                OnMobileCreated(m);\n            }\n        }\n\n        public static void InvokeItemCreated(Item i)\n        {\n            if (OnItemCreated != null)\n            {\n                OnItemCreated(i);\n            }\n        }\n\n        public static void Add(Agent a)\n        {\n            List.Add(a);\n        }\n\n        public static void ClearAll()\n        {\n            for (int i = 0; i < List.Count; i++)\n            {\n                ((Agent) List[i]).Clear();\n            }\n        }\n\n        public static void SaveProfile(XmlTextWriter xml)\n        {\n            foreach (Agent a in List)\n            {\n                xml.WriteStartElement(a.Name);\n                a.Save(xml);\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void LoadProfile(XmlElement xml)\n        {\n            ClearAll();\n\n            if (xml == null)\n            {\n                return;\n            }\n\n            for (int i = 0; i < List.Count; i++)\n            {\n                try\n                {\n                    Agent a = (Agent) List[i];\n                    XmlElement el = xml[a.Name];\n                    if (el != null)\n                    {\n                        a.Load(el);\n                    }\n                }\n                catch\n                {\n                }\n            }\n        }\n\n        public static void Redraw(ComboBox list, GroupBox gb, params Button[] buttons)\n        {\n            list.Visible = true;\n            list.BeginUpdate();\n            list.Items.Clear();\n            list.SelectedIndex = -1;\n\n            for (int i = 0; i < buttons.Length; i++)\n            {\n                buttons[i].Visible = false;\n            }\n\n            for (int i = 0; i < List.Count; i++)\n            {\n                list.Items.Add(List[i]);\n            }\n\n            list.EndUpdate();\n\n            gb.Visible = false;\n        }\n\n        public static void Select(int idx, ComboBox agents, ListBox subList, GroupBox grp, params Button[] buttons)\n        {\n            for (int i = 0; i < buttons.Length; i++)\n            {\n                buttons[i].Visible = false;\n                buttons[i].Text = \"\";\n                Engine.MainWindow.SafeAction(s => s.UnlockControl(buttons[i]));\n            }\n\n            grp.Visible = false;\n            subList.Visible = false;\n            Engine.MainWindow.SafeAction(s => s.UnlockControl(subList));\n\n            Agent a = null;\n            if (idx >= 0 && idx < List.Count)\n            {\n                a = List[idx] as Agent;\n            }\n\n            if (a != null)\n            {\n                grp.Visible = true;\n                subList.Visible = true;\n                grp.Text = a.ToString();\n                a.OnSelected(subList, buttons);\n            }\n        }\n\n        public override string ToString()\n        {\n            return !string.IsNullOrEmpty(Alias) ? $\"{Name} ({Alias})\" : Name;\n        }\n\n        public abstract string Name { get; }\n        public abstract string Alias { get; set; }\n        public abstract int Number { get; }\n        public abstract void Save(XmlTextWriter xml);\n        public abstract void Load(XmlElement node);\n        public abstract void Clear();\n        public abstract void OnSelected(ListBox subList, params Button[] buttons);\n        public abstract void OnButtonPress(int num);\n    }\n}"
  },
  {
    "path": "Razor/Agents/BuyAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Gumps.Internal;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class BuyAgent : Agent\n    {\n        public class BuyEntry\n        {\n            public BuyEntry(ItemID id, ushort amount)\n            {\n                Id = id;\n                Amount = amount;\n            }\n\n            public readonly ItemID Id;\n            public ushort Amount;\n\n            public override string ToString()\n            {\n                return $\"{Id}\\t{Amount}\";\n            }\n        }\n\n        private class ItemXYComparer : IComparer<Item>\n        {\n            public static readonly ItemXYComparer Instance = new ItemXYComparer();\n\n            private ItemXYComparer()\n            {\n            }\n\n            public int Compare(Item x, Item y)\n            {\n                if (!(x is Item))\n                {\n                    return 1;\n                }\n                else if (!(y is Item))\n                {\n                    return -1;\n                }\n\n                int xsum = x.Position.X + x.Position.Y * 200;\n                int ysum = y.Position.X + y.Position.Y * 200;\n\n                return xsum.CompareTo(ysum);\n            }\n        }\n\n        private static readonly ArrayList m_Instances = new ArrayList();\n\n        public static List<BuyAgent> Agents { get; set; }\n\n        public static void Initialize()\n        {\n            PacketHandler.RegisterServerToClientViewer(0x74, new PacketViewerCallback(ExtBuyInfo));\n            PacketHandler.RegisterServerToClientViewer(0x24, new PacketViewerCallback(DisplayBuy));\n            PacketHandler.RegisterServerToClientViewer(0x3B, new PacketViewerCallback(EndVendorBuy));\n\n            int maxAgents = Config.GetAppSetting<int>(\"MaxBuyAgents\") == 0\n                ? 20\n                : Config.GetAppSetting<int>(\"MaxBuyAgents\");\n\n            Agents = new List<BuyAgent>();\n\n            for (int i = 1; i <= maxAgents; i++)\n            {\n                BuyAgent b = new BuyAgent(i);\n                m_Instances.Add(b);\n                Agent.Add(b);\n\n                Agents.Add(b);\n            }\n        }\n\n        private ListBox m_SubList;\n        private Button m_EnableBTN;\n        public readonly List<BuyEntry> Items;\n        private bool m_Enabled;\n        private bool _fromGump;\n\n        public BuyAgent(int num)\n        {\n            Number = num;\n            Items = new List<BuyEntry>();\n        }\n\n        private static void DisplayBuy(PacketReader p, PacketHandlerEventArgs args)\n        {\n            Serial serial = p.ReadUInt32();\n            ushort gump = p.ReadUInt16();\n\n            if (gump != 0x30 || !serial.IsMobile || !Client.Instance.AllowBit(FeatureBit.BuyAgent) ||\n                World.Player == null)\n            {\n                return;\n            }\n\n            Mobile vendor = World.FindMobile(serial);\n            if (vendor == null)\n            {\n                return;\n            }\n\n            Item pack = vendor.GetItemOnLayer(Layer.ShopBuy);\n            if (pack == null || pack.Contains == null || pack.Contains.Count <= 0)\n            {\n                return;\n            }\n\n            pack.Contains.Sort(ItemXYComparer.Instance);\n\n            int total = 0;\n            int cost = 0;\n            List<VendorBuyItem> buyList = new List<VendorBuyItem>();\n            Dictionary<ushort, int> found = new Dictionary<ushort, int>();\n            bool lowGoldWarn = false;\n            for (int i = 0; i < pack.Contains.Count; i++)\n            {\n                Item item = (Item) pack.Contains[i];\n                if (item == null)\n                {\n                    continue;\n                }\n\n                foreach (BuyAgent ba in m_Instances)\n                {\n                    if (ba == null || ba.Items == null || !ba.m_Enabled)\n                    {\n                        continue;\n                    }\n\n                    for (int a = 0; a < ba.Items.Count; a++)\n                    {\n                        BuyEntry b = (BuyEntry) ba.Items[a];\n                        if (b == null)\n                        {\n                            continue;\n                        }\n\n                        bool dupe = false;\n                        foreach (VendorBuyItem vbi in buyList)\n                        {\n                            if (vbi.Serial == item.Serial)\n                            {\n                                dupe = true;\n                            }\n                        }\n\n                        if (dupe)\n                        {\n                            continue;\n                        }\n\n                        // fucking osi and their blank scrolls\n                        if (b.Id == item.ItemID.Value || (b.Id == 0x0E34 && item.ItemID.Value == 0x0EF3) ||\n                            (b.Id == 0x0EF3 && item.ItemID.Value == 0x0E34))\n                        {\n                            int count = World.Player.Backpack.GetCount(b.Id);\n                            if (found.ContainsKey(b.Id))\n                            {\n                                count += (int) found[b.Id];\n                            }\n\n                            if (count < b.Amount && b.Amount > 0)\n                            {\n                                count = b.Amount - count;\n                                if (count >= item.Amount)\n                                {\n                                    count = item.Amount;\n                                }\n                                else if (count <= 0)\n                                {\n                                    continue;\n                                }\n\n                                if (!found.ContainsKey(b.Id))\n                                {\n                                    found.Add(b.Id, (int) count);\n                                }\n                                else\n                                {\n                                    found[b.Id] = (int) found[b.Id] + (int) count;\n                                }\n\n                                buyList.Add(new VendorBuyItem(item.Serial, count, item.Price));\n                                total += count;\n                                cost += item.Price * count;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (!Config.GetBool(\"BuyAgentsIgnoreGold\"))\n            {\n                if (cost > World.Player.Gold && cost < 2000 && buyList.Count > 0)\n                {\n                    lowGoldWarn = true;\n                    do\n                    {\n                        VendorBuyItem vbi = (VendorBuyItem)buyList[0];\n                        if (cost - vbi.TotalCost <= World.Player.Gold)\n                        {\n                            while (cost > World.Player.Gold && vbi.Amount > 0)\n                            {\n                                cost -= vbi.Price;\n                                --vbi.Amount;\n                                --total;\n                            }\n\n                            if (vbi.Amount <= 0)\n                            {\n                                buyList.RemoveAt(0);\n                            }\n                        }\n                        else\n                        {\n                            cost -= vbi.TotalCost;\n                            total -= vbi.Amount;\n                            buyList.RemoveAt(0);\n                        }\n                    } while (cost > World.Player.Gold && buyList.Count > 0);\n                }\n            }            \n\n            if (buyList.Count > 0)\n            {\n                args.Block = true;\n                BuyLists[serial] = buyList;\n                Client.Instance.SendToServer(new VendorBuyResponse(serial, buyList));\n\n                if (Config.GetBool(\"BuyAgentsIgnoreGold\"))\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.BuyAgentAttempt, total, cost);\n                }\n                else\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.BuyTotals, total, cost);\n                }\n            }\n\n            if (lowGoldWarn)\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.BuyLowGold);\n            }\n        }\n\n        private static readonly Dictionary<uint, List<VendorBuyItem>> BuyLists = new Dictionary<uint, List<VendorBuyItem>>();\n        private static void ExtBuyInfo(PacketReader p, PacketHandlerEventArgs args)\n        {\n            Serial ser = p.ReadUInt32();\n            Item pack = World.FindItem(ser);\n            if (pack == null)\n            {\n                return;\n            }\n\n            byte count = p.ReadByte();\n            if (count < pack.Contains.Count)\n            {\n                World.Player.SendMessage(MsgLevel.Debug,\n                    \"Buy Agent Warning: Contains Count {0} does not match ExtInfo {1}.\", pack.Contains.Count, count);\n            }\n\n            pack.Contains.Sort(ItemXYComparer.Instance);\n\n            for (int i = count - 1; i >= 0; i--)\n            {\n                if (i < pack.Contains.Count)\n                {\n                    Item item = (Item) pack.Contains[i];\n                    item.Price = p.ReadInt32();\n                    byte len = p.ReadByte();\n                    item.BuyDesc = p.ReadStringSafe(len);\n                }\n                else\n                {\n                    p.ReadInt32();\n                    p.Position += p.ReadByte() + 1;\n                }\n            }\n        }\n\n        private static void EndVendorBuy(PacketReader p, PacketHandlerEventArgs args)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.BuyAgent) || World.Player == null)\n                return;\n            uint serial = p.ReadUInt32();\n            if (BuyLists.TryGetValue(serial, out var list))\n            {\n                BuyLists.Remove(serial);\n                Mobile vendor = World.FindMobile(serial);\n                if (vendor == null)\n                    return;\n\n                Item pack = vendor.GetItemOnLayer(Layer.ShopBuy);\n                if (pack == null || pack.Contains == null || pack.Contains.Count <= 0)\n                    return;\n\n                for (int i = list.Count - 1; i >= 0; --i)\n                {\n                    VendorBuyItem vbi = list[i];\n                    Item item = World.FindItem(vbi.Serial);\n                    if (item == null || !pack.Contains.Contains(item))\n                        continue;\n                    item.Amount -= (ushort)vbi.Amount;\n                    if (item.Amount <= 0)\n                        item.Remove();\n                }\n            }\n        }\n\n        public override void Clear()\n        {\n            Items.Clear();\n        }\n\n        internal static void OnDisconnected()\n        {\n            BuyLists.Clear();\n        }\n\n        public override string Name => $\"{Language.GetString(LocString.Buy)}-{Number}\";\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            m_SubList = subList;\n            m_EnableBTN = buttons[4];\n\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            buttons[1].Text = Language.GetString(LocString.Edit);\n            buttons[1].Visible = true;\n            buttons[2].Text = Language.GetString(LocString.Remove);\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.ClearList);\n            buttons[3].Visible = true;\n            buttons[4].Text = Language.GetString(m_Enabled ? LocString.PushDisable : LocString.PushEnable);\n            buttons[4].Visible = true;\n\n            m_SubList.BeginUpdate();\n            m_SubList.Items.Clear();\n            for (int i = 0; i < Items.Count; i++)\n            {\n                m_SubList.Items.Add(Items[i]);\n            }\n\n            m_SubList.EndUpdate();\n\n            if (!Client.Instance.AllowBit(FeatureBit.BuyAgent) && Engine.MainWindow != null)\n            {\n                for (int i = 0; i < buttons.Length; i++)\n                {\n                    Engine.MainWindow.SafeAction(s => s.LockControl(buttons[i]));\n                }\n\n                Engine.MainWindow.SafeAction(s => s.LockControl(subList));\n            }\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            switch (num)\n            {\n                case 1:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTarget));\n                    break;\n                case 2:\n                    if (m_SubList == null)\n                    {\n                        break;\n                    }\n\n                    if (m_SubList.SelectedIndex >= 0)\n                    {\n                        BuyEntry e = (BuyEntry)Items[m_SubList.SelectedIndex];\n\n                        InputDialogGump inputGump = new InputDialogGump(OnItemChangeAmountResponse, m_SubList.SelectedIndex, Language.GetString(LocString.EnterAmount), e.Amount.ToString());\n                        inputGump.SendGump();\n                    }\n\n                    break;\n                case 3:\n\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        if (m_SubList.SelectedIndex >= 0)\n                        {\n                            Items.RemoveAt(m_SubList.SelectedIndex);\n                            m_SubList.Items.RemoveAt(m_SubList.SelectedIndex);\n                            m_SubList.SelectedIndex = -1;\n                        }\n                    }\n\n                    break;\n                case 4:\n\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        m_SubList.Items.Clear();\n                        Items.Clear();\n                    }\n\n                    break;\n                case 5:\n                    m_Enabled = !m_Enabled;\n                    m_EnableBTN.Text = Language.GetString(m_Enabled ? LocString.PushDisable : LocString.PushEnable);\n                    break;\n            }\n        }\n\n        private void OnTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (!location && !serial.IsMobile)\n            {\n                InputDialogGump inputGump = new InputDialogGump(OnItemTargetAmountResponse, gfx, Language.GetString(LocString.EnterAmount), \"0\");\n                inputGump.SendGump();\n            }\n\n            if (!_fromGump)\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n        }\n\n        private bool OnItemTargetAmountResponse(int gfx, string input)\n        {\n            if (ushort.TryParse(input, out ushort count))\n            {\n                if (count <= 0)\n                {\n                    return false;\n                }\n\n                AddItem(new BuyEntry((ushort) gfx, count));\n                \n                if (_fromGump)\n                {\n                    _fromGump = false;\n\n                    AgentsGump agent = new AgentsGump(this);\n                    agent.SendGump();\n                }\n                else\n                {\n                    Engine.MainWindow.SafeAction(s => s.ShowMe());\n                }\n\n                return true;\n            }\n\n            if (_fromGump)\n            {\n                _fromGump = false;\n\n                AgentsGump agent = new AgentsGump(this);\n                agent.SendGump();\n            }\n            else\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            return false;\n        }\n\n        private bool OnItemChangeAmountResponse(int entryId, string input)\n        {\n            if (ushort.TryParse(input, out ushort amount))\n            {\n                if (amount <= 0)\n                {\n                    return false;\n                }\n\n                BuyEntry e = (BuyEntry)Items[entryId];\n\n                e.Amount = amount;\n\n                if (m_SubList != null)\n                {\n                    m_SubList.BeginUpdate();\n                    m_SubList.Items.Clear();\n\n                    for (int i = 0; i < Items.Count; i++)\n                    {\n                        m_SubList.Items.Add(Items[i]);\n                    }\n\n                    m_SubList.EndUpdate();\n                }\n\n                if (_fromGump)\n                {\n                    _fromGump = false;\n\n                    AgentsGump agent = new AgentsGump(this);\n                    agent.SendGump();\n                }\n                else\n                {\n                    Engine.MainWindow.SafeAction(s => s.ShowMe());\n                }\n\n                return true;\n            }\n\n            if (_fromGump)\n            {\n                _fromGump = false;\n\n                AgentsGump agent = new AgentsGump(this);\n                agent.SendGump();\n            }\n            else\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            return false;\n        }\n\n        public void AddItemTarget(bool fromGump = false)\n        {\n            _fromGump = fromGump;\n\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n            Targeting.OneTimeTarget(OnTarget);\n        }\n\n        public void AddItem(BuyEntry entry)\n        {\n            Items?.Add(entry);\n\n            m_SubList?.Items.Add(entry);\n\n            World.Player?.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n        }\n\n        public void RemoveItem(int itemId)\n        {\n            BuyEntry item = Items.FirstOrDefault(a => a.Id == itemId);\n\n            if (item != null)\n            {\n                Items.Remove(item);\n                m_SubList?.Items?.Remove(item);\n\n                World.Player?.SendMessage(MsgLevel.Force, LocString.ItemRemoved);\n            }\n        }\n\n        public void SetItemAmount(int itemId, bool fromGump = false)\n        {\n            int itemIndex = Items.FindIndex(a => a.Id == itemId);\n            BuyEntry item = Items[itemIndex];\n\n            if (item != null)\n            {\n                _fromGump = fromGump;\n\n                InputDialogGump inputGump = new InputDialogGump(OnItemChangeAmountResponse, itemIndex, Language.GetString(LocString.EnterAmount), item.Amount.ToString());\n                inputGump.SendGump();\n            }\n        }\n\n        public override void Save(XmlTextWriter xml)\n        {\n            if (Items == null)\n            {\n                return;\n            }\n\n            xml.WriteAttributeString(\"enabled\", m_Enabled.ToString());\n            xml.WriteAttributeString(\"alias\", Alias);\n\n            foreach (BuyEntry b in Items)\n            {\n                xml.WriteStartElement(\"item\");\n                xml.WriteAttributeString(\"id\", b.Id.Value.ToString());\n                xml.WriteAttributeString(\"amount\", b.Amount.ToString());\n                xml.WriteEndElement();\n            }\n        }\n\n        public override void Load(XmlElement node)\n        {\n            try\n            {\n                m_Enabled = bool.Parse(node.GetAttribute(\"enabled\"));\n            }\n            catch\n            {\n                m_Enabled = false;\n            }\n\n            try\n            {\n                Alias = node.GetAttribute(\"alias\");\n            }\n            catch\n            {\n                Alias = string.Empty;\n            }\n\n            foreach (XmlElement el in node.GetElementsByTagName(\"item\"))\n            {\n                try\n                {\n                    ushort id = Convert.ToUInt16(el.GetAttribute(\"id\"));\n                    ushort amount = Convert.ToUInt16(el.GetAttribute(\"amount\"));\n\n                    Items.Add(new BuyEntry(id, amount));\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Agents/IgnoreAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Core;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class IgnoreAgent : Agent\n    {\n        public static IgnoreAgent Instance { get; private set; }\n\n        public static void Initialize()\n        {\n            Agent.Add(Instance = new IgnoreAgent());\n            \n            MessageManager.OnMobileMessage += HandleMobileMessage;\n        }\n        \n        public static void HandleMobileMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\n            MessageType type, ushort hue, ushort font, string lang, string sourceName,\n            string text)\n        {\n            if (Instance == null)\n                return;\n\n            if (Instance.IsSerialIgnored(source))\n            {\n                args.Block = true;\n            }\n        }\n\n        public static bool IsIgnored(Serial ser)\n        {\n            return Instance?.IsSerialIgnored(ser) ?? false;\n        }\n\n        private ListBox m_SubList;\n        private readonly List<Serial> m_Chars;\n        private readonly Dictionary<Serial, string> m_Names;\n        private static bool m_Enabled;\n        private Button m_EnableBTN;\n\n        public IgnoreAgent()\n        {\n            m_Chars = new List<Serial>();\n            m_Names = new Dictionary<Serial, string>();\n\n            Number = 0;\n\n            HotKey.Add(HKCategory.Targets, LocString.AddToIgnore, new HotKeyCallback(AddToIgnoreList));\n            HotKey.Add(HKCategory.Targets, LocString.RemoveFromIgnore, new HotKeyCallback(RemoveFromIgnoreList));\n\n            Agent.OnMobileCreated += new MobileCreatedEventHandler(OPLCheckIgnore);\n        }\n\n        public override void Clear()\n        {\n            m_Chars.Clear();\n            m_Names.Clear();\n        }\n\n        public static bool IsEnabled()\n        {\n            return m_Enabled;\n        }\n\n        public bool IsSerialIgnored(Serial ser)\n        {\n            if (m_Enabled)\n            {\n                return m_Chars.Contains(ser);\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        public override string Name\n        {\n            get { return Language.GetString(LocString.IgnoreAgent); }\n        }\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            m_EnableBTN = buttons[4];\n\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            buttons[1].Text = Language.GetString(LocString.Remove);\n            buttons[1].Visible = true;\n            buttons[2].Text = Language.GetString(LocString.RemoveTarg);\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.ClearList);\n            buttons[3].Visible = true;\n            buttons[4].Text = Language.GetString(m_Enabled ? LocString.PushDisable : LocString.PushEnable);\n            buttons[4].Visible = true;\n\n            m_SubList = subList;\n            subList.BeginUpdate();\n            subList.Items.Clear();\n            for (int i = 0; i < m_Chars.Count; i++)\n            {\n                Add2List((Serial) m_Chars[i]);\n            }\n\n            subList.EndUpdate();\n        }\n\n        public void AddToIgnoreList()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.AddToIgnore);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnAddTarget));\n        }\n\n        public void RemoveFromIgnoreList()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.RemoveFromIgnore);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnRemoveTarget));\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            switch (num)\n            {\n                case 1:\n                {\n                    AddToIgnoreList();\n                    break;\n                }\n\n                case 2:\n                {\n                    if (m_SubList.SelectedIndex >= 0 && m_SubList.SelectedIndex < m_Chars.Count)\n                    {\n                        try\n                        {\n                            m_Names.Remove(m_Chars[m_SubList.SelectedIndex]);\n                        }\n                        catch\n                        {\n                        }\n\n                        m_Chars.RemoveAt(m_SubList.SelectedIndex);\n                        m_SubList.Items.RemoveAt(m_SubList.SelectedIndex);\n                    }\n\n                    break;\n                }\n\n                case 3:\n                {\n                    RemoveFromIgnoreList();\n                    break;\n                }\n\n                case 4:\n                {\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        foreach (Serial s in m_Chars)\n                        {\n                            Mobile m = World.FindMobile(s);\n                            if (m != null)\n                            {\n                                if (m.ObjPropList.Remove(Language.GetString(LocString.RazorIgnored)))\n                                {\n                                    m.OPLChanged();\n                                }\n                            }\n                        }\n\n                        m_Chars.Clear();\n                        m_SubList.Items.Clear();\n                    }\n\n                    break;\n                }\n\n                case 5:\n                {\n                    m_Enabled = !m_Enabled;\n                    m_EnableBTN.Text = Language.GetString(m_Enabled ? LocString.PushDisable : LocString.PushEnable);\n                    break;\n                }\n            }\n        }\n\n        private void OPLCheckIgnore(Mobile m)\n        {\n            if (IsIgnored(m.Serial))\n            {\n                m.ObjPropList.Add(Language.GetString(LocString.RazorIgnored));\n            }\n        }\n\n        private void OnAddTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n\n            if (!location && serial.IsMobile && serial != World.Player.Serial)\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.AddToIgnore);\n                if (!m_Chars.Contains(serial))\n                {\n                    m_Chars.Add(serial);\n\n                    Add2List(serial);\n\n                    Mobile m = World.FindMobile(serial);\n                    if (m != null)\n                    {\n                        m.ObjPropList.Add(Language.GetString(LocString.RazorIgnored));\n                        m.OPLChanged();\n                    }\n                }\n            }\n        }\n\n        private void Add2List(Serial s)\n        {\n            Mobile m = World.FindMobile(s);\n            string name = null;\n\n            if (m_Names.ContainsKey(s))\n            {\n                name = m_Names[s] as string;\n            }\n\n            if (m != null && m.Name != null && m.Name != \"\")\n            {\n                name = m.Name;\n            }\n\n            if (name == null)\n            {\n                name = \"(Name Unknown)\";\n            }\n\n            m_Names[s] = name;\n\n            if (m_SubList != null)\n            {\n                m_SubList.Items.Add($\"\\\"{name}\\\" {s}\");\n            }\n        }\n\n        private void OnRemoveTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n\n            if (!location && serial.IsMobile && serial != World.Player.Serial)\n            {\n                m_Chars.Remove(serial);\n                m_Names.Remove(serial);\n\n                World.Player.SendMessage(MsgLevel.Force, LocString.RemoveFromIgnore);\n\n                m_SubList.BeginUpdate();\n                m_SubList.Items.Clear();\n                for (int i = 0; i < m_Chars.Count; i++)\n                {\n                    Add2List((Serial) m_Chars[i]);\n                }\n\n                m_SubList.EndUpdate();\n\n                Mobile m = World.FindMobile(serial);\n                if (m != null)\n                {\n                    if (m.ObjPropList.Remove(Language.GetString(LocString.RazorIgnored)))\n                    {\n                        m.OPLChanged();\n                    }\n                }\n            }\n        }\n\n        public override void Save(XmlTextWriter xml)\n        {\n            xml.WriteAttributeString(\"enabled\", m_Enabled.ToString());\n            for (int i = 0; i < m_Chars.Count; i++)\n            {\n                xml.WriteStartElement(\"ignore\");\n                xml.WriteAttributeString(\"serial\", m_Chars[i].ToString());\n                try\n                {\n                    if (m_Names.ContainsKey((Serial) m_Chars[i]))\n                    {\n                        xml.WriteAttributeString(\"name\", m_Names[(Serial) m_Chars[i]].ToString());\n                    }\n                }\n                catch\n                {\n                }\n\n                xml.WriteEndElement();\n            }\n        }\n\n        public override void Load(XmlElement node)\n        {\n            try\n            {\n                m_Enabled = Convert.ToBoolean(node.GetAttribute(\"enabled\"));\n            }\n            catch\n            {\n                // ignored\n            }\n\n            foreach (XmlElement el in node.GetElementsByTagName(\"ignore\"))\n            {\n                try\n                {\n                    Serial toAdd = Serial.Parse(el.GetAttribute(\"serial\"));\n\n                    if (!m_Chars.Contains(toAdd))\n                    {\n                        m_Chars.Add(toAdd);\n                    }\n\n                    string name = el.GetAttribute(\"name\");\n                    if (!string.IsNullOrEmpty(name))\n                    {\n                        m_Names.Add(toAdd, name.Trim());\n                    }\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Agents/OrganizerAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Gumps.Internal;\nusing Assistant.Scripts;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class OrganizerAgent : Agent\n    {\n        public static List<OrganizerAgent> Agents { get; set; }\n\n        public static void Initialize()\n        {\n            int maxAgents = Config.GetAppSetting<int>(\"MaxOrganizerAgents\") == 0\n                ? 20\n                : Config.GetAppSetting<int>(\"MaxOrganizerAgents\");\n\n            Agents = new List<OrganizerAgent>();\n\n            for (int i = 1; i <= maxAgents; i++)\n            {\n                OrganizerAgent organizerAgent = new OrganizerAgent(i);\n\n                Agent.Add(organizerAgent);\n\n                Agents.Add(organizerAgent);\n            }\n        }\n\n        private ListBox m_SubList;\n        private Button m_BagBTN;\n        private Button m_ArrBTN;\n        public readonly List<ItemID> Items;\n        private uint m_Cont;\n        private bool _fromGump;\n\n        public OrganizerAgent(int num)\n        {\n            Items = new List<ItemID>();\n            Number = num;\n            HotKey.Add(HKCategory.Agents, HKSubCat.None,\n                $\"{Language.GetString(LocString.OrganizerAgent)}-{Number:D2}\",\n                new HotKeyCallback(Organize));\n            HotKey.Add(HKCategory.Agents, HKSubCat.None,\n                $\"{Language.GetString(LocString.SetOrganizerHB)}-{Number:D2}\",\n                new HotKeyCallback(SetHotBag));\n            PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick));\n\n            Agent.OnItemCreated += new ItemCreatedEventHandler(CheckContOPL);\n        }\n\n        public void CheckContOPL(Item item)\n        {\n            if (item.Serial == m_Cont)\n            {\n                item.ObjPropList.Add(Language.Format(LocString.OrganizerHBA1, Number));\n            }\n        }\n\n        private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args)\n        {\n            uint serial = pvSrc.ReadUInt32();\n            if (m_Cont == serial)\n            {\n                ushort gfx = 0;\n                Item c = World.FindItem(m_Cont);\n                if (c != null)\n                {\n                    gfx = c.ItemID.Value;\n                }\n\n                Client.Instance.SendToClient(new UnicodeMessage(m_Cont, gfx, Assistant.MessageType.Label, 0x3B2, 3,\n                    Language.CliLocName, \"\", Language.Format(LocString.OrganizerHBA1, Number)));\n            }\n        }\n\n        public override string Name\n        {\n            get { return $\"{Language.GetString(LocString.Organizer)}-{Number}\"; }\n        }\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            m_SubList = subList;\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            m_BagBTN = buttons[1];\n            m_ArrBTN = buttons[2];\n            if (m_Cont != 0)\n            {\n                buttons[1].Text = Language.GetString(LocString.ClearHB);\n            }\n            else\n            {\n                buttons[1].Text = Language.GetString(LocString.SetHB);\n            }\n\n            buttons[1].Visible = true;\n            buttons[2].Text = Language.GetString(LocString.OrganizeNow);\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.Remove);\n            buttons[3].Visible = true;\n            buttons[4].Text = Language.GetString(LocString.Clear);\n            buttons[4].Visible = true;\n            buttons[5].Text = Language.GetString(LocString.StopNow);\n            buttons[5].Visible = true;\n\n            m_SubList.BeginUpdate();\n            m_SubList.Items.Clear();\n            for (int i = 0; i < Items.Count; i++)\n            {\n                m_SubList.Items.Add((ItemID) (Items[i]));\n            }\n\n            m_SubList.EndUpdate();\n        }\n\n        public void SetHotBag()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargCont);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetBag));\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            switch (num)\n            {\n                case 1:\n                    AddItemTarget();\n                    break;\n                case 2:\n                    SetHotBag();\n                    break;\n                case 3:\n                    Organize();\n                    break;\n                case 4:\n                    if (m_SubList.SelectedIndex >= 0 && m_SubList.SelectedIndex < Items.Count)\n                    {\n                        Items.RemoveAt(m_SubList.SelectedIndex);\n                        m_SubList.Items.RemoveAt(m_SubList.SelectedIndex);\n                    }\n\n                    break;\n                case 5:\n                {\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        Item bag = World.FindItem(m_Cont);\n                        if (bag != null)\n                        {\n                            bag.ObjPropList.Remove(Language.Format(LocString.OrganizerHBA1, Number));\n                            bag.OPLChanged();\n                        }\n\n                        m_SubList.Items.Clear();\n                        Items.Clear();\n                        m_Cont = 0;\n                        m_BagBTN.Text = Language.GetString(LocString.SetHB);\n                    }\n\n                    break;\n                }\n\n                case 6:\n                    DragDropManager.GracefulStop();\n                    break;\n            }\n        }\n\n        public void Organize()\n        {\n            if (m_Cont == 0 || m_Cont > 0x7FFFFF00)\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.ContNotSet);\n                return;\n            }\n\n            Item pack = World.Player.Backpack;\n            if (pack == null)\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.NoBackpack);\n                return;\n            }\n\n            int count = OrganizeChildren(pack);\n\n            if (count > 0)\n            {\n                World.Player.SendMessage(LocString.OrgQueued, count);\n            }\n            else\n            {\n                World.Player.SendMessage(LocString.OrgNoItems);\n            }\n        }\n\n        private int OrganizeChildren(Item container)\n        {\n            object dest = World.FindItem(m_Cont);\n            if (dest == null)\n            {\n                dest = World.FindMobile(m_Cont);\n                if (dest == null)\n                {\n                    return 0;\n                }\n            }\n\n            /*else if ( World.Player.Backpack != null && ((Item)dest).IsChildOf( World.Player ) && !((Item)dest).IsChildOf( World.Player.Backpack ) )\n            {\n                 return 0;\n            }*/\n\n            return OrganizeChildren(container, dest);\n        }\n\n        private int OrganizeChildren(Item container, object dest)\n        {\n            int count = 0;\n            for (int i = 0; i < container.Contains.Count; i++)\n            {\n                Item item = (Item) container.Contains[i];\n                if (item.Serial != m_Cont && !item.IsChildOf(dest))\n                {\n                    count += OrganizeChildren(item, dest);\n                    if (Items.Contains(item.ItemID.Value))\n                    {\n                        if (dest is Item)\n                        {\n                            DragDropManager.DragDrop(item, (Item) dest);\n                        }\n                        else if (dest is Mobile)\n                        {\n                            DragDropManager.DragDrop(item, ((Mobile) dest).Serial);\n                        }\n\n                        count++;\n                    }\n                }\n            }\n\n            return count;\n        }\n\n        private void OnTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (!location && serial.IsItem && World.Player != null)\n            {\n                AddItem(gfx);\n            }\n\n            if (_fromGump)\n            {\n                _fromGump = false;\n\n                AgentsGump agent = new AgentsGump(this);\n                agent.SendGump();\n            } \n            else if (Engine.MainWindow != null)\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n        }\n        public void AddItemTarget(bool fromGump = false)\n        {\n            _fromGump = fromGump;\n\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n            Targeting.OneTimeTarget(OnTarget);\n        }\n\n        public void AddItem(ushort gfx)\n        {\n            if (Items != null && Items.Contains(gfx))\n            {\n                World.Player?.SendMessage(MsgLevel.Force, LocString.ItemExists);\n            }\n            else\n            {\n                Items?.Add(gfx);\n\n                m_SubList?.Items.Add((ItemID)gfx);\n\n                World.Player?.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n            }\n        }\n\n        public void RemoveItem(int itemId)\n        {\n            ItemID item = Items.FirstOrDefault(a => a == itemId);\n\n            if (item != null)\n            {\n                Items.Remove(item);\n                m_SubList?.Items?.Remove(item);\n\n                World.Player?.SendMessage(MsgLevel.Force, LocString.ItemRemoved);\n            }\n        }\n\n        private void OnTargetBag(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (Engine.MainWindow != null && !ScriptManager.Running)\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            if (!location && serial > 0 && serial <= 0x7FFFFF00)\n            {\n                Item bag = World.FindItem(m_Cont);\n                if (bag != null && bag.ObjPropList != null)\n                {\n                    bag.ObjPropList.Remove(Language.Format(LocString.OrganizerHBA1, Number));\n                    bag.OPLChanged();\n                }\n\n                m_Cont = serial;\n                if (m_BagBTN != null)\n                {\n                    m_BagBTN.Text = Language.GetString(LocString.ClearHB);\n                }\n\n                if (World.Player != null)\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.ContSet);\n                }\n\n                bag = World.FindItem(m_Cont);\n                if (bag != null && bag.ObjPropList != null)\n                {\n                    bag.ObjPropList.Add(Language.Format(LocString.OrganizerHBA1, Number));\n                    bag.OPLChanged();\n                }\n            }\n        }\n\n        public override void Clear()\n        {\n            Items.Clear();\n            m_Cont = 0;\n            if (m_BagBTN != null)\n            {\n                m_BagBTN.Text = Language.GetString(LocString.SetHB);\n            }\n        }\n\n        public override void Save(XmlTextWriter xml)\n        {\n            xml.WriteAttributeString(\"hotbag\", m_Cont.ToString());\n            xml.WriteAttributeString(\"alias\", Alias);\n\n            for (int i = 0; i < Items.Count; i++)\n            {\n                xml.WriteStartElement(\"item\");\n                xml.WriteAttributeString(\"id\", Items[i].Value.ToString());\n                xml.WriteEndElement();\n            }\n        }\n\n        public override void Load(XmlElement node)\n        {\n            try\n            {\n                m_Cont = Convert.ToUInt32(node.GetAttribute(\"hotbag\"));\n            }\n            catch\n            {\n                // ignored\n            }\n\n            try\n            {\n                Alias = node.GetAttribute(\"alias\");\n            }\n            catch\n            {\n                Alias = string.Empty;\n            }\n\n            if (m_BagBTN != null)\n            {\n                m_BagBTN.Text = Language.GetString(m_Cont != 0 ? LocString.ClearHB : LocString.SetHB);\n            }\n\n            foreach (XmlElement el in node.GetElementsByTagName(\"item\"))\n            {\n                try\n                {\n                    string gfx = el.GetAttribute(\"id\");\n                    Items.Add(Convert.ToUInt16(gfx));\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Agents/RestockAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Gumps;\nusing Assistant.Gumps.Internal;\nusing Assistant.Scripts;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class RestockAgent : Agent\n    {\n        public static List<RestockAgent> Agents { get; set; }\n        \n        public static void Initialize()\n        {\n            int maxAgents = Config.GetAppSetting<int>(\"MaxRestockAgents\") == 0\n                ? 20\n                : Config.GetAppSetting<int>(\"MaxRestockAgents\");\n\n            Agents = new List<RestockAgent>();\n\n            for (int i = 1; i <= maxAgents; i++)\n            {\n                RestockAgent restockAgent = new RestockAgent(i);\n\n                Agent.Add(restockAgent);\n                Agents.Add(restockAgent);\n            }\n        }\n\n        private ListBox m_SubList;\n        public readonly List<RestockItem> Items;\n        private Button m_HotBTN;\n        private Serial m_HotBag;\n\n        private bool _fromGump { get; set; }\n\n        public RestockAgent(int num)\n        {\n            Number = num;\n\n            Items = new List<RestockItem>();\n\n            HotKey.Add(HKCategory.Agents, HKSubCat.None,\n                $\"{Language.GetString(LocString.RestockAgent)}-{Number:D2}\",\n                new HotKeyCallback(OnHotKey));\n            HotKey.Add(HKCategory.Agents, HKSubCat.None,\n                $\"{Language.GetString(LocString.SetRestockHB)}-{Number:D2}\",\n                new HotKeyCallback(SetHB));\n            PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick));\n\n            Agent.OnItemCreated += new ItemCreatedEventHandler(CheckHBOPL);\n        }\n\n        public void CheckHBOPL(Item item)\n        {\n            if (item.Serial == m_HotBag)\n            {\n                item.ObjPropList.Add(Language.Format(LocString.RestockHBA1, Number));\n            }\n        }\n\n        private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args)\n        {\n            Serial serial = pvSrc.ReadUInt32();\n            if (m_HotBag == serial)\n            {\n                ushort gfx = 0;\n                Item c = World.FindItem(m_HotBag);\n                if (c != null)\n                {\n                    gfx = c.ItemID.Value;\n                }\n\n                Client.Instance.SendToClient(new UnicodeMessage(m_HotBag, gfx, Assistant.MessageType.Label, 0x3B2, 3,\n                    Language.CliLocName, \"\", Language.Format(LocString.RestockHBA1, Number)));\n            }\n        }\n\n        public override void Clear()\n        {\n            Items.Clear();\n        }\n        public override string Name\n        {\n\n            get { return $\"{Language.GetString(LocString.Restock)}-{Number}\"; }\n        }\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            buttons[1].Text = Language.GetString(LocString.Remove);\n            buttons[1].Visible = true;\n            buttons[2].Text = Language.GetString(LocString.SetAmt);\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.ClearList);\n            buttons[3].Visible = true;\n            m_HotBTN = buttons[4];\n            SetHBText();\n            buttons[4].Visible = true;\n            buttons[5].Text = Language.GetString(LocString.RestockNow);\n            buttons[5].Visible = true;\n\n            m_SubList = subList;\n            subList.BeginUpdate();\n            subList.Items.Clear();\n            for (int i = 0; i < Items.Count; i++)\n            {\n                subList.Items.Add(Items[i]);\n            }\n\n            subList.EndUpdate();\n\n            if (!Client.Instance.AllowBit(FeatureBit.RestockAgent) && Engine.MainWindow != null)\n            {\n                for (int i = 0; i < buttons.Length; i++)\n                {\n                    Engine.MainWindow.SafeAction(s => s.LockControl(buttons[i]));\n                }\n\n                Engine.MainWindow.SafeAction(s => s.LockControl(subList));\n            }\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            switch (num)\n            {\n                case 1:\n                {\n                    AddItemTarget();\n                    break;\n                }\n\n                case 2:\n                {\n                    if (m_SubList.SelectedIndex >= 0 && m_SubList.SelectedIndex < Items.Count)\n                    {\n                        Items.RemoveAt(m_SubList.SelectedIndex);\n                        m_SubList.Items.RemoveAt(m_SubList.SelectedIndex);\n                    }\n\n                    break;\n                }\n\n                case 3:\n                {\n                    int i = m_SubList.SelectedIndex;\n                    if (i < 0 || i > Items.Count)\n                    {\n                        return;\n                    }\n\n                    RestockItem ri = (RestockItem) Items[i];\n                    \n                    InputDialogGump inputGump = new InputDialogGump(OnItemTargetChangeResponse, m_SubList.SelectedIndex, Language.GetString(LocString.EnterAmount), ri.Amount.ToString());\n                    inputGump.SendGump();\n\n                    break;\n                }\n\n                case 4:\n                {\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        m_SubList.Items.Clear();\n                        Items.Clear();\n                    }\n\n                    break;\n                }\n\n                case 5:\n                {\n                    if (m_HotBag == Serial.Zero)\n                    {\n                        SetHB();\n                    }\n                    else\n                    {\n                        m_HotBag = Serial.Zero;\n                        SetHBText();\n                    }\n\n                    break;\n                }\n\n                case 6:\n                {\n                    OnHotKey();\n                    break;\n                }\n            }\n        }\n\n        private void SetHBText()\n        {\n            if (m_HotBTN != null)\n            {\n                m_HotBTN.Text = Language.GetString(m_HotBag == Serial.Zero ? LocString.SetHB : LocString.ClearHB);\n            }\n        }\n\n        public void SetHB()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargCont);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnHBTarget));\n        }\n\n        private void OnHBTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (Engine.MainWindow != null && !ScriptManager.Running)\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            Item hb = World.FindItem(m_HotBag);\n            if (hb != null)\n            {\n                if (hb.ObjPropList.Remove(Language.Format(LocString.RestockHBA1, Number)))\n                {\n                    hb.OPLChanged();\n                }\n            }\n\n            if (!location && serial.IsItem)\n            {\n                m_HotBag = serial;\n            }\n            else\n            {\n                m_HotBag = Serial.Zero;\n            }\n\n            hb = World.FindItem(m_HotBag);\n            if (hb != null)\n            {\n                hb.ObjPropList.Add(Language.Format(LocString.RestockHBA1, Number));\n                hb.OPLChanged();\n            }\n\n            SetHBText();\n        }\n\n        public void OnHotKey()\n        {\n            if (Client.Instance.AllowBit(FeatureBit.RestockAgent))\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.RestockTarget);\n                Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnRestockTarget));\n            }\n        }\n\n        Item m_Cont = null;\n\n        private void OnRestockTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (serial == World.Player.Serial)\n            {\n                m_Cont = World.Player.GetItemOnLayer(Layer.Bank);\n            }\n            else if (serial.IsItem)\n            {\n                m_Cont = World.FindItem(serial);\n                if (m_Cont != null)\n                {\n                    object root = m_Cont.RootContainer;\n                    if (root is Mobile && root != World.Player)\n                    {\n                        m_Cont = null;\n                    }\n                }\n            }\n\n            if (m_Cont == null || m_Cont.IsCorpse)\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.InvalidCont);\n                return;\n            }\n\n            if (Utility.Distance(World.Player.Position, m_Cont.GetWorldPosition()) > 3)\n            {\n                World.Player.SendMessage(MsgLevel.Error, LocString.TooFar);\n            }\n            else\n            {\n                if (m_Cont.IsContainer && m_Cont.Layer != Layer.Bank)\n                {\n                    PlayerData.DoubleClick(m_Cont);\n\n                    if (Config.GetBool(\"ObjectDelayEnabled\"))\n                    {\n                        Timer.DelayedCallback(TimeSpan.FromMilliseconds(Config.GetInt(\"ObjectDelay\") + 200),\n                            new TimerCallback(DoRestock)).Start();\n                    }\n                    else\n                    {\n                        Timer.DelayedCallback(TimeSpan.FromMilliseconds(200), new TimerCallback(DoRestock)).Start();\n                    }\n\n\n                    World.Player.SendMessage(LocString.RestockQueued);\n                }\n                else\n                {\n                    DoRestock();\n                }\n            }\n        }\n\n        private void DoRestock()\n        {\n            Item bag = null;\n            if (m_HotBag != Serial.Zero)\n            {\n                bag = World.FindItem(m_HotBag);\n                if (bag != null && bag.RootContainer != World.Player)\n                {\n                    bag = null;\n                }\n            }\n\n            if (bag == null)\n            {\n                bag = World.Player.Backpack;\n                if (bag == null)\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.NoBackpack);\n                    return;\n                }\n            }\n\n            int num = 0;\n            for (int i = 0; i < Items.Count; i++)\n            {\n                RestockItem ri = Items[i];\n                int count = World.Player.Backpack.GetCount(ri.ItemID);\n\n                num += Recurse(bag, m_Cont.Contains, ri, ref count);\n            }\n\n            World.Player.SendMessage(MsgLevel.Force, LocString.RestockDone, num, num != 1 ? \"s\" : \"\");\n        }\n\n        private int Recurse(Item pack, List<Item> items, RestockItem ri, ref int count)\n        {\n            int num = 0;\n            for (int i = 0; count < ri.Amount && i < items.Count; i++)\n            {\n                Item item = (Item) items[i];\n\n                if (item.ItemID == ri.ItemID)\n                {\n                    int amt = ri.Amount - count;\n                    if (amt > item.Amount)\n                    {\n                        amt = item.Amount;\n                    }\n\n                    DragDropManager.DragDrop(item, amt, pack);\n                    count += amt;\n                    num++;\n                }\n                else if (item.Contains.Count > 0)\n                {\n                    num += Recurse(pack, item.Contains, ri, ref count);\n                }\n            }\n\n            return num;\n        }\n\n        private void OnItemTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (location || serial.IsMobile)\n            {\n                return;\n            }\n\n            Item item = World.FindItem(serial);\n            if (item != null)\n            {\n                gfx = item.ItemID;\n            }\n\n            if (gfx == 0 || gfx >= 0x4000)\n            {\n                return;\n            }\n            \n            InputDialogGump inputGump = new InputDialogGump(OnItemTargetAmountResponse, gfx, Language.GetString(LocString.EnterAmount),\"1\");\n            inputGump.SendGump();\n        }\n\n        private bool OnItemTargetAmountResponse(int gfx, string input)\n        {\n            if (int.TryParse(input, out int amount))\n            {\n                RestockItem ri = new RestockItem((ushort) gfx, amount);\n                AddItem(ri);\n\n                if (_fromGump)\n                {\n                    _fromGump = false;\n\n                    AgentsGump agent = new AgentsGump(this);\n                    agent.SendGump();\n                }\n                else\n                {\n                    Engine.MainWindow.SafeAction(s => s.ShowMe());\n                }\n\n                return true;\n            }\n\n            if (_fromGump)\n            {\n                _fromGump = false;\n\n                AgentsGump agent = new AgentsGump(this);\n                agent.SendGump();\n            }\n            else\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            return false;\n        }\n\n        private bool OnItemTargetChangeResponse(int restockId, string input)\n        {\n            if (int.TryParse(input, out int amount))\n            {\n                RestockItem ri = (RestockItem)Items[restockId];\n                \n                ri.Amount = amount;\n\n                if (m_SubList != null)\n                {\n                    m_SubList.BeginUpdate();\n                    m_SubList.Items.Clear();\n\n                    for (int j = 0; j < Items.Count; j++)\n                    {\n                        m_SubList.Items.Add(Items[j]);\n                    }\n\n                    m_SubList.SelectedIndex = restockId;\n                    m_SubList.EndUpdate();\n                }\n\n                if (_fromGump)\n                {\n                    _fromGump = false;\n\n                    AgentsGump agent = new AgentsGump(this);\n                    agent.SendGump();\n                }\n                else\n                {\n                    Engine.MainWindow.SafeAction(s => s.ShowMe());\n                }\n\n                return true;\n            }\n\n            if (_fromGump)\n            {\n                _fromGump = false;\n\n                AgentsGump agent = new AgentsGump(this);\n                agent.SendGump();\n            }\n            else\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            return false;\n        }\n\n        public void AddItemTarget(bool fromGump = false)\n        {\n            _fromGump = fromGump;\n\n            Targeting.OneTimeTarget(OnItemTarget);\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n        }\n\n        public void AddItem(RestockItem item)\n        {\n            foreach (RestockItem restockItem in Items)\n            {\n                if (restockItem.ItemID.Value == item.ItemID.Value)\n                {\n                    World.Player?.SendMessage(MsgLevel.Force, LocString.ItemExists);\n                    return;\n                }\n            }\n\n            Items.Add(item);\n            m_SubList?.Items?.Add(item);\n\n            World.Player?.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n        }\n\n        public void RemoveItem(int itemId)\n        {\n            RestockItem item = Items.FirstOrDefault(a => a.ItemID == itemId);\n\n            if (item != null)\n            {\n                Items.Remove(item);\n                m_SubList?.Items?.Remove(item);\n\n                World.Player?.SendMessage(MsgLevel.Force, LocString.ItemRemoved);\n            }\n        }\n\n        public void SetItemAmount(int itemId, bool fromGump = false)\n        {\n            int itemIndex = Items.FindIndex(a => a.ItemID == itemId);\n            RestockItem item = Items[itemIndex];\n\n            if (item != null)\n            {\n                _fromGump = fromGump;\n\n                InputDialogGump inputGump = new InputDialogGump(OnItemTargetChangeResponse, itemIndex, Language.GetString(LocString.EnterAmount), item.Amount.ToString());\n                inputGump.SendGump();\n            }\n        }\n\n        public override void Save(XmlTextWriter xml)\n        {\n            xml.WriteAttributeString(\"hotbag\", m_HotBag.Value.ToString());\n            xml.WriteAttributeString(\"alias\", Alias);\n\n            for (int i = 0; i < Items.Count; i++)\n            {\n                xml.WriteStartElement(\"item\");\n                RestockItem ri = (RestockItem) Items[i];\n                xml.WriteAttributeString(\"id\", ri.ItemID.Value.ToString());\n                xml.WriteAttributeString(\"amount\", ri.Amount.ToString());\n                xml.WriteEndElement();\n            }\n        }\n\n        public override void Load(XmlElement node)\n        {\n            try\n            {\n                m_HotBag = Convert.ToUInt32(node.GetAttribute(\"hotbag\"));\n            }\n            catch\n            {\n                m_HotBag = Serial.Zero;\n            }\n\n            try\n            {\n                Alias = node.GetAttribute(\"alias\");\n            }\n            catch\n            {\n                Alias = string.Empty;\n            }\n\n            foreach (XmlElement el in node.GetElementsByTagName(\"item\"))\n            {\n                try\n                {\n                    string iid = el.GetAttribute(\"id\");\n                    string amt = el.GetAttribute(\"amount\");\n                    Items.Add(new RestockItem((ItemID) Convert.ToInt32(iid), Convert.ToInt32(amt)));\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n\n        public class RestockItem\n        {\n            public ItemID ItemID;\n            public int Amount;\n\n            public RestockItem(ItemID id, int amount)\n            {\n                ItemID = id;\n                Amount = amount;\n            }\n\n            public override string ToString()\n            {\n                return $\"{ItemID}\\t\\t{Amount}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Agents/ScavengerAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class ScavengerAgent : Agent\n    {\n        private static readonly ScavengerAgent m_Instance = new ScavengerAgent();\n\n        public static ScavengerAgent Instance\n        {\n            get { return m_Instance; }\n        }\n\n        public static bool Debug = false;\n\n        public static void Initialize()\n        {\n            Agent.Add(m_Instance);\n        }\n\n        private bool m_Enabled;\n        private Serial m_Bag;\n        private ListBox m_SubList;\n        private Button m_EnButton;\n        private readonly List<ItemID> m_Items;\n\n        private List<Serial> m_Cache;\n        private Item m_BagRef;\n\n        public ScavengerAgent()\n        {\n            m_Items = new List<ItemID>();\n\n            Number = 0;\n\n            HotKey.Add(HKCategory.Agents, LocString.ClearScavCache, new HotKeyCallback(ClearCache));\n            HotKey.Add(HKCategory.Agents, LocString.ScavengerEnableDisable, new HotKeyCallback(OnEnableDisable));\n            HotKey.Add(HKCategory.Agents, LocString.ScavengerSetHotBag, new HotKeyCallback(OnSetHotBag));\n            HotKey.Add(HKCategory.Agents, LocString.ScavengerAddTarget, new HotKeyCallback(OnAddToHotBag));\n\n            PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick));\n\n            Agent.OnItemCreated += new ItemCreatedEventHandler(CheckBagOPL);\n        }\n\n        public void ToggleEnabled()\n        {\n            OnEnableDisable();\n        }\n\n        public void Disable()\n        {\n            m_Enabled = false;\n            UpdateEnableButton();\n            World.Player.SendMessage(MsgLevel.Force, \"Scavenger Agent Disabled\");\n        }\n\n        public void Enable()\n        {\n            m_Enabled = true;\n            UpdateEnableButton();\n            World.Player.SendMessage(MsgLevel.Force, \"Scavenger Agent Enabled\");\n        }\n\n        private void OnEnableDisable()\n        {\n            m_Enabled = !m_Enabled;\n            UpdateEnableButton();\n\n            if (m_Enabled)\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"Scavenger Agent Enabled\");\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"Scavenger Agent Disabled\");\n            }\n        }\n\n        public void OnAddToHotBag()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTarget));\n        }\n\n        public void OnSetHotBag()\n        {\n            World.Player.SendMessage(LocString.TargCont);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetBag));\n        }\n\n        private void CheckBagOPL(Item item)\n        {\n            if (item.Serial == m_Bag)\n            {\n                item.ObjPropList.Add(Language.GetString(LocString.ScavengerHB));\n            }\n        }\n\n        private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args)\n        {\n            Serial serial = pvSrc.ReadUInt32();\n            if (m_Bag == serial)\n            {\n                ushort gfx = 0;\n                Item c = World.FindItem(m_Bag);\n                if (c != null)\n                {\n                    gfx = c.ItemID.Value;\n                }\n\n                Client.Instance.SendToClient(new UnicodeMessage(m_Bag, gfx, Assistant.MessageType.Label, 0x3B2, 3,\n                    Language.CliLocName, \"\", Language.GetString(LocString.ScavengerHB)));\n            }\n        }\n\n        public override void Clear()\n        {\n            m_Items.Clear();\n            m_BagRef = null;\n        }\n\n        public bool Enabled\n        {\n            get { return m_Enabled; }\n        }\n\n        public override string Name\n        {\n            get { return Language.GetString(LocString.Scavenger); }\n        }\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            buttons[1].Text = Language.GetString(LocString.Remove);\n            buttons[1].Visible = true;\n            buttons[2].Text = Language.GetString(LocString.SetHB);\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.ClearList);\n            buttons[3].Visible = true;\n            buttons[4].Text = Language.GetString(LocString.ClearScavCache);\n            buttons[4].Visible = true;\n            m_EnButton = buttons[5];\n            m_EnButton.Visible = true;\n            UpdateEnableButton();\n\n            m_SubList = subList;\n            subList.BeginUpdate();\n            subList.Items.Clear();\n\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                subList.Items.Add(m_Items[i]);\n            }\n\n            subList.EndUpdate();\n        }\n\n        private void UpdateEnableButton()\n        {\n            if (m_EnButton != null)\n            {\n                m_EnButton.Text = Language.GetString(m_Enabled ? LocString.PushDisable : LocString.PushEnable);\n            }\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            DebugLog(\"User pressed button {0}\", num);\n            switch (num)\n            {\n                case 1:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTarget));\n                    break;\n                case 2:\n                    if (m_SubList.SelectedIndex >= 0 && m_SubList.SelectedIndex < m_Items.Count)\n                    {\n                        m_Items.RemoveAt(m_SubList.SelectedIndex);\n                        m_SubList.Items.RemoveAt(m_SubList.SelectedIndex);\n                    }\n\n                    break;\n                case 3:\n                    World.Player.SendMessage(LocString.TargCont);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetBag));\n                    break;\n                case 4:\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        m_SubList.Items.Clear();\n                        m_Items.Clear();\n                    }\n\n                    break;\n                case 5:\n                    ClearCache();\n                    break;\n                case 6:\n                    m_Enabled = !m_Enabled;\n                    UpdateEnableButton();\n                    break;\n            }\n        }\n\n        public void ClearCache()\n        {\n            DebugLog(\"Clearing Cache of {0} items\", m_Cache == null ? -1 : m_Cache.Count);\n            if (m_Cache != null)\n            {\n                m_Cache.Clear();\n            }\n\n            if (World.Player != null)\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"Scavenger agent item cache cleared.\");\n            }\n        }\n\n        private void OnTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n\n            if (location || !serial.IsItem)\n            {\n                return;\n            }\n\n            Item item = World.FindItem(serial);\n            if (item == null)\n            {\n                return;\n            }\n\n            Add(item.ItemID);\n        }\n\n        public void Add(ItemID itemId)\n        {\n            m_Items?.Add(itemId);\n            m_SubList?.Items.Add(itemId);\n\n            DebugLog(\"Added item {0}\", itemId);\n\n            World.Player?.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n        }\n\n        private void OnTargetBag(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n\n            if (location || !serial.IsItem)\n            {\n                return;\n            }\n\n            if (m_BagRef == null)\n            {\n                m_BagRef = World.FindItem(m_Bag);\n            }\n\n            if (m_BagRef != null)\n            {\n                m_BagRef.ObjPropList.Remove(Language.GetString(LocString.ScavengerHB));\n                m_BagRef.OPLChanged();\n            }\n\n            DebugLog(\"Set bag to {0}\", serial);\n            m_Bag = serial;\n            m_BagRef = World.FindItem(m_Bag);\n            if (m_BagRef != null)\n            {\n                m_BagRef.ObjPropList.Add(Language.GetString(LocString.ScavengerHB));\n                m_BagRef.OPLChanged();\n            }\n\n            World.Player.SendMessage(MsgLevel.Force, LocString.ContSet, m_Bag);\n        }\n\n        public void Uncache(Serial s)\n        {\n            if (m_Cache != null)\n            {\n                m_Cache.Remove(s);\n            }\n        }\n\n        public void Scavenge(Item item)\n        {\n            DebugLog(\"Checking WorldItem {0} ...\", item);\n            if (!m_Enabled || !m_Items.Contains(item.ItemID) || World.Player.Backpack == null || World.Player.IsGhost ||\n                World.Player.Weight >= World.Player.MaxWeight)\n            {\n                DebugLog(\"... skipped.\");\n                return;\n            }\n\n            if (m_Cache == null)\n            {\n                m_Cache = new List<Serial>();\n            }\n            else if (m_Cache.Count >= 190)\n            {\n                m_Cache.RemoveRange(0, 50);\n            }\n\n            if (m_Cache.Contains(item.Serial))\n            {\n                DebugLog(\"Item was cached.\");\n                return;\n            }\n\n            Item bag = m_BagRef;\n            if (bag == null || bag.Deleted)\n            {\n                bag = m_BagRef = World.FindItem(m_Bag);\n            }\n\n            if (bag == null || bag.Deleted || !bag.IsChildOf(World.Player.Backpack))\n            {\n                bag = World.Player.Backpack;\n            }\n\n            m_Cache.Add(item.Serial);\n            DragDropManager.DragDrop(item, bag);\n            DebugLog(\"Dragging to {0}!\", bag);\n        }\n\n        private static void DebugLog(string str, params object[] args)\n        {\n            if (Debug)\n            {\n                using (System.IO.StreamWriter w = new System.IO.StreamWriter(\"Scavenger.log\", true))\n                {\n                    w.Write(Engine.MistedDateTime.ToString(\"HH:mm:ss.fff\"));\n                    w.Write(\":: \");\n                    w.WriteLine(str, args);\n                    w.Flush();\n                }\n            }\n        }\n\n        public override void Save(XmlTextWriter xml)\n        {\n            xml.WriteAttributeString(\"enabled\", m_Enabled.ToString());\n\n            if (m_Bag != Serial.Zero)\n            {\n                xml.WriteStartElement(\"bag\");\n                xml.WriteAttributeString(\"serial\", m_Bag.ToString());\n                xml.WriteEndElement();\n            }\n\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                xml.WriteStartElement(\"item\");\n                xml.WriteAttributeString(\"id\", ((ItemID) m_Items[i]).Value.ToString());\n                xml.WriteEndElement();\n            }\n        }\n\n        public override void Load(XmlElement node)\n        {\n            try\n            {\n                m_Enabled = bool.Parse(node.GetAttribute(\"enabled\"));\n            }\n            catch\n            {\n                m_Enabled = false;\n            }\n\n            try\n            {\n                m_Bag = node[\"bag\"] != null ? Serial.Parse(node[\"bag\"].GetAttribute(\"serial\")) : Serial.Zero;\n            }\n            catch\n            {\n                m_Bag = Serial.Zero;\n            }\n\n            foreach (XmlElement el in node.GetElementsByTagName(\"item\"))\n            {\n                try\n                {\n                    string iid = el.GetAttribute(\"id\");\n                    m_Items.Add((ItemID) Convert.ToUInt16(iid));\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Agents/SearchExemptionAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class SearchExemptionAgent : Agent\n    {\n        public static int Count\n        {\n            get { return Instance.m_Items.Count; }\n        }\n\n        public static SearchExemptionAgent Instance { get; private set; }\n\n        public static void Initialize()\n        {\n            Agent.Add(Instance = new SearchExemptionAgent());\n        }\n\n        public static bool IsExempt(Item item)\n        {\n            if (item == null || item.IsBagOfSending)\n            {\n                return true;\n            }\n\n            return Instance == null ? false : Instance.CheckExempt(item);\n        }\n\n        public static bool Contains(Item item)\n        {\n            return Instance == null\n                ? false\n                : Instance.m_Items.Contains(item.Serial) || Instance.m_Items.Contains(item.ItemID);\n        }\n\n        private ListBox m_SubList;\n        private readonly ArrayList m_Items;\n\n        public SearchExemptionAgent()\n        {\n            m_Items = new ArrayList();\n        }\n\n        public override void Clear()\n        {\n            m_Items.Clear();\n        }\n\n        private bool CheckExempt(Item item)\n        {\n            if (m_Items.Count > 0)\n            {\n                if (m_Items.Contains(item.Serial))\n                {\n                    return true;\n                }\n                else if (m_Items.Contains(item.ItemID))\n                {\n                    return true;\n                }\n                else if (item.Container != null && item.Container is Item)\n                {\n                    return CheckExempt((Item) item.Container);\n                }\n            }\n\n            return false;\n        }\n\n        public override string Name\n        {\n            get { return Language.GetString(LocString.AutoSearchEx); }\n        }\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            m_SubList = subList;\n\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            buttons[1].Text = Language.GetString(LocString.AddTargType);\n            buttons[1].Visible = true;\n            buttons[2].Text = Language.GetString(LocString.Remove);\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.RemoveTarg);\n            buttons[3].Visible = true;\n            buttons[4].Text = Language.GetString(LocString.ClearList);\n            buttons[4].Visible = true;\n\n            m_SubList.BeginUpdate();\n            m_SubList.Items.Clear();\n\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                Item item = null;\n                if (m_Items[i] is Serial)\n                {\n                    item = World.FindItem((Serial) m_Items[i]);\n                }\n\n                if (item != null)\n                {\n                    m_SubList.Items.Add(item.ToString());\n                }\n                else\n                {\n                    m_SubList.Items.Add(m_Items[i].ToString());\n                }\n            }\n\n            m_SubList.EndUpdate();\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            switch (num)\n            {\n                case 1:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTarget));\n                    break;\n                case 2:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetType));\n                    break;\n                case 3:\n                    if (m_SubList.SelectedIndex >= 0 && m_SubList.SelectedIndex < m_Items.Count)\n                    {\n                        m_Items.RemoveAt(m_SubList.SelectedIndex);\n                        m_SubList.Items.RemoveAt(m_SubList.SelectedIndex);\n                    }\n\n                    break;\n                case 4:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargItemRem);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetRemove));\n                    break;\n                case 5:\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        m_SubList.Items.Clear();\n                        m_Items.Clear();\n                    }\n\n                    break;\n            }\n        }\n\n        private void OnTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n            if (!location && serial.IsItem)\n            {\n                m_Items.Add(serial);\n\n                Item item = World.FindItem(serial);\n                if (item != null)\n                {\n                    Client.Instance.SendToClient(new ContainerItem(item));\n                    m_SubList.Items.Add(item.ToString());\n                }\n                else\n                {\n                    m_SubList.Items.Add(serial.ToString());\n                }\n\n                World.Player.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n            }\n        }\n\n        private void OnTargetType(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n\n            if (!serial.IsItem)\n            {\n                return;\n            }\n\n            m_Items.Add((ItemID) gfx);\n            m_SubList.Items.Add(((ItemID) gfx).ToString());\n            World.Player.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n        }\n\n        private void OnTargetRemove(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n            if (!location && serial.IsItem)\n            {\n                for (int i = 0; i < m_Items.Count; i++)\n                {\n                    if (m_Items[i] is Serial && (Serial) m_Items[i] == serial)\n                    {\n                        m_Items.RemoveAt(i);\n                        m_SubList.Items.RemoveAt(i);\n                        World.Player.SendMessage(MsgLevel.Force, LocString.ItemRemoved);\n\n                        Item item = World.FindItem(serial);\n                        if (item != null)\n                        {\n                            Client.Instance.SendToClient(new ContainerItem(item));\n                        }\n\n                        return;\n                    }\n                }\n\n                World.Player.SendMessage(MsgLevel.Force, LocString.ItemNotFound);\n            }\n        }\n\n        public override void Save(XmlTextWriter xml)\n        {\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                xml.WriteStartElement(\"item\");\n                if (m_Items[i] is Serial)\n                {\n                    xml.WriteAttributeString(\"serial\", ((Serial) m_Items[i]).Value.ToString());\n                }\n                else\n                {\n                    xml.WriteAttributeString(\"id\", ((ItemID) m_Items[i]).Value.ToString());\n                }\n\n                xml.WriteEndElement();\n            }\n        }\n\n        public override void Load(XmlElement node)\n        {\n            foreach (XmlElement el in node.GetElementsByTagName(\"item\"))\n            {\n                try\n                {\n                    string ser = el.GetAttribute(\"serial\");\n                    string iid = el.GetAttribute(\"id\");\n\n                    if (!string.IsNullOrEmpty(ser))\n                    {\n                        m_Items.Add((Serial) Convert.ToUInt32(ser));\n                    }\n                    else if (!string.IsNullOrEmpty(iid))\n                    {\n                        m_Items.Add((ItemID) Convert.ToUInt16(iid));\n                    }\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Agents/SellAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Gumps.Internal;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class SellAgent : Agent\n    {\n        public static SellAgent Instance { get; private set; }\n\n        public static void Initialize()\n        {\n            Agent.Add(Instance = new SellAgent());\n        }\n\n        private ListBox m_SubList;\n        private Button m_EnableBTN;\n        private Button m_HotBTN;\n        private Button m_AmountButton;\n        private readonly List<ushort> m_Items;\n        private Serial m_HotBag;\n        private bool m_Enabled;\n        \n        public SellAgent()\n        {\n            m_Items = new List<ushort>();\n            PacketHandler.RegisterServerToClientViewer(0x9E, new PacketViewerCallback(OnVendorSell));\n            PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick));\n\n            Number = 0;\n\n            HotKey.Add(HKCategory.Agents, HKSubCat.None, Language.GetString(LocString.SetSellAgentHotBag),\n                new HotKeyCallback(SetHotBag));\n\n            Agent.OnItemCreated += new ItemCreatedEventHandler(CheckHBOPL);\n        }\n\n        private void CheckHBOPL(Item item)\n        {\n            if (item.Serial == m_HotBag)\n            {\n                item.ObjPropList.Add(Language.GetString(LocString.SellHB));\n            }\n        }\n\n        private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args)\n        {\n            Serial serial = pvSrc.ReadUInt32();\n            if (m_HotBag == serial)\n            {\n                ushort gfx = 0;\n                Item c = World.FindItem(m_HotBag);\n                if (c != null)\n                {\n                    gfx = c.ItemID.Value;\n                }\n\n                Client.Instance.SendToClient(new UnicodeMessage(m_HotBag, gfx, Assistant.MessageType.Label, 0x3B2, 3,\n                    Language.CliLocName, \"\", Language.GetString(LocString.SellHB)));\n            }\n        }\n\n        public override void Clear()\n        {\n            m_Items.Clear();\n        }\n\n        private void OnVendorSell(PacketReader pvSrc, PacketHandlerEventArgs args)\n        {\n            if (!m_Enabled || !Client.Instance.AllowBit(FeatureBit.SellAgent) ||\n                (m_Items.Count == 0 && m_HotBag == Serial.Zero))\n            {\n                return;\n            }\n\n            Item hb = null;\n            if (m_HotBag != Serial.Zero)\n            {\n                hb = World.FindItem(m_HotBag);\n                if (hb == null)\n                {\n                    //m_HotBag = Serial.Zero;\n                    //SetHBText();\n                    World.Player.SendMessage(MsgLevel.Warning, \"Sell Agent HotBag could not be found.\");\n\n                    if (m_Items.Count == 0)\n                    {\n                        return;\n                    }\n                }\n            }\n\n            int total = 0;\n\n            uint serial = pvSrc.ReadUInt32();\n            Mobile vendor = World.FindMobile(serial);\n            if (vendor == null)\n            {\n                World.AddMobile(vendor = new Mobile(serial));\n            }\n\n            int count = pvSrc.ReadUInt16();\n\n            int maxSell = Config.GetInt(\"SellAgentMax\");\n            int sold = 0;\n            List<SellListItem> list = new List<SellListItem>(count);\n            for (int i = 0; i < count && (sold < maxSell || maxSell <= 0); i++)\n            {\n                uint ser = pvSrc.ReadUInt32();\n                ushort gfx = pvSrc.ReadUInt16();\n                ushort hue = pvSrc.ReadUInt16();\n                ushort amount = pvSrc.ReadUInt16();\n                ushort price = pvSrc.ReadUInt16();\n\n                pvSrc.ReadString(pvSrc.ReadUInt16()); //name\n\n                Item item = World.FindItem(ser);\n\n                if (m_Items.Contains(gfx) || (item != null && item != hb && item.IsChildOf(hb)))\n                {\n                    if (sold + amount > maxSell && maxSell > 0)\n                    {\n                        amount = (ushort) (maxSell - sold);\n                    }\n\n                    list.Add(new SellListItem(ser, amount));\n                    total += amount * price;\n                    sold += amount;\n                }\n\n                //if ( sold >= maxSell && maxSell > 0 ) break;\n            }\n\n            if (list.Count > 0)\n            {\n                Client.Instance.SendToServer(new VendorSellResponse(vendor, list));\n                World.Player.SendMessage(MsgLevel.Force, LocString.SellTotals, sold, total);\n                args.Block = true;\n            }\n        }\n\n        public override string Name\n        {\n            get { return Language.GetString(LocString.Sell); }\n        }\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            m_SubList = subList;\n            m_EnableBTN = buttons[5];\n            m_HotBTN = buttons[2];\n            m_AmountButton = buttons[4];\n\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            buttons[1].Text = Language.GetString(LocString.Remove);\n            buttons[1].Visible = true;\n            //button[2] = hotbutton\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.Clear);\n            buttons[3].Visible = true;\n            m_AmountButton.Text = Language.Format(LocString.SellAmount, Config.GetInt(\"SellAgentMax\"));\n            buttons[4].Visible = true;\n            buttons[5].Text = Language.GetString(m_Enabled ? LocString.PushDisable : LocString.PushEnable);\n            buttons[5].Visible = true;\n\n            SetHBText();\n            m_SubList.BeginUpdate();\n            m_SubList.Items.Clear();\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                m_SubList.Items.Add((ItemID) ((ushort) m_Items[i]));\n            }\n\n            m_SubList.EndUpdate();\n\n            if (!Client.Instance.AllowBit(FeatureBit.SellAgent) && Engine.MainWindow != null)\n            {\n                for (int i = 0; i < buttons.Length; i++)\n                {\n                    Engine.MainWindow.SafeAction(s => s.LockControl(buttons[i]));\n                }\n\n                Engine.MainWindow.SafeAction(s => s.LockControl(subList));\n            }\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            switch (num)\n            {\n                case 1:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTarget));\n                    break;\n                case 2:\n                    if (m_SubList.SelectedIndex >= 0)\n                    {\n                        m_Items.RemoveAt(m_SubList.SelectedIndex);\n                        m_SubList.Items.RemoveAt(m_SubList.SelectedIndex);\n                        m_SubList.SelectedIndex = -1;\n                    }\n\n                    break;\n                case 3:\n                    if (m_HotBag == Serial.Zero)\n                    {\n                        World.Player.SendMessage(MsgLevel.Force, LocString.TargCont);\n                        Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnHBTarget));\n                    }\n                    else\n                    {\n                        Item hb = World.FindItem(m_HotBag);\n                        if (hb != null)\n                        {\n                            if (hb.ObjPropList.Remove(Language.GetString(LocString.SellHB)))\n                            {\n                                hb.OPLChanged();\n                            }\n                        }\n\n                        m_HotBag = Serial.Zero;\n                        SetHBText();\n                    }\n\n                    break;\n                case 4:\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        m_SubList.Items.Clear();\n                        m_Items.Clear();\n                    }\n\n                    break;\n                case 5:\n\n                    InputDialogGump gump = new InputDialogGump(OnChangeSellMaxAmount, 0, Language.GetString(LocString.EnterAmount), Config.GetInt(\"SellAgentMax\").ToString());\n                    gump.SendGump();\n\n                    break;\n                case 6:\n                    m_Enabled = !m_Enabled;\n                    m_EnableBTN.Text = Language.GetString(m_Enabled ? LocString.PushDisable : LocString.PushEnable);\n                    break;\n            }\n        }\n        \n        private bool OnChangeSellMaxAmount(int gfx, string amount)\n        {\n            if (int.TryParse(amount, out int parsedAmount))\n            {\n                Config.SetProperty(\"SellAgentMax\", parsedAmount);\n                m_AmountButton.Text = Language.Format(LocString.SellAmount, Config.GetInt(\"SellAgentMax\"));\n\n                return true;\n            }\n\n            return false;\n        }\n\n        private void SetHBText()\n        {\n            m_HotBTN?.SafeAction(s =>\n            {\n                s.Text = Language.GetString(m_HotBag == Serial.Zero ? LocString.SetHB : LocString.ClearHB);\n            });\n        }\n\n        private void OnTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n            if (!location && serial.IsItem)\n            {\n                Add(gfx);\n            }\n        }\n\n        public void Add(ItemID itemId)\n        {\n            m_Items?.Add(itemId);\n            m_SubList?.Items.Add((ItemID)itemId);\n\n            World.Player?.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n        }\n\n        private void OnHBTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n            if (!location && serial.IsItem)\n            {\n                m_HotBag = serial;\n                SetHBText();\n\n                Item hb = World.FindItem(m_HotBag);\n                if (hb != null)\n                {\n                    hb.ObjPropList.Add(Language.GetString(LocString.SellHB));\n                    hb.OPLChanged();\n                }\n            }\n        }\n\n        public void SetHotBag()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargCont);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnHBTarget));\n        }\n\n        /*private void OnHBTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe(););\n\n            Item hb = World.FindItem(m_HotBag);\n            if (hb != null)\n            {\n                if (hb.ObjPropList.Remove(Language.Format(LocString.RestockHBA1, m_Num)))\n                {\n                    hb.OPLChanged();\n                }\n            }\n\n            if (!location && serial.IsItem)\n            {\n                m_HotBag = serial;\n            }\n            else\n            {\n                m_HotBag = Serial.Zero;\n            }\n\n            hb = World.FindItem(m_HotBag);\n            if (hb != null)\n            {\n                hb.ObjPropList.Add(Language.Format(LocString.RestockHBA1, m_Num));\n                hb.OPLChanged();\n            }\n\n            SetHBText();\n        }*/\n\n        public override void Save(XmlTextWriter xml)\n        {\n            if (m_Items == null)\n            {\n                return;\n            }\n\n            xml.WriteAttributeString(\"enabled\", m_Enabled.ToString());\n\n            if (m_HotBag != Serial.Zero)\n            {\n                xml.WriteStartElement(\"hotbag\");\n                xml.WriteString(m_HotBag.ToString());\n                xml.WriteEndElement();\n            }\n\n            foreach (ushort iid in m_Items)\n            {\n                xml.WriteStartElement(\"item\");\n                xml.WriteAttributeString(\"id\", iid.ToString());\n                xml.WriteEndElement();\n            }\n        }\n\n\n        public override void Load(XmlElement node)\n        {\n            try\n            {\n                m_Enabled = bool.Parse(node.GetAttribute(\"enabled\"));\n            }\n            catch\n            {\n                m_Enabled = false;\n            }\n\n            try\n            {\n                m_HotBag = node[\"hotbag\"] != null ? Serial.Parse(node[\"hotbag\"].InnerText) : Serial.Zero;\n            }\n            catch\n            {\n                m_HotBag = Serial.Zero;\n            }\n\n            foreach (XmlElement el in node.GetElementsByTagName(\"item\"))\n            {\n                try\n                {\n                    string str = el.GetAttribute(\"id\");\n                    m_Items.Add(Convert.ToUInt16(str));\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Agents/UseOnceAgent.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\n\nnamespace Assistant.Agents\n{\n    public class UseOnceAgent : Agent\n    {\n        public static UseOnceAgent Instance { get; private set; }\n\n        public static void Initialize()\n        {\n            Agent.Add(Instance = new UseOnceAgent());\n        }\n\n        private ListBox m_SubList;\n        private readonly ArrayList m_Items;\n\n        public UseOnceAgent()\n        {\n            m_Items = new ArrayList();\n            PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnSingleClick));\n            HotKey.Add(HKCategory.Agents, LocString.UseOnceAgent, new HotKeyCallback(OnHotKey));\n            HotKey.Add(HKCategory.Agents, LocString.AddUseOnce, new HotKeyCallback(OnAdd));\n            HotKey.Add(HKCategory.Agents, LocString.AddUseOnceContainer, new HotKeyCallback(OnAddContainer));\n\n            Number = 0;\n\n            Agent.OnItemCreated += new ItemCreatedEventHandler(CheckItemOPL);\n        }\n\n        public override void Clear()\n        {\n            m_Items.Clear();\n        }\n\n        private void CheckItemOPL(Item newItem)\n        {\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                if (m_Items[i] is Serial)\n                {\n                    if (newItem.Serial == (Serial) m_Items[i])\n                    {\n                        m_Items[i] = newItem;\n                        newItem.ObjPropList.Add(Language.GetString(LocString.UseOnce));\n                        break;\n                    }\n                }\n            }\n        }\n\n        private void OnSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args)\n        {\n            Serial serial = pvSrc.ReadUInt32();\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                Item item;\n                if (m_Items[i] is Serial)\n                {\n                    item = World.FindItem((Serial) m_Items[i]);\n                    if (item != null)\n                    {\n                        m_Items[i] = item;\n                    }\n                }\n\n                item = m_Items[i] as Item;\n                if (item == null)\n                {\n                    continue;\n                }\n\n                if (item.Serial == serial)\n                {\n                    Client.Instance.SendToClient(new UnicodeMessage(item.Serial, item.ItemID,\n                        Assistant.MessageType.Label, 0x3B2, 3, Language.CliLocName, \"\",\n                        Language.Format(LocString.UseOnceHBA1, i + 1)));\n                    break;\n                }\n            }\n        }\n\n        public override string Name\n        {\n            get { return Language.GetString(LocString.UseOnce); }\n        }\n\n        public override string Alias { get; set; }\n\n        public override int Number { get; }\n\n        public override void OnSelected(ListBox subList, params Button[] buttons)\n        {\n            m_SubList = subList;\n            buttons[0].Text = Language.GetString(LocString.AddTarg);\n            buttons[0].Visible = true;\n            buttons[1].Text = Language.GetString(LocString.AddContTarg);\n            buttons[1].Visible = true;\n            buttons[2].Text = Language.GetString(LocString.RemoveTarg);\n            buttons[2].Visible = true;\n            buttons[3].Text = Language.GetString(LocString.ClearList);\n            buttons[3].Visible = true;\n\n            m_SubList.BeginUpdate();\n            m_SubList.Items.Clear();\n\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                if (m_Items[i] is Serial)\n                {\n                    Item item = World.FindItem((Serial) m_Items[i]);\n                    if (item != null)\n                    {\n                        m_Items[i] = item;\n                    }\n                }\n\n                m_SubList.Items.Add(m_Items[i]);\n            }\n\n            m_SubList.EndUpdate();\n\n            if (!Client.Instance.AllowBit(FeatureBit.UseOnceAgent) && Engine.MainWindow != null)\n            {\n                for (int i = 0; i < buttons.Length; i++)\n                {\n                    Engine.MainWindow.SafeAction(s => s.LockControl(buttons[i]));\n                }\n\n                Engine.MainWindow.SafeAction(s => s.LockControl(subList));\n            }\n        }\n\n        public override void OnButtonPress(int num)\n        {\n            switch (num)\n            {\n                case 1:\n                    OnAdd();\n                    break;\n                case 2:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargCont);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetBag));\n                    break;\n                case 3:\n                    World.Player.SendMessage(MsgLevel.Force, LocString.TargItemRem);\n                    Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetRemove));\n                    break;\n                case 4:\n\n                    if (MessageBox.Show(Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\n                    {\n                        for (int i = 0; i < m_Items.Count; i++)\n                        {\n                            if (m_Items[i] is Item)\n                            {\n                                Item item = (Item) m_Items[i];\n\n                                item.ObjPropList.Remove(Language.GetString(LocString.UseOnce));\n                                item.OPLChanged();\n                            }\n                        }\n\n                        m_SubList.Items.Clear();\n                        m_Items.Clear();\n                    }\n\n                    break;\n            }\n        }\n\n        public void OnAdd()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTarget));\n        }\n\n        public void OnAddContainer()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargItemAdd);\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTargetBag));\n        }\n\n        private void OnTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (Config.GetBool(\"AlwaysOnTop\"))\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            if (!location && serial.IsItem)\n            {\n                Item item = World.FindItem(serial);\n                if (item == null)\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.ItemNotFound);\n                    return;\n                }\n\n                item.ObjPropList.Add(Language.GetString(LocString.UseOnce));\n                item.OPLChanged();\n\n                m_Items.Add(item);\n                if (m_SubList != null)\n                {\n                    m_SubList.Items.Add(item);\n                }\n\n                World.Player.SendMessage(MsgLevel.Force, LocString.ItemAdded);\n            }\n        }\n\n        private void OnTargetRemove(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n            if (!location && serial.IsItem)\n            {\n                for (int i = 0; i < m_Items.Count; i++)\n                {\n                    bool rem = false;\n                    if (m_Items[i] is Item)\n                    {\n                        if (((Item) m_Items[i]).Serial == serial)\n                        {\n                            ((Item) m_Items[i]).ObjPropList.Remove(Language.GetString(LocString.UseOnce));\n                            ((Item) m_Items[i]).OPLChanged();\n\n                            rem = true;\n                        }\n                    }\n                    else if (m_Items[i] is Serial)\n                    {\n                        if (((Serial) m_Items[i]) == serial)\n                        {\n                            rem = true;\n                        }\n                    }\n\n                    if (rem)\n                    {\n                        m_Items.RemoveAt(i);\n                        m_SubList.Items.RemoveAt(i);\n                        World.Player.SendMessage(MsgLevel.Force, LocString.ItemRemoved);\n                        return;\n                    }\n                }\n\n                World.Player.SendMessage(MsgLevel.Force, LocString.ItemNotFound);\n            }\n        }\n\n        private void OnTargetBag(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            if (Config.GetBool(\"AlwaysOnTop\"))\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n            }\n\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n            if (!location && serial.IsItem)\n            {\n                Item i = World.FindItem(serial);\n                if (i != null && i.Contains.Count > 0)\n                {\n                    for (int ci = 0; ci < i.Contains.Count; ci++)\n                    {\n                        Item toAdd = i.Contains[ci] as Item;\n\n                        if (toAdd != null)\n                        {\n                            toAdd.ObjPropList.Add(Language.GetString(LocString.UseOnce));\n                            toAdd.OPLChanged();\n                            m_Items.Add(toAdd);\n\n                            if (m_SubList != null)\n                            {\n                                m_SubList.Items.Add(toAdd);\n                            }\n                        }\n                    }\n\n                    World.Player.SendMessage(MsgLevel.Force, LocString.ItemsAdded, i.Contains.Count);\n                }\n            }\n        }\n\n        public override void Save(XmlTextWriter xml)\n        {\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                xml.WriteStartElement(\"item\");\n                if (m_Items[i] is Item)\n                {\n                    xml.WriteAttributeString(\"serial\", ((Item) m_Items[i]).Serial.Value.ToString());\n                }\n                else\n                {\n                    xml.WriteAttributeString(\"serial\", ((Serial) m_Items[i]).Value.ToString());\n                }\n\n                xml.WriteEndElement();\n            }\n        }\n\n        public override void Load(XmlElement node)\n        {\n            foreach (XmlElement el in node.GetElementsByTagName(\"item\"))\n            {\n                try\n                {\n                    string ser = el.GetAttribute(\"serial\");\n                    m_Items.Add((Serial) Convert.ToUInt32(ser));\n                }\n                catch\n                {\n                    // ignored\n                }\n            }\n        }\n\n        public void OnHotKey()\n        {\n            if (World.Player == null || !Client.Instance.AllowBit(FeatureBit.UseOnceAgent))\n            {\n                return;\n            }\n\n            if (m_Items.Count <= 0)\n            {\n                World.Player.SendMessage(MsgLevel.Error, LocString.UseOnceEmpty);\n            }\n            else\n            {\n                Item item = null;\n                if (m_Items[0] is Item)\n                {\n                    item = (Item) m_Items[0];\n                }\n                else if (m_Items[0] is Serial)\n                {\n                    item = World.FindItem((Serial) m_Items[0]);\n                }\n\n                try\n                {\n                    m_Items.RemoveAt(0);\n                    if (m_SubList != null && m_SubList.Items.Count > 0)\n                    {\n                        m_SubList.Items.RemoveAt(0);\n                    }\n                }\n                catch\n                {\n                }\n\n                if (item != null)\n                {\n                    item.ObjPropList.Remove(Language.GetString(LocString.UseOnce));\n                    item.OPLChanged();\n\n                    World.Player.SendMessage(LocString.UseOnceStatus, item, m_Items.Count);\n                    PlayerData.DoubleClick(item);\n                }\n                else\n                {\n                    World.Player.SendMessage(LocString.UseOnceError);\n                    OnHotKey();\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Boat/BoatWindow.Designer.cs",
    "content": "﻿using System.Windows.Forms;\n\nnamespace Assistant.Boat\n{\n    partial class BoatWindow\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BoatWindow));\n            this.boatNorth = new System.Windows.Forms.PictureBox();\n            this.boatNortheast = new System.Windows.Forms.PictureBox();\n            this.boatEast = new System.Windows.Forms.PictureBox();\n            this.boatSoutheast = new System.Windows.Forms.PictureBox();\n            this.boatSouth = new System.Windows.Forms.PictureBox();\n            this.boatSouthwest = new System.Windows.Forms.PictureBox();\n            this.boatWest = new System.Windows.Forms.PictureBox();\n            this.boatNorthwest = new System.Windows.Forms.PictureBox();\n            this.boatAnchor = new System.Windows.Forms.PictureBox();\n            this.boatT2a = new System.Windows.Forms.PictureBox();\n            this.boatSpeedNormal = new System.Windows.Forms.RadioButton();\n            this.boatSpeedSlow = new System.Windows.Forms.RadioButton();\n            this.boatSpeedOne = new System.Windows.Forms.RadioButton();\n            this.boatStop = new System.Windows.Forms.PictureBox();\n            this.boatTurnRight = new System.Windows.Forms.PictureBox();\n            this.boatTurnLeft = new System.Windows.Forms.PictureBox();\n            this.boatTurnAround = new System.Windows.Forms.PictureBox();\n            this.boatGoto1 = new System.Windows.Forms.Button();\n            this.boatGoto2 = new System.Windows.Forms.Button();\n            this.boatGoto3 = new System.Windows.Forms.Button();\n            this.boatGoto4 = new System.Windows.Forms.Button();\n            this.boatGoto5 = new System.Windows.Forms.Button();\n            this.boatGoto6 = new System.Windows.Forms.Button();\n            this.boatGoto7 = new System.Windows.Forms.Button();\n            this.boatGoto8 = new System.Windows.Forms.Button();\n            this.boatGoto9 = new System.Windows.Forms.Button();\n            this.boatStart = new System.Windows.Forms.Button();\n            this.boatContinue = new System.Windows.Forms.Button();\n            this.boatNav = new System.Windows.Forms.Button();\n            this.alwaysOnTop = new System.Windows.Forms.CheckBox();\n            this.boatBorder = new System.Windows.Forms.PictureBox();\n            this.boatWindowsBorder = new System.Windows.Forms.CheckBox();\n            this.boatClose = new System.Windows.Forms.Label();\n            ((System.ComponentModel.ISupportInitialize)(this.boatNorth)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatNortheast)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatEast)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatSoutheast)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatSouth)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatSouthwest)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatWest)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatNorthwest)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatAnchor)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatT2a)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatStop)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatTurnRight)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatTurnLeft)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatTurnAround)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatBorder)).BeginInit();\n            this.SuspendLayout();\n            // \n            // boatNorth\n            // \n            this.boatNorth.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;\n            this.boatNorth.Image = ((System.Drawing.Image)(resources.GetObject(\"boatNorth.Image\")));\n            this.boatNorth.Location = new System.Drawing.Point(80, 40);\n            this.boatNorth.Name = \"boatNorth\";\n            this.boatNorth.Size = new System.Drawing.Size(27, 28);\n            this.boatNorth.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatNorth.TabIndex = 0;\n            this.boatNorth.TabStop = false;\n            this.boatNorth.MouseClick += new System.Windows.Forms.MouseEventHandler(this.boatNorth_MouseClick);\n            // \n            // boatNortheast\n            // \n            this.boatNortheast.Image = ((System.Drawing.Image)(resources.GetObject(\"boatNortheast.Image\")));\n            this.boatNortheast.Location = new System.Drawing.Point(113, 40);\n            this.boatNortheast.Name = \"boatNortheast\";\n            this.boatNortheast.Size = new System.Drawing.Size(27, 28);\n            this.boatNortheast.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatNortheast.TabIndex = 1;\n            this.boatNortheast.TabStop = false;\n            this.boatNortheast.MouseClick += new MouseEventHandler(this.boatNortheast_Click);\n            // \n            // boatEast\n            // \n            this.boatEast.Image = ((System.Drawing.Image)(resources.GetObject(\"boatEast.Image\")));\n            this.boatEast.Location = new System.Drawing.Point(113, 74);\n            this.boatEast.Name = \"boatEast\";\n            this.boatEast.Size = new System.Drawing.Size(27, 28);\n            this.boatEast.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatEast.TabIndex = 2;\n            this.boatEast.TabStop = false;\n            this.boatEast.Click += new System.EventHandler(this.boatEast_Click);\n            // \n            // boatSoutheast\n            // \n            this.boatSoutheast.Image = ((System.Drawing.Image)(resources.GetObject(\"boatSoutheast.Image\")));\n            this.boatSoutheast.Location = new System.Drawing.Point(113, 108);\n            this.boatSoutheast.Name = \"boatSoutheast\";\n            this.boatSoutheast.Size = new System.Drawing.Size(27, 28);\n            this.boatSoutheast.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatSoutheast.TabIndex = 3;\n            this.boatSoutheast.TabStop = false;\n            this.boatSoutheast.MouseClick += new MouseEventHandler(this.boatSoutheast_Click);\n            // \n            // boatSouth\n            // \n            this.boatSouth.Image = ((System.Drawing.Image)(resources.GetObject(\"boatSouth.Image\")));\n            this.boatSouth.Location = new System.Drawing.Point(80, 108);\n            this.boatSouth.Name = \"boatSouth\";\n            this.boatSouth.Size = new System.Drawing.Size(27, 28);\n            this.boatSouth.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatSouth.TabIndex = 4;\n            this.boatSouth.TabStop = false;\n            this.boatSouth.Click += new System.EventHandler(this.boatSouth_Click);\n            // \n            // boatSouthwest\n            // \n            this.boatSouthwest.Image = ((System.Drawing.Image)(resources.GetObject(\"boatSouthwest.Image\")));\n            this.boatSouthwest.Location = new System.Drawing.Point(47, 108);\n            this.boatSouthwest.Name = \"boatSouthwest\";\n            this.boatSouthwest.Size = new System.Drawing.Size(27, 28);\n            this.boatSouthwest.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatSouthwest.TabIndex = 5;\n            this.boatSouthwest.TabStop = false;\n            this.boatSouthwest.MouseClick += new MouseEventHandler(this.boatSouthwest_Click);\n            // \n            // boatWest\n            // \n            this.boatWest.Image = ((System.Drawing.Image)(resources.GetObject(\"boatWest.Image\")));\n            this.boatWest.Location = new System.Drawing.Point(47, 74);\n            this.boatWest.Name = \"boatWest\";\n            this.boatWest.Size = new System.Drawing.Size(27, 28);\n            this.boatWest.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatWest.TabIndex = 6;\n            this.boatWest.TabStop = false;\n            this.boatWest.Click += new System.EventHandler(this.boatWest_Click);\n            // \n            // boatNorthwest\n            // \n            this.boatNorthwest.Image = ((System.Drawing.Image)(resources.GetObject(\"boatNorthwest.Image\")));\n            this.boatNorthwest.Location = new System.Drawing.Point(47, 40);\n            this.boatNorthwest.Name = \"boatNorthwest\";\n            this.boatNorthwest.Size = new System.Drawing.Size(27, 28);\n            this.boatNorthwest.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatNorthwest.TabIndex = 7;\n            this.boatNorthwest.TabStop = false;\n            this.boatNorthwest.MouseClick += new MouseEventHandler(this.boatNorthwest_Click);\n            // \n            // boatAnchor\n            // \n            this.boatAnchor.Image = ((System.Drawing.Image)(resources.GetObject(\"boatAnchor.Image\")));\n            this.boatAnchor.Location = new System.Drawing.Point(15, 142);\n            this.boatAnchor.Name = \"boatAnchor\";\n            this.boatAnchor.Size = new System.Drawing.Size(27, 28);\n            this.boatAnchor.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatAnchor.TabIndex = 8;\n            this.boatAnchor.TabStop = false;\n            this.boatAnchor.Click += new System.EventHandler(this.boatAnchor_Click);\n            // \n            // boatT2a\n            // \n            this.boatT2a.Image = ((System.Drawing.Image)(resources.GetObject(\"boatT2a.Image\")));\n            this.boatT2a.Location = new System.Drawing.Point(145, 142);\n            this.boatT2a.Name = \"boatT2a\";\n            this.boatT2a.Size = new System.Drawing.Size(27, 28);\n            this.boatT2a.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatT2a.TabIndex = 9;\n            this.boatT2a.TabStop = false;\n            this.boatT2a.Click += new System.EventHandler(this.boatT2a_Click);\n            // \n            // boatSpeedNormal\n            // \n            this.boatSpeedNormal.AutoSize = true;\n            this.boatSpeedNormal.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatSpeedNormal.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatSpeedNormal.Location = new System.Drawing.Point(12, 12);\n            this.boatSpeedNormal.Name = \"boatSpeedNormal\";\n            this.boatSpeedNormal.Size = new System.Drawing.Size(62, 17);\n            this.boatSpeedNormal.TabIndex = 11;\n            this.boatSpeedNormal.TabStop = true;\n            this.boatSpeedNormal.Text = \"Normal\";\n            this.boatSpeedNormal.UseVisualStyleBackColor = true;\n            // \n            // boatSpeedSlow\n            // \n            this.boatSpeedSlow.AutoSize = true;\n            this.boatSpeedSlow.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatSpeedSlow.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatSpeedSlow.Location = new System.Drawing.Point(74, 12);\n            this.boatSpeedSlow.Name = \"boatSpeedSlow\";\n            this.boatSpeedSlow.Size = new System.Drawing.Size(50, 17);\n            this.boatSpeedSlow.TabIndex = 12;\n            this.boatSpeedSlow.TabStop = true;\n            this.boatSpeedSlow.Text = \"Slow\";\n            this.boatSpeedSlow.UseVisualStyleBackColor = true;\n            // \n            // boatSpeedOne\n            // \n            this.boatSpeedOne.AutoSize = true;\n            this.boatSpeedOne.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatSpeedOne.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatSpeedOne.Location = new System.Drawing.Point(128, 12);\n            this.boatSpeedOne.Name = \"boatSpeedOne\";\n            this.boatSpeedOne.Size = new System.Drawing.Size(47, 17);\n            this.boatSpeedOne.TabIndex = 13;\n            this.boatSpeedOne.TabStop = true;\n            this.boatSpeedOne.Text = \"One\";\n            this.boatSpeedOne.UseVisualStyleBackColor = true;\n            // \n            // boatStop\n            // \n            this.boatStop.Image = ((System.Drawing.Image)(resources.GetObject(\"boatStop.Image\")));\n            this.boatStop.Location = new System.Drawing.Point(80, 74);\n            this.boatStop.Name = \"boatStop\";\n            this.boatStop.Size = new System.Drawing.Size(27, 28);\n            this.boatStop.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatStop.TabIndex = 14;\n            this.boatStop.TabStop = false;\n            this.boatStop.Click += new System.EventHandler(this.boatStop_Click);\n            // \n            // boatTurnRight\n            // \n            this.boatTurnRight.Image = ((System.Drawing.Image)(resources.GetObject(\"boatTurnRight.Image\")));\n            this.boatTurnRight.Location = new System.Drawing.Point(146, 74);\n            this.boatTurnRight.Name = \"boatTurnRight\";\n            this.boatTurnRight.Size = new System.Drawing.Size(26, 19);\n            this.boatTurnRight.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatTurnRight.TabIndex = 16;\n            this.boatTurnRight.TabStop = false;\n            this.boatTurnRight.Click += new System.EventHandler(this.boatTurnRight_Click);\n            // \n            // boatTurnLeft\n            // \n            this.boatTurnLeft.Image = ((System.Drawing.Image)(resources.GetObject(\"boatTurnLeft.Image\")));\n            this.boatTurnLeft.Location = new System.Drawing.Point(15, 74);\n            this.boatTurnLeft.Name = \"boatTurnLeft\";\n            this.boatTurnLeft.Size = new System.Drawing.Size(26, 19);\n            this.boatTurnLeft.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatTurnLeft.TabIndex = 17;\n            this.boatTurnLeft.TabStop = false;\n            this.boatTurnLeft.Click += new System.EventHandler(this.boatTurnLeft_Click);\n            // \n            // boatTurnAround\n            // \n            this.boatTurnAround.Image = ((System.Drawing.Image)(resources.GetObject(\"boatTurnAround.Image\")));\n            this.boatTurnAround.Location = new System.Drawing.Point(80, 142);\n            this.boatTurnAround.Name = \"boatTurnAround\";\n            this.boatTurnAround.Size = new System.Drawing.Size(27, 28);\n            this.boatTurnAround.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatTurnAround.TabIndex = 18;\n            this.boatTurnAround.TabStop = false;\n            this.boatTurnAround.Click += new System.EventHandler(this.boatTurnAround_Click);\n            // \n            // boatGoto1\n            // \n            this.boatGoto1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto1.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto1.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto1.Location = new System.Drawing.Point(26, 185);\n            this.boatGoto1.Name = \"boatGoto1\";\n            this.boatGoto1.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto1.TabIndex = 19;\n            this.boatGoto1.Text = \"1\";\n            this.boatGoto1.UseVisualStyleBackColor = true;\n            this.boatGoto1.Click += new System.EventHandler(this.boatGoto1_Click);\n            // \n            // boatGoto2\n            // \n            this.boatGoto2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto2.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto2.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto2.Location = new System.Drawing.Point(54, 185);\n            this.boatGoto2.Name = \"boatGoto2\";\n            this.boatGoto2.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto2.TabIndex = 20;\n            this.boatGoto2.Text = \"2\";\n            this.boatGoto2.UseVisualStyleBackColor = true;\n            this.boatGoto2.Click += new System.EventHandler(this.boatGoto2_Click);\n            // \n            // boatGoto3\n            // \n            this.boatGoto3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto3.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto3.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto3.Location = new System.Drawing.Point(82, 185);\n            this.boatGoto3.Name = \"boatGoto3\";\n            this.boatGoto3.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto3.TabIndex = 21;\n            this.boatGoto3.Text = \"3\";\n            this.boatGoto3.UseVisualStyleBackColor = true;\n            this.boatGoto3.Click += new System.EventHandler(this.boatGoto3_Click);\n            // \n            // boatGoto4\n            // \n            this.boatGoto4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto4.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto4.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto4.Location = new System.Drawing.Point(26, 212);\n            this.boatGoto4.Name = \"boatGoto4\";\n            this.boatGoto4.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto4.TabIndex = 22;\n            this.boatGoto4.Text = \"4\";\n            this.boatGoto4.UseVisualStyleBackColor = true;\n            this.boatGoto4.Click += new System.EventHandler(this.boatGoto4_Click);\n            // \n            // boatGoto5\n            // \n            this.boatGoto5.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto5.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto5.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto5.Location = new System.Drawing.Point(54, 212);\n            this.boatGoto5.Name = \"boatGoto5\";\n            this.boatGoto5.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto5.TabIndex = 23;\n            this.boatGoto5.Text = \"5\";\n            this.boatGoto5.UseVisualStyleBackColor = true;\n            this.boatGoto5.Click += new System.EventHandler(this.boatGoto5_Click);\n            // \n            // boatGoto6\n            // \n            this.boatGoto6.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto6.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto6.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto6.Location = new System.Drawing.Point(82, 212);\n            this.boatGoto6.Name = \"boatGoto6\";\n            this.boatGoto6.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto6.TabIndex = 24;\n            this.boatGoto6.Text = \"6\";\n            this.boatGoto6.UseVisualStyleBackColor = true;\n            this.boatGoto6.Click += new System.EventHandler(this.boatGoto6_Click);\n            // \n            // boatGoto7\n            // \n            this.boatGoto7.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto7.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto7.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto7.Location = new System.Drawing.Point(26, 239);\n            this.boatGoto7.Name = \"boatGoto7\";\n            this.boatGoto7.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto7.TabIndex = 25;\n            this.boatGoto7.Text = \"7\";\n            this.boatGoto7.UseVisualStyleBackColor = true;\n            this.boatGoto7.Click += new System.EventHandler(this.boatGoto7_Click);\n            // \n            // boatGoto8\n            // \n            this.boatGoto8.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto8.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto8.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto8.Location = new System.Drawing.Point(54, 239);\n            this.boatGoto8.Name = \"boatGoto8\";\n            this.boatGoto8.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto8.TabIndex = 26;\n            this.boatGoto8.Text = \"8\";\n            this.boatGoto8.UseVisualStyleBackColor = true;\n            this.boatGoto8.Click += new System.EventHandler(this.boatGoto8_Click);\n            // \n            // boatGoto9\n            // \n            this.boatGoto9.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatGoto9.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatGoto9.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatGoto9.Location = new System.Drawing.Point(82, 239);\n            this.boatGoto9.Name = \"boatGoto9\";\n            this.boatGoto9.Size = new System.Drawing.Size(22, 21);\n            this.boatGoto9.TabIndex = 27;\n            this.boatGoto9.Text = \"9\";\n            this.boatGoto9.UseVisualStyleBackColor = true;\n            this.boatGoto9.Click += new System.EventHandler(this.boatGoto9_Click);\n            // \n            // boatStart\n            // \n            this.boatStart.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatStart.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatStart.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatStart.Location = new System.Drawing.Point(110, 185);\n            this.boatStart.Name = \"boatStart\";\n            this.boatStart.Size = new System.Drawing.Size(52, 21);\n            this.boatStart.TabIndex = 28;\n            this.boatStart.Text = \"Start\";\n            this.boatStart.UseVisualStyleBackColor = true;\n            this.boatStart.Click += new System.EventHandler(this.boatStart_Click);\n            // \n            // boatContinue\n            // \n            this.boatContinue.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatContinue.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatContinue.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatContinue.Location = new System.Drawing.Point(110, 212);\n            this.boatContinue.Name = \"boatContinue\";\n            this.boatContinue.Size = new System.Drawing.Size(52, 21);\n            this.boatContinue.TabIndex = 29;\n            this.boatContinue.Text = \"Cont.\";\n            this.boatContinue.UseVisualStyleBackColor = true;\n            this.boatContinue.Click += new System.EventHandler(this.boatContinue_Click);\n            // \n            // boatNav\n            // \n            this.boatNav.FlatStyle = System.Windows.Forms.FlatStyle.Flat;\n            this.boatNav.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatNav.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatNav.Location = new System.Drawing.Point(110, 239);\n            this.boatNav.Name = \"boatNav\";\n            this.boatNav.Size = new System.Drawing.Size(52, 21);\n            this.boatNav.TabIndex = 30;\n            this.boatNav.Text = \"Nav\";\n            this.boatNav.UseVisualStyleBackColor = true;\n            this.boatNav.Click += new System.EventHandler(this.boatNav_Click);\n            // \n            // alwaysOnTop\n            // \n            this.alwaysOnTop.AutoSize = true;\n            this.alwaysOnTop.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.alwaysOnTop.ForeColor = System.Drawing.Color.DarkGray;\n            this.alwaysOnTop.Location = new System.Drawing.Point(11, 270);\n            this.alwaysOnTop.Name = \"alwaysOnTop\";\n            this.alwaysOnTop.Size = new System.Drawing.Size(101, 17);\n            this.alwaysOnTop.TabIndex = 31;\n            this.alwaysOnTop.Text = \"Always On Top\";\n            this.alwaysOnTop.UseVisualStyleBackColor = true;\n            this.alwaysOnTop.CheckedChanged += new System.EventHandler(this.alwaysOnTop_CheckedChanged);\n            // \n            // boatBorder\n            // \n            this.boatBorder.Image = ((System.Drawing.Image)(resources.GetObject(\"boatBorder.Image\")));\n            this.boatBorder.Location = new System.Drawing.Point(0, 0);\n            this.boatBorder.Name = \"boatBorder\";\n            this.boatBorder.Size = new System.Drawing.Size(190, 296);\n            this.boatBorder.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.boatBorder.TabIndex = 32;\n            this.boatBorder.TabStop = false;\n            this.boatBorder.Visible = false;\n            // \n            // boatWindowsBorder\n            // \n            this.boatWindowsBorder.AutoSize = true;\n            this.boatWindowsBorder.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.boatWindowsBorder.ForeColor = System.Drawing.Color.DarkGray;\n            this.boatWindowsBorder.Location = new System.Drawing.Point(114, 270);\n            this.boatWindowsBorder.Name = \"boatWindowsBorder\";\n            this.boatWindowsBorder.Size = new System.Drawing.Size(61, 17);\n            this.boatWindowsBorder.TabIndex = 33;\n            this.boatWindowsBorder.Text = \"Border\";\n            this.boatWindowsBorder.UseVisualStyleBackColor = true;\n            this.boatWindowsBorder.CheckedChanged += new System.EventHandler(this.boatWindowsBorder_CheckedChanged);\n            // \n            // boatClose\n            // \n            this.boatClose.AutoSize = true;\n            this.boatClose.ForeColor = System.Drawing.Color.DimGray;\n            this.boatClose.Location = new System.Drawing.Point(172, 4);\n            this.boatClose.Name = \"boatClose\";\n            this.boatClose.Size = new System.Drawing.Size(14, 15);\n            this.boatClose.TabIndex = 34;\n            this.boatClose.Text = \"X\";\n            this.boatClose.Click += new System.EventHandler(this.boatClose_Click);\n            // \n            // BoatWindow\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.BackColor = System.Drawing.Color.Black;\n            this.ClientSize = new System.Drawing.Size(190, 296);\n            this.Controls.Add(this.boatClose);\n            this.Controls.Add(this.boatWindowsBorder);\n            this.Controls.Add(this.alwaysOnTop);\n            this.Controls.Add(this.boatNav);\n            this.Controls.Add(this.boatContinue);\n            this.Controls.Add(this.boatStart);\n            this.Controls.Add(this.boatGoto9);\n            this.Controls.Add(this.boatGoto8);\n            this.Controls.Add(this.boatGoto7);\n            this.Controls.Add(this.boatGoto6);\n            this.Controls.Add(this.boatGoto5);\n            this.Controls.Add(this.boatGoto4);\n            this.Controls.Add(this.boatGoto3);\n            this.Controls.Add(this.boatGoto2);\n            this.Controls.Add(this.boatGoto1);\n            this.Controls.Add(this.boatTurnAround);\n            this.Controls.Add(this.boatTurnLeft);\n            this.Controls.Add(this.boatTurnRight);\n            this.Controls.Add(this.boatStop);\n            this.Controls.Add(this.boatSpeedOne);\n            this.Controls.Add(this.boatSpeedSlow);\n            this.Controls.Add(this.boatSpeedNormal);\n            this.Controls.Add(this.boatT2a);\n            this.Controls.Add(this.boatAnchor);\n            this.Controls.Add(this.boatNorthwest);\n            this.Controls.Add(this.boatWest);\n            this.Controls.Add(this.boatSouthwest);\n            this.Controls.Add(this.boatSouth);\n            this.Controls.Add(this.boatSoutheast);\n            this.Controls.Add(this.boatEast);\n            this.Controls.Add(this.boatNortheast);\n            this.Controls.Add(this.boatNorth);\n            this.Controls.Add(this.boatBorder);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.MaximizeBox = false;\n            this.MinimizeBox = false;\n            this.Name = \"BoatWindow\";\n            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\n            this.Text = \"Razor Boat Control\";\n            this.Load += new System.EventHandler(this.BoatWindow_Load);\n            ((System.ComponentModel.ISupportInitialize)(this.boatNorth)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatNortheast)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatEast)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatSoutheast)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatSouth)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatSouthwest)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatWest)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatNorthwest)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatAnchor)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatT2a)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatStop)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatTurnRight)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatTurnLeft)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatTurnAround)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.boatBorder)).EndInit();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.PictureBox boatNorth;\n        private System.Windows.Forms.PictureBox boatNortheast;\n        private System.Windows.Forms.PictureBox boatEast;\n        private System.Windows.Forms.PictureBox boatSoutheast;\n        private System.Windows.Forms.PictureBox boatSouth;\n        private System.Windows.Forms.PictureBox boatSouthwest;\n        private System.Windows.Forms.PictureBox boatWest;\n        private System.Windows.Forms.PictureBox boatNorthwest;\n        private System.Windows.Forms.PictureBox boatAnchor;\n        private System.Windows.Forms.PictureBox boatT2a;\n        private System.Windows.Forms.RadioButton boatSpeedNormal;\n        private System.Windows.Forms.RadioButton boatSpeedSlow;\n        private System.Windows.Forms.RadioButton boatSpeedOne;\n        private System.Windows.Forms.PictureBox boatStop;\n        private System.Windows.Forms.PictureBox boatTurnRight;\n        private System.Windows.Forms.PictureBox boatTurnLeft;\n        private System.Windows.Forms.PictureBox boatTurnAround;\n        private System.Windows.Forms.Button boatGoto1;\n        private System.Windows.Forms.Button boatGoto2;\n        private System.Windows.Forms.Button boatGoto3;\n        private System.Windows.Forms.Button boatGoto4;\n        private System.Windows.Forms.Button boatGoto5;\n        private System.Windows.Forms.Button boatGoto6;\n        private System.Windows.Forms.Button boatGoto7;\n        private System.Windows.Forms.Button boatGoto8;\n        private System.Windows.Forms.Button boatGoto9;\n        private System.Windows.Forms.Button boatStart;\n        private System.Windows.Forms.Button boatContinue;\n        private System.Windows.Forms.Button boatNav;\n        private System.Windows.Forms.CheckBox alwaysOnTop;\n        private System.Windows.Forms.PictureBox boatBorder;\n        private System.Windows.Forms.CheckBox boatWindowsBorder;\n        private System.Windows.Forms.Label boatClose;\n    }\n}"
  },
  {
    "path": "Razor/Boat/BoatWindow.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Windows.Forms;\n\nnamespace Assistant.Boat\n{\n    public partial class BoatWindow : Form\n    {\n        private enum Orientation\n        {\n            Normal,\n            Northwest,\n            Southwest,\n            Southeast,\n            Northeast\n        }\n\n        private int _orientation = 0;\n\n        public const int WM_NCLBUTTONDOWN = 0xA1;\n        public const int HT_CAPTION = 0x2;\n\n        [System.Runtime.InteropServices.DllImport(\"user32.dll\")]\n        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);\n\n        [System.Runtime.InteropServices.DllImport(\"user32.dll\")]\n        public static extern bool ReleaseCapture();\n\n        private bool _inT2A = false;\n        private bool _ancherUp = false;\n\n        public BoatWindow()\n        {\n            InitializeComponent();\n            this.MouseDown += BoatWindow_MouseDown;\n            this.boatBorder.MouseDown += BoatWindow_MouseDown;\n        }\n\n        private void BoatWindow_Load(object sender, EventArgs e)\n        {\n            alwaysOnTop.Checked = true;\n        }\n\n        private void BoatWindow_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\n        {\n            if (e.Button == MouseButtons.Left)\n            {\n                ReleaseCapture();\n                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);\n            }\n        }\n\n        private void SendBoatCommand(string command, bool directionCommand = true)\n        {\n            string boatCommand = command;\n\n            if (boatSpeedOne.Checked && directionCommand)\n            {\n                boatCommand = $\"{command} One\";\n            }\n            else if (boatSpeedSlow.Checked && directionCommand)\n            {\n                boatCommand = $\"Slow {command}\";\n            }\n\n            if (World.Player != null)\n            {\n                World.Player.Say(boatCommand);\n            }\n        }\n\n        private string[] _boatDirCommands =\n            {\"Forward\", \"Forward Right\", \"Right\", \"Back Right\", \"Back\", \"Back Left\", \"Left\", \"Forward Left\"};\n        //        0             1            2           3          4        5          6           7\n\n        private void boatNorth_MouseClick(object sender, MouseEventArgs e)\n        {\n            switch (e.Button)\n            {\n                case MouseButtons.Left:\n\n                    switch (_orientation)\n                    {\n                        case (int) Orientation.Northwest:\n                            SendBoatCommand(_boatDirCommands[1]);\n                            break;\n                        case (int) Orientation.Southwest:\n                            SendBoatCommand(_boatDirCommands[3]);\n                            break;\n                        case (int) Orientation.Southeast:\n                            SendBoatCommand(_boatDirCommands[5]);\n                            break;\n                        case (int) Orientation.Northeast:\n                            SendBoatCommand(_boatDirCommands[7]);\n                            break;\n                        default:\n                            SendBoatCommand(_boatDirCommands[0]);\n                            break;\n                    }\n\n                    //SendBoatCommand(_boatDirCommands[1]); //NW orientation\n                    //SendBoatCommand(_boatDirCommands[3]); //SW orientation\n                    //SendBoatCommand(_boatDirCommands[5]); //SE orientation\n                    //SendBoatCommand(_boatDirCommands[7]); //NE orientation\n                    break;\n                case MouseButtons.Right:\n                    _orientation = (int) Orientation.Normal;\n\n                    boatNorth.BorderStyle = BorderStyle.FixedSingle;\n                    boatNortheast.BorderStyle = BorderStyle.None;\n                    boatNorthwest.BorderStyle = BorderStyle.None;\n                    boatSouthwest.BorderStyle = BorderStyle.None;\n                    boatSoutheast.BorderStyle = BorderStyle.None;\n\n                    if (World.Player != null)\n                        World.Player.SendMessage(MsgLevel.Force, \"Set Boat Orientation: Normal\");\n\n                    break;\n            }\n        }\n\n        private void boatNorthwest_Click(object sender, MouseEventArgs e)\n        {\n            switch (e.Button)\n            {\n                case MouseButtons.Left:\n                    switch (_orientation)\n                    {\n                        case (int) Orientation.Northwest:\n                            SendBoatCommand(_boatDirCommands[0]);\n                            break;\n                        case (int) Orientation.Southwest:\n                            SendBoatCommand(_boatDirCommands[2]);\n                            break;\n                        case (int) Orientation.Southeast:\n                            SendBoatCommand(_boatDirCommands[4]);\n                            break;\n                        case (int) Orientation.Northeast:\n                            SendBoatCommand(_boatDirCommands[6]);\n                            break;\n                        default:\n                            SendBoatCommand(_boatDirCommands[7]);\n                            break;\n                    }\n\n                    break;\n                case MouseButtons.Right:\n                    _orientation = (int) Orientation.Northwest;\n\n                    boatNorth.BorderStyle = BorderStyle.None;\n                    boatNortheast.BorderStyle = BorderStyle.None;\n                    boatNorthwest.BorderStyle = BorderStyle.FixedSingle;\n                    boatSouthwest.BorderStyle = BorderStyle.None;\n                    boatSoutheast.BorderStyle = BorderStyle.None;\n\n                    if (World.Player != null)\n                        World.Player.SendMessage(MsgLevel.Force, \"Set Boat Orientation: Northwest\");\n\n\n                    break;\n            }\n        }\n\n        private void boatSouth_Click(object sender, EventArgs e)\n        {\n            switch (_orientation)\n            {\n                case (int) Orientation.Northwest:\n                    SendBoatCommand(_boatDirCommands[5]);\n                    break;\n                case (int) Orientation.Southwest:\n                    SendBoatCommand(_boatDirCommands[7]);\n                    break;\n                case (int) Orientation.Southeast:\n                    SendBoatCommand(_boatDirCommands[1]);\n                    break;\n                case (int) Orientation.Northeast:\n                    SendBoatCommand(_boatDirCommands[3]);\n                    break;\n                default:\n                    SendBoatCommand(_boatDirCommands[4]);\n                    break;\n            }\n        }\n\n        private void boatSoutheast_Click(object sender, MouseEventArgs e)\n        {\n            switch (e.Button)\n            {\n                case MouseButtons.Left:\n                    switch (_orientation)\n                    {\n                        case (int) Orientation.Northwest:\n                            SendBoatCommand(_boatDirCommands[4]);\n                            break;\n                        case (int) Orientation.Southwest:\n                            SendBoatCommand(_boatDirCommands[6]);\n                            break;\n                        case (int) Orientation.Southeast:\n                            SendBoatCommand(_boatDirCommands[0]);\n                            break;\n                        case (int) Orientation.Northeast:\n                            SendBoatCommand(_boatDirCommands[2]);\n                            break;\n                        default:\n                            SendBoatCommand(_boatDirCommands[3]);\n                            break;\n                    }\n\n                    break;\n                case MouseButtons.Right:\n                    _orientation = (int) Orientation.Southeast;\n\n                    boatNorth.BorderStyle = BorderStyle.None;\n                    boatNortheast.BorderStyle = BorderStyle.None;\n                    boatNorthwest.BorderStyle = BorderStyle.None;\n                    boatSouthwest.BorderStyle = BorderStyle.None;\n                    boatSoutheast.BorderStyle = BorderStyle.FixedSingle;\n\n                    if (World.Player != null)\n                        World.Player.SendMessage(MsgLevel.Force, \"Set Boat Orientation: Southeast\");\n\n                    break;\n            }\n        }\n\n        private void boatSouthwest_Click(object sender, MouseEventArgs e)\n        {\n            switch (e.Button)\n            {\n                case MouseButtons.Left:\n                    switch (_orientation)\n                    {\n                        case (int) Orientation.Northwest:\n                            SendBoatCommand(_boatDirCommands[6]);\n                            break;\n                        case (int) Orientation.Southwest:\n                            SendBoatCommand(_boatDirCommands[0]);\n                            break;\n                        case (int) Orientation.Southeast:\n                            SendBoatCommand(_boatDirCommands[2]);\n                            break;\n                        case (int) Orientation.Northeast:\n                            SendBoatCommand(_boatDirCommands[4]);\n                            break;\n                        default:\n                            SendBoatCommand(_boatDirCommands[5]);\n                            break;\n                    }\n\n                    break;\n                case MouseButtons.Right:\n                    _orientation = (int) Orientation.Southwest;\n\n                    boatNorth.BorderStyle = BorderStyle.None;\n                    boatNortheast.BorderStyle = BorderStyle.None;\n                    boatNorthwest.BorderStyle = BorderStyle.None;\n                    boatSouthwest.BorderStyle = BorderStyle.FixedSingle;\n                    boatSoutheast.BorderStyle = BorderStyle.None;\n\n                    if (World.Player != null)\n                        World.Player.SendMessage(MsgLevel.Force, \"Set Boat Orientation: Southwest\");\n\n                    break;\n            }\n        }\n\n        private void boatWest_Click(object sender, EventArgs e)\n        {\n            switch (_orientation)\n            {\n                case (int) Orientation.Northwest:\n                    SendBoatCommand(_boatDirCommands[7]);\n                    break;\n                case (int) Orientation.Southwest:\n                    SendBoatCommand(_boatDirCommands[1]);\n                    break;\n                case (int) Orientation.Southeast:\n                    SendBoatCommand(_boatDirCommands[3]);\n                    break;\n                case (int) Orientation.Northeast:\n                    SendBoatCommand(_boatDirCommands[5]);\n                    break;\n                default:\n                    SendBoatCommand(_boatDirCommands[6]);\n                    break;\n            }\n        }\n\n        private void boatNortheast_Click(object sender, MouseEventArgs e)\n        {\n            switch (e.Button)\n            {\n                case MouseButtons.Left:\n                    switch (_orientation)\n                    {\n                        case (int) Orientation.Northwest:\n                            SendBoatCommand(_boatDirCommands[2]);\n                            break;\n                        case (int) Orientation.Southwest:\n                            SendBoatCommand(_boatDirCommands[4]);\n                            break;\n                        case (int) Orientation.Southeast:\n                            SendBoatCommand(_boatDirCommands[6]);\n                            break;\n                        case (int) Orientation.Northeast:\n                            SendBoatCommand(_boatDirCommands[0]);\n                            break;\n                        default:\n                            SendBoatCommand(_boatDirCommands[1]);\n                            break;\n                    }\n\n                    break;\n                case MouseButtons.Right:\n                    _orientation = (int) Orientation.Northeast;\n\n                    boatNorth.BorderStyle = BorderStyle.None;\n                    boatNortheast.BorderStyle = BorderStyle.FixedSingle;\n                    boatNorthwest.BorderStyle = BorderStyle.None;\n                    boatSouthwest.BorderStyle = BorderStyle.None;\n                    boatSoutheast.BorderStyle = BorderStyle.None;\n\n                    if (World.Player != null)\n                        World.Player.SendMessage(MsgLevel.Force, \"Set Boat Orientation: Northeast\");\n\n                    break;\n            }\n        }\n\n        private void boatEast_Click(object sender, EventArgs e)\n        {\n            switch (_orientation)\n            {\n                case (int) Orientation.Northwest:\n                    SendBoatCommand(_boatDirCommands[3]);\n                    break;\n                case (int) Orientation.Southwest:\n                    SendBoatCommand(_boatDirCommands[5]);\n                    break;\n                case (int) Orientation.Southeast:\n                    SendBoatCommand(_boatDirCommands[7]);\n                    break;\n                case (int) Orientation.Northeast:\n                    SendBoatCommand(_boatDirCommands[1]);\n                    break;\n                default:\n                    SendBoatCommand(_boatDirCommands[2]);\n                    break;\n            }\n        }\n\n        private void boatTurnRight_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Turn Right\", false);\n\n            switch (_orientation)\n            {\n                case (int) Orientation.Northwest:\n                    boatNortheast_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Southwest:\n                    boatNorthwest_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Southeast:\n                    boatSouthwest_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Northeast:\n                    boatSoutheast_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n            }\n        }\n\n        private void boatTurnLeft_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Turn Left\", false);\n\n            switch (_orientation)\n            {\n                case (int) Orientation.Northwest:\n                    boatSouthwest_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Southwest:\n                    boatSoutheast_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Southeast:\n                    boatNortheast_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Northeast:\n                    boatNorthwest_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n            }\n        }\n\n        private void boatTurnAround_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Turn Around\", false);\n\n            switch (_orientation)\n            {\n                case (int) Orientation.Northwest:\n                    boatSoutheast_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Southwest:\n                    boatNortheast_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Southeast:\n                    boatNorthwest_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n                case (int) Orientation.Northeast:\n                    boatSouthwest_Click(null, new MouseEventArgs(MouseButtons.Right, 1, 1, 1, 1));\n                    break;\n            }\n        }\n\n        private void boatAnchor_Click(object sender, EventArgs e)\n        {\n            if (_ancherUp)\n            {\n                SendBoatCommand(\"Drop Anchor\", false);\n                _ancherUp = false;\n            }\n            else\n            {\n                SendBoatCommand(\"Raise Anchor\", false);\n                _ancherUp = true;\n            }\n        }\n\n        private void boatT2a_Click(object sender, EventArgs e)\n        {\n            if (_inT2A)\n            {\n                SendBoatCommand(\"Sueacron\", false);\n                _inT2A = false;\n            }\n            else\n            {\n                SendBoatCommand(\"Doracron\", false);\n                _inT2A = true;\n            }\n        }\n\n        private void alwaysOnTop_CheckedChanged(object sender, EventArgs e)\n        {\n            TopMost = alwaysOnTop.Checked;\n        }\n\n        private void boatGoto1_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 1\", false);\n        }\n\n        private void boatGoto2_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 2\", false);\n        }\n\n        private void boatGoto3_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 3\", false);\n        }\n\n        private void boatGoto4_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 4\", false);\n        }\n\n        private void boatGoto5_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 5\", false);\n        }\n\n        private void boatGoto6_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 6\", false);\n        }\n\n        private void boatGoto7_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 7\", false);\n        }\n\n        private void boatGoto8_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 8\", false);\n        }\n\n        private void boatGoto9_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Goto 9\", false);\n        }\n\n        private void boatStart_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Start\", false);\n        }\n\n        private void boatContinue_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Continue\", false);\n        }\n\n        private void boatNav_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Nav\", false);\n        }\n\n        private void boatWindowsBorder_CheckedChanged(object sender, EventArgs e)\n        {\n            boatBorder.Visible = boatWindowsBorder.Checked;\n        }\n\n        private void boatStop_Click(object sender, EventArgs e)\n        {\n            SendBoatCommand(\"Stop\", false);\n        }\n\n        private void boatClose_Click(object sender, EventArgs e)\n        {\n            Hide();\n        }\n    }\n}"
  },
  {
    "path": "Razor/Boat/BoatWindow.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"boatNorth.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAUFSURBVGhD7Vor\n        sKNKEI2MjMQikUgsEokci0QixyJHIrEjkUgsEhkZG3nlyn7nzAz7srt3782+ejeZVG1XdVF8Evr06e7p\n        6eTwV+6U0/Eox+NBwunrSlUkkqWn1wZCJggkTY4AQn1RUWUq1Cw9SnJ6WSBH0U0mbZ1KkZ9ekRVvcFtn\n        YtpCeqiqMpcniQPzMsIqdRTTlTL2NVRJ31VSl3lI+pcA49lowMCgK7GmETt0Mo2d6LZGiKWvwooHYtoc\n        QEppVAnjM1nn0QFSdQFWkthZ8SBqVKkeQAgmOZ1cmNnRyDIZhJjyrMRdwQIbHRM8R4KnDgS1qsqfWIk2\n        VzwIVqcdSJp4Nqi8N1sjc2Alj5cVbyzzgkAalN4dxA5E1ZWsS/S5gkpVM8ErV3Zp5C2QXReE1w+5ElcF\n        8x7nmkEgrSreBcFn2kbJdsNKnkXFCnMjl9F4IPQ0DT+FinWrvLYtFqwMN6xE0Rl7T9sBC5/xK/it0bcg\n        qHy2161sq0VJ1oGVNAZWsG5UhUxDC0aUlIVP8vdA7JomiZy32ZXjXjduwXwyK97Ds2UL0sqAnmoH8BEQ\n        fmYYNMBMMtkerJSuHD+RFZbUEkB6GKQdMzT0IxC75lkml/Pi8sX0rRRg8kmseM+ylFInxDsNoZH3AOFn\n        52l0YGYkfqNYJLLnAGlU7Ra4ZR5QVmtn4D0gdi3LQt6uG0JsEWM0WEFvhvwJL3iUHAHCyorqw0UuDQvg\n        nwDhd2zrItfrGd9hpYEzCCa84DHCdmNbJwdGo5zSk2ma3qW3YBRY/fZ2kfN5BSs9ql7x2FzxIFB1EN+q\n        rmGQgkcbd/xMazyfIdl3MJfzJtfL5nKGwB7GSg02LvAgw8H0Wvq+RzkdnBpj7lKtNVp7v3i2rfqeK8PQ\n        u5afIRpe93Xyhpi+wIPLPAEEgMAorbGV7TrpuvZfbRsYCUV/xcLAI43mdaedV67018sKMKs7TnZw18Pr\n        vkbIxre3q0tQJqq1o2NFw3AayerFUsotLtuPGvsTDujKPHFHnit0ybzfYQ8/YA1h+eVK78EwzFZ3Xn5l\n        iDEUmNh7ctPzM5iZJwtPGvRcWgbTiNE12vlKdFugG/azLR51g00XrvP+iOc4lFhm4xZGMpPhO/fv57vC\n        ax8nE5ihF7dlkIUti2si2Q1jo4XdYt9wxsX9SoF2v8J95Z7xrc0Xh9GfSJHnKACznNdR1knLPCoAqWQE\n        kKHzgwiD4wggvE6QbPvJTBrXgPsIRuwNI7VYeJ4MEMAOxDPCwV2FECvdJoyfDV8Sh3DntyHeCYQetzSY\n        jPykBMJjh3xh8oePxyNsHlcAmW3rQyd4nhsunzMNzv11DihalUtVsn2PTCwqkAOCBN7zg0CYzKxmy4R2\n        nxswXNuBlEWEQAwMXufeAyEAGMsQYkOZYTvL0CMYMsQpPUdGhRs+RCa6Q1sPQwmE4cMhHX8fCbcPXPhW\n        tPwsufvsK8+iqlheGuwW6XECYXXqsADeThPJCvfpC3aUvM+pJKeR4XY8UpX5dyDe47/GP8emZMUi6fnT\n        Q5Q/MXCC4hJ6RCOIsHpvtutYQa4w6fmLVpTzXwJhjrD9YFiFy78Ih3MML91waxshEE4NWX65hnzkaZ8r\n        2L8g/KJkJEMpJRCOTcOl3woXz88AP03oaebIPZWIz7IoRBlaNI7zrXD6qXAvEmX5PSFM/ED6PuGz/MNN\n        OI1J/otRUQL5K/+DHA7/AFGuD+HZCC/CAAAAAElFTkSuQmCC\n</value>\n  </data>\n  <data name=\"boatNortheast.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAnQSURBVGhD7Zh7\n        UFNXHsetWr2BAAGCBEEwPA3yMEQkUUGeylMQRJCnhIc8lAQIBKKovCEBiQLlIUiESpE34qO0StWqfdiH\n        u+O023a72+0fu+Mu3Z3dznS2O9v57rl4dTu6dv+BtnT4zHznJvfe3N/53nPO7/xOli2xxBJLLLHELxPK\n        lsiEa7yqVY9aPsScXAxQK5ljHpui9umvpn6/hsN66OFkDIe1huBQlMej6z9bKCdjY4pNjjfMTFl9JsYU\n        rLjUv+2tKAgdDRAq4WHHJu5+5uafI1Qi14CKe3EFBUue4W/51sbY5LQGIgEP24XmCJJwkRzEx1YXU1DU\n        shLmRz8HKAMWixKTY5+5EXXO1IgNO0tDuDlaIGCbM2JCNyN7fwDkqb4oTBVDleaOokRH7N1hM8w84KeE\n        MidyY7PZlfos/U/WWrD+yrfiQui8DptFdoiL2IJ8aQjqS5PR2yzDQFsx+rQ56K5OQHORH3L2CEB+/x4R\n        i3ngj8sLL1AZq1frZxsZGbxvYcb9xsHWHB7Olgjy3oDY0C04nBaMurIkdDbJMXr2GK6NNGOiX4N2tRKK\n        g9Ho00jRVh6Gg3tcwGEbjDGP/fHg8XjWTnaWGWZmHDg5WcHDzZ4Mm03YG+4JWXoYasib1zXLMamrwNUh\n        DS4NN+HyQCPkOUmIjgqGoQEb4YEiNCp3o6EgAHwrE5CXQveKkgmxcPB4nCCikI0bHcccHGxnvb3cEOTn\n        gaT4QORnRaOxKge61jJMvFKHGxfbcfdKJ853VqBdW47QIG8IXV2wgkx4iqLA1tPD7u22OFXiDVWKELZr\n        TWkTbxIZMOHmD3+JkEsfrazWNjs62ra4uzt9u9nNBZG7g5CwPxzKkoNo0SgxdK6BNLwDb73Ri7euncN7\n        ty+gU3sUeenx8HAnQ8bIFKtXU1i58pEJWnbrOChMEKA2T4hdXutoE7RuEK2YCz5f6OmxHEUujp+qq4ve\n        K5RLEbs3DFJpPBRy0vgWNabGe3H7xgQ+/vAafvfRdXxwZwxDfSdRX1eAHRJPONmux/Lljxq9atV/DdDS\n        12PB1ZYLldQVqnR3eDrzHhuJZ8LPHyRgqPkaMwy9fAr3bo3hzswQLk/24u7MKD66fxN//PLX+PzTe/js\n        wW001JYgNysFFmY8rDEzezJ86F74voHH4hjqIzncAfUyT8iT3PHiShZt4k9EFkz4+YVM6Dg+fz1en9Lh\n        L1++jT9/eRsP//Au7t2+jNemhpCZmQRfHx9wuWZzjX76zT8tFos1d1xP5kN+wiYyySVICBWAWqVPG+lj\n        wi4MdtbWcXvDAvHh3XF88fEMLg69NDc/uKam4HCMnmns86Svrw8jo0f3B4jtoSkKQIsqEC4OFrSJ74j8\n        mJALh6ZCHndj8gzukIncoT2CdGksJBIvCIVCrF+//klDv9/wp0Vfp3vEysIEaXtEOF0WAmX6NvC4JrSR\n        r4hIJfAjMHK2fPTVsVp0N8pQVpSC/ENpUJWVkgQghb+/P/h8/pM3/r9kaGgIPZJyN9hbQFO8C51VkUiK\n        ENEm/kYkYcIsLNbWRpXFuaEYOXMYOm02lIejkJsWhRJZDslStcjPz0dISMhzzdA9QfeIMceArPYexMRe\n        aFRh2GhnSRv5hGj+145noQKs15qhoiAML2tTcL45FQ1lUchK2oq0xEDIZVLU1dX8oBlSf8HAwGDufHH2\n        TvSfTEVr9X6Yc+cWwSom0MISFewkTtzt/s0JmT961HtwQbsP7RURKM/1Q0KEM/ZHeOFQZgrqap9vhjZB\n        HwO83dClScVgSzZ2B3nSJr4hcmNCLRxB2/niUH/+bGa8EDWFvuipIb2iCcOZCn80yL2Qt9+ZlBmWiNkp\n        IjUU3TPPDjN6WNHzw9iYjbSEQIz2KTHVX4htWzbSRj4g4jHhFgaxwFy8Q2Q9mxy5ESXpm0mW8cWZygB0\n        nfBBR5kXmmQeKD8gQE60LaL9rJAUuwNF8mfnDJfLnZvkm1wc0N9ajCsD1ThWlEgWTT3aSA4TbmFw5nPE\n        IoHJbIy/LRSpHmgskqDjhC86T9C5fzuaFORcvhAN2a44kekGRYYIB2JFyEqJIPWXDPX1dU+ZMUFwoBdG\n        +mtwffwkDmdEk8WTTRvJZELOPxY8ltiGZzgb5m1Dygc3NB3aiq6KEOjqY8gmKAbtx4LRrJCg8bAQLYVC\n        tCq9cfpIEBoKQ5F3IBC5mXFQKuVzZhQKBcLDw2FjYw11bRFuvt6N8QE1bG34tIkRJuT8wzOhxDxTapau\n        RmWJ7jhVuo1kmERMkLR7qVeJyR4FXiEZp+P4LjSXSNBSKkZvRSAGmvZAp07AycoEFGTHID83GUdLi6HV\n        NqOgoADJ8bHo7arD3Vvnca6j5rGRcSbs/DJnwpyajfS2RjlZcV+u3oNL3Qpcu1CDWxe1uPdaB7oaC0gK\n        PoR+dRy6ygPRc8wXA3VhmOzYh1d1eZjSKXDulBKqYimKC7Jx/HgpamtqUH1CiVcvdeP9OyNITYheQBMc\n        YoJDzaaRilRbGo6LXUWYGVNjZlSLkbN131YcyUZLY0mLo6P1t7IMkrWqo9BdRdaD6gAMnozE1bOZeOdi\n        Je6/0YY7r/Vg5PxpqCtVqCkvJSaOoLWpCjNXBnB1/AwSokMXxoQVjy3mraFm6X8zBk8mY2ZYg+vDWtRV\n        5H2RlRr1ID9rn59AwE+k7+XzeUGFBzy/66R7g0z8fnUkJjuluHlBhQ+ut+LTD4cxPdmD8cHery9ODKK9\n        VYPenlZcnRjA/Xem8cb0+V/NBZ1vjFmUeB3XcFaVF4qmI7EY11V8nRK/63J8TFADafwqInPm1jkifdZe\n        qs4Vok2xFf21wRh9KRnTg0W4d0mN+ze70FRfgM2url9VqhSStramuKysA+jrbsPHD+7is9+8jcyMxH9F\n        R4euYx43X1AOLy6nZjfaWeF0VdogaXTpzoAtO5iLz0CGnqXvpjUPjx90J2uJH0a1iZjuK8SdKTVuTjTh\n        3ekOsp+gyth6nCcFoECwIc7e3g5XLw/j7w8//+7B+zM7mUvzDeUjFPB9mC8/iMTVNDc3zh6Nii14pXkf\n        pnUFxEQlhkk2G+s7+txNEb05syVriTQtEaQ3djOnfxpIb6zYsM7wTVW6G/oaYnCFmLg5Uol2dRY0VdL/\n        u7MjRWMcqX61zNefDk8nE5vCBMGDdrIwTukO4xoxcVwWB3lG2MJuT+cb0iOVhSmeJC1nYIaYyE8PRUSg\n        aHGZoGkoCKwf1Cbj9kQtZAeC4S8RLD4TfB4nID7ME7cm6pCZFIBtIrvFZ4LmdNVBn0nd0X8m7fOHQMBb\n        nCZIajbfKtzwj5BAT2KCvzhNPIatz37b2Ji1uE08gjrEfFhiiV82y5b9B9NZKrUTvUWDAAAAAElFTkSu\n        QmCC\n</value>\n  </data>\n  <data name=\"boatEast.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAR7SURBVGhD7Zgt\n        kJxAEIVPIldikUgkFolEjh2JRI5FIkdikUgkFolErl15MrLzXgN7l8sludxtVXYrdFUXy+4F5pvXf5On\n        ww477LDDDjvssP/AgiCQLE1ku31cC8NQlnmQqrJyOp0eF4ggl/MkfeclzzNJoU4YPiBQHEXyfJkVxvta\n        jCkQaukGFD4OUO1KhXi+TAixUYa+laapxdpCYdIk3hQK7htqHjvNkRWGysyyLJOMQwcgJ9bkAIolSaJ7\n        BAokik7ia4sFN1DBC5UpSyPnZZZvz2e5XJZNIS9NXYopkD9QJ4lvDhTICaUzwkPDMJDwtPn+GVf+lsQn\n        SeMQcR9JnkVS5LGUJpXGFdK3JbwCUKlVi6WYzjyZp1EVOi+jULW+qwFrAYT8gToJnsl33ASIu8OFDFhQ\n        1xTiq1ScTaQsYrFYsIFbfoaXBt/DK5tKXWXS4u97b3G1UpWFguR5foXhArMs1ZwhzDL3Mg2tdK3DvzdX\n        oDgCEDbuJkAxgMa+wYu8jNi53gOsBpjDzgOuKbcr3DtA1LmC996oMtZkgLHinJM4jq8wO1CC77x3mkvz\n        1OFdXjpfXYGYPzFC9cZAXqaxfYFStYwuvq0JsXrX8D7HYnIsBkoBpGkaKYriB5DXQBHKMXOJoTbjHdy8\n        10BXhW4VcgQaOiq0AfWrSq2qlKlSLZxXh1DTvEGiE8QYg0IQvQtD5wI5AZTWoFDg+QAa3gVac/d2QFBo\n        3b0aKlgFaapk9ZJ5E0uehrqwj4DszgXyaor8umm7Qg45V2SJwkRb8bkZUIcYZ3IrCADotYUSRSRZEiJP\n        ir8C2X1dYKDjTdeuQCxAGrJQOk1OAGJYBgoWBE+fB4oQt+wZzJVdEf9FRX7l7DVUpa2N1Cgy3CiDss93\n        0NkytmV93Cipw67vlUr9miO8ZgiDPUfWZP8KSIjcYQVkCDMfWS35foJ8SgkCWOxEhd2usevsL1y4Vit1\n        lt+1BDdatdJr1foTCBOd/vo7Nl6TR6owN8e7HM/NtJ99KjcIsC9+7RkAeLPwtX8UaKJGc+baR6rytyDv\n        AbDUstnyfbsThs2Yv/81BHeEu7A3ub612u1/8q5Eb6nUp97p1SMMOBj+CuQ9AJbXkmMOdn1vtPQCIbQn\n        /4t/wNYRBQtCaZ0w/KnjM+935/00vPw+00cvy9TqldWsxMj+FuQtAD9nmIJZjbhpL55pdfoUwGp8OOQF\n        zOqh7hRfRs9Rxy0mVlchD1ixUBJZ59lTlrnD/DToyNGjB7AZugrqeI9ziP1BEU66RY4wRRVqUfV0SoDy\n        TGaLieALALcwhkcCCHblDhAl5qwVhIrwZMiSTaWoeN/BEZo6wyGvTP7PAX62YeihGCZaDIx1jaMuZi2H\n        eYrjx6jjDc4rmNkG5BOVuavFvzbmRgdlasAQqNehs5MJUy7nKILwUHW3ALsxH3iIGqEMj7fT2OMeZw/A\n        cGy5e4Dd9L+DcKw946x+xlmdEBwEHwZgN4J8e77gWLvgLEKABzWW2IcGOOywww477LDDDruVPT19B3xJ\n        D+GMWMoJAAAAAElFTkSuQmCC\n</value>\n  </data>\n  <data name=\"boatSoutheast.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAnWSURBVGhD7Zh5\n        UJTnHceNMfguLLDAIosguJwucrisiCuCnAosCIIIcspyyKGwCwsLKCr3sRyrQDgEwUUJciPeUaJGzGEO\n        23GSNmnaNH+0Y0vaaTOTaTrNfPu829e26cQxf7hWZvjM/PY99t3n93z39/x+7/M8K5ZZ5qWCcmROljKU\n        32srqUUTFrWVubE0EQr4fhvtrbGOa7RozWMvbTGnatJHK/LDwVtDLfI4SzgyAgG/rPVIHIrStoIIWeSZ\n        LlExO4O27JgeqvpmtC0F6RGO4FksYTGpCbsuz4+roC6LQJSvDXhm1KIlj7X0xCTEhjTdGlfjYl8xKjN8\n        sMt7HWx5RosufM7SEkPyRK+hKv/L+almnKvdg8IkD0h8bSESmC5uFVg8UwxFUeH6+iwn5lI3kBJrwZw+\n        FSLEIjst+tH8pBqX+hU4WeYDWbI7YgPtsENksxiynf9UMTweL95ijTlErk6fBYqFXOb284Q6xDZgv7tN\n        uOGvp2oO+vF5nCDmix+lIHtfwMSZhu9uXqjDcFsSWg9tgyLNEylRGxEeyF+MDnUmYqgftGFvYxPP56/H\n        2LmTaK4t/oC5/fwxMWFpwoK9MDt09G8JEi80yYMbSYmt9nI2tSXHV5nHtJCoJFUdycHdi2rMnD6Mvqow\n        tBSLUZqxGVkJQiTt9vjWZq05bGyMq+nnVVWy+L2SYLw5N4QHd6dQJJPC2nptu7YxXUA6qEneF4i7Mw0Y\n        VaegKNULRYmCRxvWGb0tdjPLI4KsmEdXdLSUdjy40YNLg0oMNcai54Q/TpX7o67IHycKA1Ell6AkLxwT\n        Zyonb8+exsf3p/HHr97FwvwY4vZK4ORk18E0pRsEAp4mKzkI92bqSWXKRDf5tysy3JEX7wD/TWseR/mt\n        vcTn80KcnGy+62uRY3ZAgf7aWPSeCMLp6iAM1Ekw0LwH59SpmCDRujZVj4WbZ/Hlp/P4w1f3cHl2EFJp\n        Ajw8nL/j8TghjFvd4COy1xQeCMX8RDXmhg5D0xSLFsUWHD/ogdo8IYoOeH1fmCkhnT2EN9rS0H0sFB0V\n        29F3wg/nVBJcUO/D+fY0DKlz0N9SiB71EVwcex2Pf/s+7s9PQiE7iM3uriBCwhiXuiNQLNAUZITjJhFz\n        ZUiON9r3kY4GoEuxDb2VwThdG43h5nj0HN+FdoUYrQpP9JR743RVIIliJJrKo6E8HI3y4lRkSOOQuD8C\n        D+5dxicP76CjoxlRu0OwcaPTFONOt0QGizTHC+Nxh4i5TsRMqpMwXB+KATKM+mt2oo8Iai8Vo+WwEC0F\n        QrQWeqJJ5o3KvABkJ29DXno0Cg6lQyz2BtfMDDfmxvC7r36OuelBrTBHR7tFUpJtGHe6RZYp0XQ3Z2Nh\n        jojRFGHy9RQSiSgM15J8OOaPjrKt6CgSoinHDZUHBMjf74LESBekJwWjtDAXFeVlEAqF4HCMkZWVjC8+\n        e4B7t2egLD0IX293ONtbZTKudI+qRqoZJ9VpYa4Z10eLMdsrxWhbFEYaJBisCkan0hcnstyRG2OH3dut\n        sD/SG7JCKRob6kliS7F+/XqQNzr8/fzw+aN7+PTjm+hQKRES4Alzcw5eeYV6cWKmNEc1d2Za8eBSM+5c\n        qMDVM1mY7dmHkdY9OHUkBIpMEWICrBG7U4RDWaloaKhDQUEBAgMDtSJo43LN0VRfil9/cgtjZ5uQnBAM\n        Z2drrF5tkMO4eTG8f71H8/BOHz661Yn3Llbj2lA+hpoT0VQUjgNxIiTH7YAsV4qG+n+JCAsLA5/Ph4GB\n        gVbI6tUU8rJT8dHCFG5f7EFBdgw83R1gbGz4IZkJPHN69Byhylsb5fjs43E8fKuLlGYF2qoTkX8gGNmp\n        kSiW5ZJI1P9AhLGx8b8joqdHwdKchzFNG955axAtNbkI8tlE7nG/JW27M050D1ufI97s5vb19dkBLNwY\n        wNmTSshzYpGXFU+St1CbE08T8cTWmJuT5+R4h7wkhzrLsTfCC452FmCz2drpzAujukIhnh4d/Gbi/ClU\n        lEhRkJcCpVKGxsaGZ4qg7dVXKewQe+GDexcw80YDCjMk8HSxggHL4JckKoaMG93T1dUaf3FmFM3VFSiR\n        5+BoWclPFvHEnO3Wo1d9lORJN+rKUhDiuwFrLVl/Yr2orSaBYEN8dvYBdHeqUFdZhuPHy6BWt0OhUPxk\n        EXTCr1xJIT8jAfev9GKoXYa48C3gW3NBIqJhXOkOelHk4GAPTX8XBgc6UXviCOrr6iCXyxEREaEVweVy\n        wWKxflTA/5qnhyvO91aRZUMVDqeHQuiyDhbG1FnGnW4giRhvRzp69fI4Pn10H1dnRtDZWkPEKJGSEAdb\n        WxsiwhT6+vowMjKCoaEhnbxPFUVXL46xGbrVlbg6pkJDeTI2i+xhZsymo5LEuH3+kPeAWpqehL88/uL7\n        z3/xLh6+dx3zV0Zw7VI/Bvsa0FxfjNBgb2xydYSJCVvbWVoM/f6ghdHHJ++SJ0YPsfAQX1wab0Vvqwzx\n        kVtgb2UEriEVz7jVDTEx4bsffTi/Mysz6e9vXT//s6vTp/HhwgTu3z2PO2/2Y2KYLHs7S5CeGIwgX3dt\n        rphwDLVRoiNDX/93hFatoiB0c8XlkRZMnjmGAmkY3J0s8RqpaiQqzoxb3UEEraOPiTHh02mJMTjbU4fp\n        kWbcmm7DlZFaTGqU6FOloSRnJ0liT2xwsIS1pekPovHE6FIsy00mS4V2NJLqFeTjAiue0a9MTCi21tmL\n        g5q2s+WDtsOZMThWnIS54SKMduRgmCy4emv2QlWyC+l7RAja6oD1a83AMSLDTP8/kYmJDsXMsAqD7YWI\n        Dd8Mvo0JHZHbxFYxTl4U1DSxCT09NvmH9eGzZSN2h3ihs3Y/VBUSIiaKrOXDoCoOQkHiJqREOMLNjgv7\n        dRyw6eJgyEZ3sxIjXSXI2R+ETc5rYG7G0n0ZfjpUFrFcYh8R+9aCa4aN9lZIjhRBmeFDlsLBaJKL0Vjo\n        hQqpG72pQab8dogIFkFxMAYadS5kaf4QCXgwNdHmST7T8P8LikeMTACpGmL0tOPPPFKaXR0tkRgugCzZ\n        AxUZHqjPF+JkqS9alLuhUUnRX5uo3eXfLrSANZf6B5ui9jENvgzQcydKTOxrYt9TegZ4bRULXi487Z5x\n        RSpZWcqD0FUpQXtxACrSPRAi5sLBmoLBauo35Dd2TEMvC/QcigogRsY+9Xti9NCBHUl+vrUpDu5xRe4e\n        AYqTnJASwofQyRBrOKzH5BlTpoGXEcqSWAIxujK9TZa54LANp8j5B3t32I5vczVDuJgHT2cTcE30Opkf\n        vczQ27DaoadkrlnaT2pF6Y5N3P2Oa42gT60c0361lOFQlCdzuswyyyyzzMvGihX/BKVCKrWoB0HcAAAA\n        AElFTkSuQmCC\n</value>\n  </data>\n  <data name=\"boatSouth.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAUESURBVGhD7Vor\n        lKtIEB2JjMQikUgsEonEIpHItsiWSGxLJBIbiYyMHTnyydp7qyGTnZ1P3p6dTGfPq3PqMOGXun3r25mn\n        P/L/lUi2P35D/s0z3yyHQyRZmtxsGO89RAECSWHYNJqbDZvGTpL4ECaQZepvMo73zmMrcRwkI7EcZyuD\n        Kb80bpmsOFtJDHfcToUjeZYokK8MJBvHeZChy8MEUuSpHOFa01BLV6cfGrhMgyyuF9NkYboWgTBGprGR\n        voWR76y2srGMANtKW6VhMlIWmQJhEFu4TVP9MxXPzqpbub6SpgSQEBlpquICZDC5utf1ivvYGNWteL0G\n        kCDTr+kqjRECGftC3cs0r7EyIzbIxnRhLEUBDRCI7RsY6oG4vtSsNJhCkiQWsrEiNsiYs7XY1gPJkbK3\n        x8MRh0rN9KtAbCkjQIwEBIBuMD4RIMh5joy0dSZFfntLczdhkVMgjkAqdS8aTQamAWBsg8/+/A6kLAIE\n        QtdZAWRxnQJxBAJW6F7XSiA8dk0uFQJ+ezwUieS0OsQBi10HBggEboXsZLsMMQHFkZ93pvquACs5gASU\n        gvMsk/NpltNxROYyiJP6EifDFZARQHheXQ9qTYVkEFDmmtwIRuYrRhgTlboQQfRIwzx6Rkpc93HDVMxk\n        sL3mfhJhEIrjWDVJEum6VuZ5knlyMqFqMzsNCGqutO1KMUizLQpjiyrPo0Fc9DjP6yPu40yyIK7WxUlv\n        Wknxzv39/K7ta/97qapSfr08y/PzSdbjIg5M2N6IAaC2raVt0HrUJbSQuvLBXOaxFFmsR36uq0yvdy0Y\n        67EQKJRk8/l8lJfnVY/8XOTZ9zL1AhDn84qVnKQHiN4AiOkAplOGLto2AAdtahhe6ZFgeV6180omPIij\n        Hic36Pnt675PyMr5dAQQp2z0PXqnAfMF1Fp7kxqAL8tS3YfgyMRpXfCOHucLORzulADW44R2fJIJblFX\n        ldQ1Vr1p9PiVVrg/TVMFQT2f6E4rXGzE9Ury73apa6nBigfjsLqcvX3w36I7ACoN//VylhMYtrZHXGBq\n        vG9HHCmI49HBxUYY6LMMXeLa0M+U72DCYOKgmzZIFHdlw0ukAcxpb0FrzmxF434HSFHkl9iw1igIMrt9\n        wb3ErygbRSr3s+gSNPAWMHyWMXE+LZp+mbLz7Mf6Lvg4psIZE9/kDGpErkbeAiRDsBMEC6FFLckx7985\n        Nq5lW1m2JNpq1BcQn4HhMwM6gNOKrIdF4GJkGdt5XvsxiZQJHZgwd3AnhcZ+BiRBHLByc37vTaMu9YNs\n        7OJX2GmTWGsftRv8Hhjey0q+Its5xBXbGL/x/aNs7IJYKdGia7fLoPW14j0gPMe44CZd39V6bwBs7OJX\n        mmMsgbQYlt4CoPIe9lucJN3QbWww3QbBxi6oK+hqCcRi8ku3AvlWWTyZrl/ZCAoExa+4DlLbntU1AF5j\n        W8MCurNBsIGxQdmMxbxBINyc4y7iNRBul84bG0y3Qe77evEG70Dq8rVBZGvOdPvKBgM8cCBVkSgQzujx\n        lrnc6FuZS2yEy8YuGyu60VDoSMuC93c2goyNt+KB8CcDZjDuLhIANxkMZvRAM9VH4uOCadhvkfqKXxVZ\n        6LHxVjwr/EWKu+49lNmMIB6IjWuJ9PcR7mnl2QHp2APcLj6W1Mhg1DSJHiFTfSxR9KQbcw/Nxi4E4oP8\n        wYX/OENmto9/5HN5evoL29wP4R4iUDsAAAAASUVORK5CYII=\n</value>\n  </data>\n  <data name=\"boatSouthwest.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAnISURBVGhD7Zl5\n        UJPpHcddD3wDAQIECYJgOA1yGBAxKsoRFAIIgghySjjkUBIgnIrKDQlIFFgOQTAoIiCHt67iseq669mO\n        s3bdbrv1j3Zs2XbanXFqp863zxujo113948VlZbPzG9e8l7P7/s+7+94XqZNMcX/DdQWzR+TFwMDhoqp\n        w7yh+Tk54fG4qgChO5bxF/yDz+OaaHZPLng8jip2gw9Gu7f/c2/55pWa3ZOL5W7WqpRYX1wZqUZUoDu4\n        HJav5tDkwUfAU0k2+ePqSBX6lHGozRbWaA5NHoKFbqqsJBHGBstwrD0ZOfHu4LCoMs3hyYE0OVC1UxKJ\n        80TE8e6taCkNQE407767vaGl5pT3h46OjpLJZEZqfv4oinKxqkWeistExKnubKhqw1Gc5IwF8/Q+JTMy\n        Q3Pa+yEsTLRWnBgDKy4XHA7nR8UMqbarBroKcO14Gc4SEYcbNqBOtgQZkTYQOBllaE77SUhqJlmNmpjM\n        dv/22Oq/P/7m2emTA7CxsQaPt+ClGKY2S0AGLvribKvq8kg9ESHHWVUOjipj0L7LGzs3u8Br0ZzHZDbM\n        NJf8gNW+S1aROlO4tzyxb6G1OWZNp8bJPW01h98OZDbmpSTH/Ovr39zAg/vXoepoRmrqJjQ310eWFcsE\n        i52cvquvyca9y+24eYKI6MvF0Y/j0FPlj2bZMlRk8BGycu4Jze3UEKdNiGlFhfvVxketOTncXfp9/bYI\n        FGeKMI+tN27AoJZqTn27XDx76Ff3Pj+L0yO96OpsQkuTAsdG+jDc1/X92dFOPLw7gDsXmnD5SDFG28To\n        kYegc5cv2kqEyNnk/ozL5fjR9yHOx2SlbvBOTQi9X12a+e2FASXGBhTo2x2HnISl4Myhxs05zIkRER0m\n        Gj49vA9jp3rRVF+Oil3bUFlSCHlZMQYP7cW1c524d7EZnx8rw+n9KcSpEPRU+KKjfDX2VYRCkhwIOzuL\n        p411+Y2l29IwuL/66dhRImBITtJyLpSFQUgMsqVT8zixiRFB3tPhhOgw3L42iDMnOoiIAlRVVmLnzkLk\n        ZaehOE+MA3sKSIqV4Ux3JkZbN6C3OhCdO7zQTmajRx6Jg8otaK/Lxs1zrbhyTInzRypxokOGgxXrUJK0\n        HCGeFuCYEBGGEyjCypKLA62VuH7lELraqxEXFYHs7GwolQ3YXpiHrIw4ZKeFY3dZNLrl0eitX4euUiEa\n        C5eiIV+A1p1rcHh3AkY7ZThBstnIvq3o2R2DPYXLIYlxwRqPeeAYTagIGmqQFjLcK8flTzogr8qFpaUF\n        goKCIJPJUFNTjYICKTJSIpG5SYjaHBH2bvNDU4EnGnP4qNvKR4NMgJYd/uioCEd3TTjaSWGs37IM0lhn\n        BHpawpKjN27KYUyoiBQtLSa2JofhwvBuDPZUwl/oATbbEFxSSwICApCVlfVcTL4EqfHB2BThBlmyG3al\n        OKM2zQl1WXzUy1zRWLwCbSTwW3d5oS5XAFmCK8J9rODGMxx34LImUgQNlT5jhjZ25MbgVG8FeprysMjR\n        Ftra2kQM+3Ux1VXIlaYjNmIVwrzNkR5mhZJNPNRLXNFa5EFqyUrsK/PF3iIv5CctRlzIQqxysxhfyjOZ\n        cBEcYneWL1mI4z2ksKkKkBgthIEBE3p6emAwGNDX139NTDURI00XI3y1G9auMEPmRgfUSj2wr9QHBxUk\n        +CsDUZnjhZQoPkQ+3HG/FdyJFkFDORN7stbPHX2NaWhXJMDX0xkURUFXV1e9pe0HYqoqsSUlHhuDPRAd\n        7ICSDG/SLAbjiHIDOuXrsEvig5i1Lk9C/e3fhQgaqtyEbYSmio0kwyQgL2212mlaBGkaXwp5o5jqSkgl\n        YiTGCJEauwy1RaE41JBAUnA8SrMDYTHXGOT+72JhRekS+2qhtRkUxYFoK1+PCJErDFi6IN2v+rV6Vcib\n        xNAxky9JR0ZiKAq2hqJbSYogSbt5GSJYWOi/q/UIRTeAf4sNdiMiQqDIW4MFNqbqIKfj479FvLAXYnx8\n        fCAWi1FcVIisLYkoyo1HR50EZ4aqSEUvOaoZZKKhixL1HYek2AJScfcWBSBxnRvMTQ3VM0HPyJtEvLAX\n        x+fPnw8+nw+BwANJ4gi0Krfh2vkDuDS6D4pS6c+uZ94ClDexZ462piT3C6HI9YXvUhu1c/QT/zkhrxqL\n        pQ+2kRGiNwbhWP/H+PbBGO5eH8b6QCGsLSwmWgylorR0EC3ioTZbgKzoRZg/10jt2Jti41XT0qIwezZF\n        aowxvFauREpKLM4d78fNqyfx+A9f4M+PruIvj27gk+Pd5BWc/5OLs18IZUrsT7NmMkj74IIaiTviSEfK\n        0nvzLNBO09sZMyjMMTaGqTEHGanxqK3Kx9f3r+Kbhzfxx0e/xpf3LuP62FGcHO3CtTEi7MoQ+g/ugckc\n        Y/p6kWbwtwkVRQzuDhyyvnZBsdgJTlZs6Gi/PhP0k6e306dTsLeaj1UCd5KlstGv2o0714bwuy8v4MHd\n        87h6aQTHh7vQ2CiHTLqZJIAoRKwPRI5UDHlF7i03R7uH2toMO83gbwv6gwB1iRZCd6NVmXz6iwes57Fe\n        Cpg58/kssPSN4OriiMykKLQpt+PW1SP4jATyZxe7cOlYK/oP1KJRUUD6r83q+AhZ64fFzo5wcbF/amdn\n        1WhuPreBHtFHwGerh367qGvHp1YkHorj+diT70naDCswScqlRdCvD9/JESI/T7QoS3CorRTXT7URx1sw\n        crga3U1FqCtPR1ZqGGKjhPDzdoWnhzNsba3GFy60G+JwWAHE1CvECYYq+OgjClxzQxLkvqgrWIsgoRv0\n        dJkIC/UnPVQsTvbW4cRAPU73KzDaXYruBikqC+MgSQrE+iB3+C5fBFdnG9jbm8PYmAV7a7NkEtAWmgHe\n        HSym7tDmdY5oLgmESiGGbHMYWuRkIdSjwPnBBhzdvwNt9VJUF8Via6I/qfZL4Oe5AK4OZrC1MiHBzn6i\n        r697e/ZsnTTyUJI1t33XUAxit9LX8dCQ600WQdFQKdPR25yHrgYJasiTzxIHIDJ4CRa7WYPvMI/MHhtz\n        TRl/1WHofEX6L9J2qBvN9/+vgvWrLAdyY+xQnOii/pohTfBC2kZfhIsWk9fGAc52prA204ORPhMm+tQB\n        4rSKof5kQ8fXBwJFTctf5miEOD8u/ARsrOCbkNUbB4vs54BrYQAzjt5vZ5GAZ+tSpIhRMZrLPjxWLWJv\n        FAk44Nvpwsacgjmb+rehAQVjI4aKOH7JwIBikq295vQPExZFudrO1YOrvQHmsBiPdWZTv2dS1AbieObz\n        M6iZz7eTAG1qej/bQKuJOG1IzEqze4oppphiiin+h5g27T/8sSq1mpXgwAAAAABJRU5ErkJggg==\n</value>\n  </data>\n  <data name=\"boatWest.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAASbSURBVGhD7Vgr\n        kKtYEI2MRGKRSCQWiUReeyUSiUUir8QikUgsEhkZGxn5ZO85DeQzmc3OvDe1m2zRVV13mEngnD79Y3ab\n        bbbZZpttttlmm+2yLJX9fi/L5fsZCZxPB/l1Ponv++9ChBGf3YDANHZyPIxyPE5yApk3IHIlYE0m49Aq\n        iXHoZOhbeIfrQYIgeFUitwokMnQ1wDcyjq2S6TondVVKBW/bRooifzUiVwJZGkvfFvBKiQy9gzdSljnI\n        ZSBRSVWWSqiHMssN/ku7gqebNJLWWelcLl0Db0ucpeQ2Qwr5Wg/GGHHOgVQhJdToO6gEZeIoWu7zr9o9\n        AZtF0lSZNHUmbW1wAmxlVBnf97TF0lkP1tqZSFFInhuQqOUw9WgAPU7UEdKQKrZNAcUsPpfh/omkSSRJ\n        HKrHUSBh6MN5BuJ5K5Yv2z0Bk4biygSeXrwqUn2Y510J8Gc6iVCRuq61NqhU60qAd3IYGz2nHjV18UrG\n        jul5dV6vf+c1FY9AZgH4T3ZPIEsCqYv4xhPJTayRWsHfElivPxKxBuRrKwPqaexKPel9i5RDan70rmHa\n        GqieadACqL0A/KrNQCwUqPNIqhu3WSgh8n8FS/9IYPVHIonUZQZwFkCRZo6puXoqbZUiZan4HDA+rzCh\n        +JpK37a95ADLqM/pg4fjhiYNNCK3QP+OwOp3RHKLDkaAAHwDvAVwgm+YsjfgbRb8HoH9ficGKVRaqhBr\n        MbdIA0bRfwL2md8SyUEkg8Il7s3gKHBEnmejSsxB4/N/i4CHB6axr04iOSJRKRHkpitQB+GnIL/id0Ss\n        0WfkiDYVdkUEdXACPDufQ8diy15gfd+oRBigw/h7nHsA97Q7sRt1aIkjBlvb1JKmCR4yF/9noD/zWyJc\n        W5IIRBgoVR1ESAhEWDPsZmytC6w/sb1KOhPy0KkipAHSC6ro2gFCPWYAF0GC/AqhZ4pQjasi6GRorZwp\n        PVaanyO0kGF7ZYFWxZxm/bJHcf0gMBb6M0L3NcKBiRqxrBHWxnxqvaAeuR3o3MB6swbthwn5D4SoEKM3\n        YSmssE8Fupp/TibDrkUic9dCC0fKsrDZtbRbXZy/Q0vG/Biwsykhnfo/qRBSjgpFD4QwmbHlcuVwyPEo\n        DB8IhfhdiYWRRK5zBN9HC1471WXQosnwpFLtqtJCisH7YUIfFMLKwFQ4THyBGpB+jSRJfEcoTVMMRAsy\n        3M84ra3uaRVmVYFUy02kzmFLZ7PhMOY8Ky07HIjh8/O0L76zojyzOeUiLHEXQiXAIXJMNZI5nyZ9iTLo\n        VCsZEnHVDITpQ2VyrDmsmxRtP4kDiXHPKGQH9fQZDNzlXH7m3zgyiGMB9KfGGyPdEB3OGr5U1QDKrnOY\n        Bn2t/XU+gtikhc5a4t8GLH/zzJgbxXKzV7CFENSJsQVzMaxrLIR4vT3gXf2Ed3UqdDqOWktUbfniq9pM\n        iOrEMfIdK3tdV1ozVOh8IqlRlVm+8PrGN0OSSeJY68S5SklQmRCzZfnY+5gqBEJcb7rWKZk3+r/Wo3ED\n        YNdijbw1kdUSqMNWvFxuttlmm2222Wab/X9tt/sLv/AP4ZlSTOUAAAAASUVORK5CYII=\n</value>\n  </data>\n  <data name=\"boatNorthwest.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAm+SURBVGhD7Zh7\n        UFTXHceJGr0LCyywyCIILk9BHi4ruogosIvCLgiCCPKU5SEPZRdYWEBReT8WZBWIgCAIisgb3xjFR9SY\n        mKjtOEmTNG2aP9qxJe20mck0nWa+PbveNNVo25mWjczwnfnOfZ177vnsOed3zm/15jWvec1rXq+tWBTl\n        RZ/OXelTC4Yclxlh02r2TorSK3p2l2LQRyWxIfHCZ9evsdgmi1u9nE0g9uFgvZsZtm+yHSYN/4DFNBx7\n        4w0K5Pwd4pvEscSW9GuvoyjTpSzGU56TIRKDuCiId0LWNhfs3uYGrrUp7JaZaWC+9++I+4gDiAV0Ba+L\n        KDuDJdSvHawpBPmwUZriieaCALSVSVCfJ0RpEg9b1i2HtysHby5igFpsoAH6jvgrYh9iMvReEzEpaoc1\n        m/r7Bp4F8pMF6KqKQ59KikblVhwp8kNNDg+lqZ6QJ3giTuwCN0dLcNimGqA/EX9CXEnsQcyhq/ypROWY\n        mlDgu3AgT/ZHnzoLit2RCBXxsXWDHfLjXFAqdUedzJv0kg9aSkVQpvoiIYyPVfZWsGBrh983xA+Js4jT\n        6Yp1L3MzRt9q56XI3CnEQFshjjUoYWTIBFNfH/bLWXC3YyMx1BG5cauhKhDiaEkIOirDoSqVoLVqJ7YG\n        ecN37SosXKiPxYuZGrAR4nG6el2JWkR8k2tjgijxGvQ0yzDRr0JkRDAoitLaQJ8BlpEBVpDJLxQ4IGUb\n        H6rCLQRmO/oPJ2OwJRPn+/NxoCAee9MiYWfL1VrnMCYmFNOKY/RLoa8r6ooTcW2kGfKsBPILPwN50daW\n        pljpYIlosRcKMzejU5WM0T4lLg1U4fr4YYwPNOBkezWS4yIRFynWwkRGipdrPza7opzfJI32cLJErjQE\n        oycO4OJAI3jubli06AcABoMBY2Nj7VGfDDsTlqH2WujngZQ4EfpbCzHSX41bb3fh3u3T+PDuCC6PH8eN\n        qdM/S0+L/9uTD6c3E6Ct9EdnR2xDKsbeyggxYWvR0STHheEmiIP8sGTJ871hYGCgtZGRkfZoaGiovW9i\n        wsRqN0cEi9ahoaYAPZ21uHKhC9OXBvD4vSl89ov7+PPTz7+TpsRr3lPTn50NUfFmxkys4dujtiQBl4dU\n        OKYuA8vYjEzg52G+t6ZnmEymFkYDpuklNgnNtrY2SIyNRtUhJVqbKnF5YgAfP7mHyxeHYcflat6JoT86\n        O7Iwpk7yXJdjb0owJnvLcbqjHF6ebi+FeNEaKDabDS5paGhoKPLy8lBTXU1g9qGnuxV9XW1wcLAHh8OZ\n        XYhnovq41mwyideit1mOe5c6kJMaiwULqB8NsRetmSsaiJCQECgUCqjVzTh4sBjVZcU41qpCRsYuuLis\n        1AWEnh6DQQmWWTL+GOS3EtUket08dwwd6v1wtlvx0sZ/73+FyM3NRV1dLfYXF6IwLxMNFaU4NzGItrYm\n        3UA8E2VowDD4xMvVCrJUCSbO1OKDO2exycf7laH4ZRBKpRy52YkoLZRi5PRRjA/2fF1RqiB7Mx2KTMQK\n        RzsLbA/1Rm9rCd69dhJ1tXlYam7+nyFqa6AskiE7PQZ5mVE4eUSJu1e7MTXZjTXu7l8x9Vm6hKE8LM3Z\n        3wh9V6OxMgvv3ujBUN9hWJpznoteL0LUEogCeRYyksKQs0uEwxVxON+rwOMbbfj00TCa6vI0K30J/RFd\n        iLIwNjb80MvDAbkZkWSetOPh3TFkZyT9c8Jr1o/nIGqqyU5AioToTdgVzUd9vhi9DXG40puD985V4OH1\n        Vjy+1Yn3p9pJPqNDLVlikOnsbI2EWBGGTtbjVx9dR31NEQmvPwyvwMBAuieqsSc9CVGb+YgMsIYijY+j\n        +4Iw0LQNk+07cPlEOm6dLcWDCw24NdGEsb79uoMhaW6auTkLQQFeaFEp8fGja/jsyR34b9yohVixYgWk\n        Uql2TshlUuwMW0e2/FbIirTDoXQPtCr90FMuwkCtBIOHwzHZIcXUYAHunm/AcI8Sqkqp7mCc7a3S/NZ5\n        kMm7G3duTuDzTx8gPT0BLJYxeDySbJUUo0iWhZR4EeLCXJGz0xVlu1xQn+mOlnweWooF6D7gj/4qIfob\n        wjH6ViKm+vIJTAVJEzIgT5PoBoaswDaOjnYzcTtDcX68B7/98ue4en4IbDMz+PisQ+6eFGSnRCAjYT3K\n        sgNQL1+HJpkXGnN5aNzLQ3ORDzrLROiq3IzuQwSmJhij6nhM9ebh1kgFDspiECbi6wZm1SqnsfCtQWhp\n        acBHj2/hwZ2L0IClSqNRUpAE5d4I1JdE4Fh5GI6XB6K9hMAovNCs8EH7wS2kJ2JwvCoCHQSoTbEenYcC\n        cKZ5By4RmGsEJjdVjEAfl9mH4XBYIWs83KCQ78a96VE8/c37ODf0FtrV+9DVKEOvOhOnm5NxVr0Dp1QS\n        0tCNJBXegGMHgnGGJFyn1HsgS5Mgf5f3d1XZPBzc7YlGxVr01UeR0LwX0wRGtisYvnz72YUhIEGens7f\n        SqWxuDjZg99/eQdffDyNu2SRvDJWg5Hje0ljk9DdsA3d1RIcrxCigwyjrqooTHYr0NmYBycnm2+5XE5Q\n        +MZlF/xXL32aHeOA0lQP0oshONeZhjsTNUhPEJJ9GGd2YZyc7Fqit0twd3oIf/jyPh7dG8fNyeMYOVE2\n        WpgtRnmeBIdkgajO9ye5vD/aD/mjty4KF0h0enC1HS2NRS10VXocFmXl426WvXK50Tv5cS5P8pO8MahO\n        xO2JWiTsCCQw3NmDsbZe1pwvl+LB7TG8fb4X2yUiqMrl2g2gjY1xhc0yc8Rv9fwmPZaHotQ1aCwgk5z8\n        2hOkt26fU6N8X6amgfHaymgRoIXezqa25FhRnyeqi5V4k7Rh/19DRN4kQWPMHkxDVcEHQ6eOkNV8Bext\n        bF7YxVLCiGBngTiQO5MYvgqKZC807VmP/sPxuHa2mvRc7be5GTsC6MIvFZfDEh6t3L1xPW/lX5gGzPuk\n        zj30o/+fAn14bL6b06cWS83/bVIUtIEr2MS3mYkKtIM8wQNHin1xoUuB6VE1MpIjnpBesaCLvlK8/6LM\n        /yR9fYYTWdHF9OUrJXCxEPBdTGckfraQxXviVNU2TI81oLY85wsCspguNjfkymUJbDlGM5r/jMtSfUlk\n        KsD1YTVio4Lq6SJzR5YchoBjRs2E+9lAXRyK6WEVkmK3XKQfzy1xTCkBx4KaSQl1JBvHRIz3ln+9Wbh2\n        E/14bkkLw6JmNP/yN+2L1oThYvrR3BMBEXCWUjOlOWIcrUwZpG/PTVlzmILlbKOZVfbWICF2I317bsqE\n        QQneXEDNkMVuboM8E+VIn8xrXj+99PT+ASrXKrXzqbQeAAAAAElFTkSuQmCC\n</value>\n  </data>\n  <data name=\"boatAnchor.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAACwAAAA6CAYAAADLC7uHAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAATuSURBVGhDzZkh\n        l6tIEIVHRkZikUgktiUSiUUikdiRkZGxI0eOfPb9lZX7E3rv1z2VIaTm7Z6zIYO4J6SA5Etxq7ogLzHG\n        f1Woy4i6UOmtf8yz5AaXapsy9k0V38Y2/n3pYlv/LLQbRMXxEPtQx/fXPmX3bcqwprosdJh/7pZygwig\n        35chNlUZawloQP+amwzd1DrMP3dLuUEEcBDo8XgUdJ2yPQ9tvMgaJ70CHH4A2g1WxTG+zW2CRZXgS71+\n        DHX8PTXxVcCHw2FfwKcxJNhQN3Hse2W00a4o8CIOXZ9eQ70T4FIFhyUMeOi62C2A67KKo2IGbFeC7a11\n        FzjqUnPpl8DTMKgHZ4vgZ+CbDJtiVZm9/gzou0ChL/2Qfy9DI9gqQbRNiK/TGKd+iEMbkqfJrsGWRZH2\n        8ePWn/do3QVK+Xeoi3jpBawuQXERayps0MYhNOoYTayKDIr6EBIsx64/79G6C1BwB4WBJJNYxC43QHgX\n        QMvs2LaC10KiH7T+rC10FwB01HI8t+q7UiUog24EOQ1jKkKAyXQnPQsWuUF67qRB52MK8X1qU7a/gAdl\n        VUUnu/TK7jNhkRtEdAnUVHSLnGF+SCc7kFmW62fDIjeIKLhBWT6H3LKSNQBWS5t6LLGz4ccEJJlMXUIr\n        XhAw3YIfsD72GXKDJsss3YBCS8BqX51miN0B38CqyIClMwAclO1dAa9hKTJWtlrAo/xLd/CAOQ+t44/U\n        XYAvZHkGlpm3FShjJDGENVg4vA7BuZy3JfTNG76oZrgJnfqtRkqyqve2z7yMhylCO8+Uj2EFzEv6ev8j\n        dPOGL6w0OjKRzSPDzNe8m2G0oDC5CZjtl5dbKAOe5XeO2aJP3wX4UtM6Dox1ioJLv8qiHcM9H773rsL/\n        lRv0tARmFqbouDHF1+tjOo2j+J8itX2Pkhv0dAWWh5mJAR21CvYakKzQvjKsYt0L8Kxi5A66kIfnrlIR\n        MhtnYPbbHQm3UevPeITcoCcDYo6gN5NhhqKu0V3J5/jJfuyAdgVMQdElelniNOZb/iXwVrDIDXpaAtPu\n        mNZaFR3AdAUynu2wQ2ArOuZlYNmHLb7s8PhiM7lBT2vgPNyT4expbAFs2BAWuUFPS+BeXaBX28IWAF9e\n        80PDVkv6ltlFN2/s0i5jphtgFV1aerGEWhzP2ujFW8Oi6wZADD0UDNsWX+6/WkKQ46ctOm2nJ5kqwPU5\n        W+i6kYG0emklA2wJzfYaeO5CssFlliUkzrXjt9R1AyCmq0HDOR3AoA2UlkXcbvPnvk1Phlj1zmPOtn3W\n        lrpu4F2AyTCQ1lcNFNEF0iwhD+fhvkrZxQ48MbLP2lLXDcswtz+tXjvBIFrYjT4fU1F4gwafX6dBNskr\n        n33WlrpuLDPMMLOE5UfwSIpbI7JKNxh5lNVroZAlLunp0JMtgQDh0rOdbWFPf6rkYzLL+14WmFR05+nz\n        ziId8wPA/0V4tRPwu7x7nnsVYftt795CbvBPojMw9FB0AHe1rsKT7IDc4HfCv2dNZ7/OU/IuLe1Z7czk\n        BtdigZh0Z5H+GVWBvasz9KFSO9tujPxObnApqp8/FD804KQ/F1VsaTn+AVjkBpdKbUuwb/LraaLlHX8M\n        FrnBtVgk6LtdoyX6yZ5dyw3uWW5wz3KDe5Yb3LPc4J7lBvcsN7hnucE9yw3uWW5wv4ov/wADTuEmApvE\n        QgAAAABJRU5ErkJggg==\n</value>\n  </data>\n  <data name=\"boatT2a.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAIAAAC0Ujn1AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAAgwSURBVEhLTVZp\n        c9pYFpVtkJAAiU2AWCS0IHYHvGH2Vey7DcZ27NhOnGScbifdPb1lUtUfZqmafz0HM9M1qlO3rlTo6HDf\n        fe9col83oprE0CRtIW1Wxs3aHQzjtFo9LOt1OHiO8zmdAY/H6eRY1sZxdo61OR2s4PfyHhdyj5vlPRyi\n        4Hf7fbzb5QgIvmDALwg+otuqimH/hpoyc3a7w2q1WyiOoT0c6+E4r9MR4D0hv2/L6HY7wehycuFQwOf1\n        ODi7l3cAYA8GeEkMetzOUNCPJBwOEo12NRiULBbaYqGsVoqhqRf5NF4DBQAKAAleg1hEQBJDkIbnkBUO\n        +bZQlTBu9WgkqkU0TSWa7aYkqiRJWSwkTZvBa7cx4AXwJpSCFH8T8PJuAE8QI1JYjoiKLMV0+U8kE9F4\n        TMm+SmbSsWQySUwmi+OjAsc5zGaT1UaB18pYXoroBAVrt26x/QaeI0c1Q0FBDAfliASNIAVjIq4m4npU\n        VdIp0Mbj8RjRbA46xuDVqyzL2i20CW9uhYMXwpFsqaEavCgUEiwXKo6ID8iRgCKHNFXcFEFRdS2aSaUR\n        FUUhOp1Ru91rtQ1d1zkHuGgLZWZt4HIxDG1lGEh1YD29PL5ts9mQBAOC4IdwvyKLEVFQIkFAlcOqoqZT\n        6Vw2p6maLMtEq93pdPuD4bg/GB2f5ENhwWqjUR+3y+d087xP4L0C53B5vH4762A5F279voDP5xfFoKKK\n        ybgqSwE1EtQ1SdOUbHZ/fz+NNdyons3PprMFMJnO20anVCmkM5l0JpvNHh/kCyfFSm80Lddb8fQrNZbU\n        4ik9kZEiUSEQkhVFlELRaEQUhYgcCoX8uq4eHubS6WQ0qm5Ug3G5Wq8vrwHklWaj0em2e+NGe9gbLybn\n        l8vru3Z/Uu8MS43OSbl+VKwdnFQyuRM9lfYGA6IUFgKCrEQAqE6lEoiyHMFFDEeTi/UVVKMsjZZRbjQ7\n        w8nk7Gq+vJ2ubq8e/rK4ehgvXzf781JrcFIxgIYxMQbzQrV5VCzuH+TUmL5pQ1XRde2FVwK1LCtEbzZt\n        GP3eaDaYLA7zxU5/NJ6vJmevlzcf2uPl+vb97PyqO5jOzy6mi9V4sS7Ueov1w9MPX8+v355d3p+UDTzJ\n        l41irXtarMjypszg17Qo0RtPxotVtdU9KlROy/XxZHH5+uH86u3N+8+rNx/704v+aHF5eTPojRaLVcMY\n        VpqD8+vHTz9+u7x7mizfdMeXwNnl4/2HH1eXt4nEvqZGk7FYNBolmpVWdzQr1duxdBax1e7Nz69Hi6vJ\n        xd3y9sP5+n66uLhYvz7IHeVyx+V652x9d/v4+edv//rr3/752x///vj89fbdl5u3n2/ePq+v72KxtBSW\n        4mgRVSUKR+XjUq3RGewf5l8dnfYGk+5gvnr9aEwuqp3p9ZuPy/VNrdZyOT3xRCaiJUfzq9nF/fvvf/3w\n        /Nvzz388ffn27umXH379+/2Hn4zuWNdTiqzEUHJFJfb3T6rtXjyTU2KpUq01W6yg2hhC7lNvfjlfvbm5\n        e290BixOU9YlhNXx4vrm3fPHz7//9PUfj9/9AtX/w+/lmgHV2C/Yi1hHwpM5iMb0eDKRTCcPjg5P0SWT\n        eWs0NdDmk1ljMFo/vFve3uMPHeRLp5XGcLa8e/zu7cfn1fU94vrN083j9w+fvkwvrw9LlWgyo8fTiqyL\n        UoRwSRmzmWFZTzAoZ/aPsqelYtOodvoVo1fvDbvTRanV6YxnlSZOmkmrNxrNl4Mp2D+B9+r23fj81hid\n        NQeTUsvI5fOpbE7XExFJkUBtt8q7uyxB2CwWTzSaLVSaaOyTYrXe7p+WG6DLl+ooVLM7RN4bz+tGvzta\n        VFv93vjMGMxa3Wl/fFZvd08rlePCKQoQ1TRd1SIRmaDM7p0dcm+P2d2lWY6Pp7InherxaaXVGTba/Xyx\n        Viw3esONajTo5OwCwmvtQbM7Xl7djRbrwXgxP1/XWq1Mdl8I+HDexrB3sBdR6z2zxWTeM1NmYmdnb3Nk\n        OxQ1fnhUKBRrmf3DWt3IHeSP8+XDfBmNjx14UqoeF+v5chPshWq7UKxmc0dCULDZGZeb1RRRk0Lx7W6k\n        zBRt3t2cpCRF7Jh3dyiTiWbtMJSgEJa9gsj7ww63n4Yb2zgn7w9F1LCsiUo0IMq8P2i3WynKTNMUfBnm\n        AC+I4thGg0gyAS+0UiaahnaS2DHtECTq8yd2d6k9E72zY6YstJnEb6gtLLSVZmyUhbFaLbB5n48XRRiC\n        DKPZOA1Ug5o0kTaaZF6od/ZQdMCMaDJRBLFrMpGk2UKSFuv/XfaXCwmDscLJYS6IRET1hTeVjEM1jE0B\n        td2Kv2SC58J49yiGerksFgteYyiLjWbsjNXtcPKwXY9L8HoCfl7w8XB2v9eN6PV6JCmM3YdjL5mIAZtq\n        bKlhTzS5h3qBj2KsCDYbA1CkycnaAZfdHuB5AWaIMQF2jiEGpB5ngHeHfB5IBjXOfiAeg6OjHBEcsQr6\n        GuYEtyWpXWCjmzRhFIHDwnCdLg7zkOBxS4KAASoEhSzrd7mQI+JWDYfhvBgcUAQUGtiQvgB2TKiaDqUU\n        RcKuSdK0pd6yc052M8T4/crGnnwyphqeD/t8QS+/Gal8XikQwNADmQB4/6tXlvCxiBQgGs02+hvLQqOD\n        UGWMZyBlbZtJgbVhNNhQh0NQh2EMt9v5BIwA5gUApBh3wIveQEFiOtwA3wgRMPL57Pwgd+xx+0wmzGfk\n        dqBxgN3FORz2kM+nhMOoKeqBNXA4WHQFcjScGwvr94IXMredl04lsJKb7tak/wCwwKk7K8PkFAAAAABJ\n        RU5ErkJggg==\n</value>\n  </data>\n  <data name=\"boatStop.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6\n        JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJ\n        TUUH4gcMAzMSajrZoAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGvSURBVFhH\n        zZc9bsJAFIRdRPgIVPRpUsMVaDlHDkBDTU2D3HGVIOUKERJlThCFA5j5knESZwmxwc7LSCN5Z9+bXe+v\n        nTVFWZa5OBULcSvuxYPJMxp1xOROux4yG4pr8VXciUtxJk7EkTm2Rh0xxJIztE17KHkgLsQXcSPeuupX\n        EOsccvEYuKoZlMBbP4oP4p3l1iDXHng1Gw0nPYsr8cbyxcDDXniefxkF8OYE3lvqDHja+/RIqII5Z6hW\n        ljoH3m4jXRMSWSzM19XD/hPwdhsLS++QwNCzYpM5ksZ2m1/IiW0+II01RlufU6ECe3bjYg3SMXoSOWTa\n        kJy5bWqQzhZdVwVOOA6Ok/tcOh0oXGwMcsh1sQbaEmkzp8DRuXNdAtV13gFAm+K0ClxaT4AJMS42hn3P\n        dYBju+CBS2RmPQEmb4EtQQ65LiagTXHLAzfZ2HoCTMQ+OsDu2vPAdTqyngATsY8OcIse/kUHwqcgfBES\n        GLoNww+i2KPYQtxlBFSIvY6BhLgPEiAx9pMMqCLuo7SCAuI+yysoMO7HpIIS4n7NvkLJjMbf/5x+h8x6\n        +D3PsiMj33ZRDLqMiwAAAABJRU5ErkJggg==\n</value>\n  </data>\n  <data name=\"boatTurnRight.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        /9j/4AAQSkZJRgABAQEAYABgAAD/4QBoRXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAAB\n        AAAARgEoAAMAAAABAAIAAAExAAIAAAARAAAATgAAAAAAAABgAAAAAQAAAGAAAAABcGFpbnQubmV0IDQu\n        MC4xNwAA/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n        AQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n        AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgAFgAeAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAA\n        AAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGh\n        CCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0\n        dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh\n        4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIB\n        AgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka\n        JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZ\n        mqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwD\n        AQACEQMRAD8A83/bl/aS+HfwC8IafaeCG/Zpi1XwR+zJ4J+LmtSfEnw98dfEniXx34y+KvxK8caN4s8B\n        aLB8Ofixong3R73w5FouiqZ9W0Wxs5Q4+yXMwjlMf4uW/wDwWe+KEHkyRfCr9jy1kCRS+ZbeEv2vY/s8\n        U2MSZf8AaNHyJ/y3YfLbHi4MJr3X/goV+zba6p+0J8JvhG/xI0LQrz4+/Av4DfEjWdZ1jxCJk+Htp4s+\n        J3xX8Q+NDe26QSS/YvB+j6Bql5cWsUckv7iO3toprq8sYLj6X+D3/BWT/gnJ+wT/AGT8KP2V/wBnnX9e\n        0fRJ3t9d+O8ui6HB8S/HuuMoTVPGOs+INR1Cy8Vac2sxqFtNA0+7NhZKoWVYQAB+eZVkWSzyyvicVHAz\n        xNdxlUi43XT4VJyavfRNyTunZnv4vF4unX+qUZc2G0993c7bfEmlv/d1Pnb9oz9uX9rz9nDRPhT4u8f/\n        ALNv7IL+G/2gvg78PPjD8LPGmn+Gf2tG0Dxxoninwboviyy0/S9Wuv2lUsY/Gfhe3ubXwtc6Xfy2mrST\n        6FFLHaTQ6hp8959AaP8AHPVtb1n4W3+g6vodnJ8TP2XfhN8bfGUNpBr17YaF448cxSSat4X0ePXfE2uT\n        22maeEJWNWQB8YYjiuK/4LBf8FU/Afxw+Emh/A3wN4N8PeM9O+I3gnwd8QNT13xFpGnX974Lh8SaNpfi\n        HQ9T0KGG3s9S0XxvDoniKwtW0bRfEWnaPpxv7q1vkguIvEtvr/hPwy+HEfgW9+BSWXiKz1SLxx+xL8Cf\n        iDcyR3aXQ0e712KQnw+TG8nlNZKDmHjyzwwUkA9Ussy/BV8LWwccBGdZS524NRV4X5Uqbi/NXcre9ZJM\n        wVapWwydeclqtE7dV62/XTserftcfB/WvGvxHj8SXE/grW9SmivfDQj8b+FdN8WfZLCE622r6LY6nrmm\n        6rf2+g3BvdRNjbJte2N5IQqFia+NF/Z1vIbGCY+HfgQsc9t9pdYvhL4R3l+n3m8Mf16UUVvRwtCNBRjT\n        5Y3WkZSS3h0UvN/0kd1OMZUlKUU33av1Xc3F/ZW1aXVYdLfRPgIbuWXRYpLxvhZ4bk2v4ltrC9sUhD+G\n        CUtdJs7i1sYYQAqx2iBF2gV9D/Cz4M+Ko/FOqSeI/Ftm8mkeFdE8NaJbaHZvb2OmeHtPdTp2mwRzIjLD\n        aKCsaKAqg8Ciiu6ng8NOtgFOlGXuTtdydvcvprp8vTY83G+7hY201v8A+TRP/9k=\n</value>\n  </data>\n  <data name=\"boatTurnLeft.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        /9j/4AAQSkZJRgABAQEAYABgAAD/4QBoRXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAAB\n        AAAARgEoAAMAAAABAAIAAAExAAIAAAARAAAATgAAAAAAAABgAAAAAQAAAGAAAAABcGFpbnQubmV0IDQu\n        MC4xNwAA/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n        AQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB\n        AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgAFgAeAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAA\n        AAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGh\n        CCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0\n        dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh\n        4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIB\n        AgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka\n        JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZ\n        mqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwD\n        AQACEQMRAD8A/Lv4u/theJfgt8EPE3xb03S/hx43+IH/AA1PD8C7jwn8QIviGPB7+AZPh5qniweK7mz8\n        G/E7wZNBMl9ZRQajcx3lisdsZHuPMtRNDJk3H7dv7W/h39l6H9srWv2ff2Q/CPwc8WfFvQfhJ4T8Qah4\n        S/a/sr34heIr/wAJePPEslx4Us5f2j1ur3w54XtfC2pWbXotk066vPFwtrGe8vbK6htPjP8Aal8G22j/\n        ALPmu/Gm6vtJ1e80v9uyy8HjwVqBe8s9TttN+FWteI4NT1DS7XUdNvZtLvXsV03UZra4jmis55yolkUW\n        8n7lfAX/AILtfC7wd+yRY+PPFXgcaD4l8Ga9oPwtk+G/gO20awtraa70LxA+jWmiafpdp4bsLLwpbad4\n        O1+I6xaAahJHbw6RqjrpmqaJolj8HDKcrxUMTisXDASq+1nTfuXjKLai7c/O1ZaLVxT5ny3PZnWrQpUY\n        UpycZSjF6vRNpXW2vnbsfj5pn/BYrx9qmsaNp+p/DT9jjSbK81vTbG71aTwT+1pdnSHuLqIrqMsV3+0J\n        e209tZPsnv0S3nnSGOWGAJqBt1H9BPgT4h/DPx58Ddb1TT3+Cup+Ovhh+0L4o+Fq6x8J9N+I2naB478H\n        ar8N/AHj+58WRaL8aPiD4t1jTY7DxXq99ouzy9LkkkYyQQSWkiyt+O/7Svx9/YA/4KoeCfEtv4d+GMX7\n        MH7Y2i+H9W1b4X+L7XR9D8PaT8Ul0mCbWp/hn4/Phd59Ge81mCyv38OeKNTeWc67PptrqF3aRzzTJ7T+\n        wd4DNx+zN4/+PXhfWbXxBfj9pS7+FK+FNP8AECS+Vpt38Evhb4zuNfmt3iUpLFeW9vpkryKskcs72zhZ\n        Y5kTjz7Jsqw1LC4vALALEKEYSjyvkUW47qMotvXfm6pW6HVl+JxOKnKhi5OFKn8EoXUnqrayc09F2V72\n        PlLxf8APF2s6n480SDXvCOs+FBr1x4yfQvGnh6HXbT+3bTR7nzL0WV3ZXthJNJpqz2SPNA7RecJEKOiO\n        vlDfsy6jDaX91/YPwHSLTrjSra9hj+FvhkrdnXPt13p9ysTeGPK+06f9ivLcyuA3kalcKhO4glFe+8Jh\n        4U8Uo0lFfWnpFyS0mlfSW/nv13ObDLmw1G6v70N/PlvpsNg/Z01WO80y7ttA+AqXwvG+x3P/AAqfwnG9\n        tPZRPdWtyCnhZtz208Mc0alSrvGEf5GJr9P/ANij4f8AiD4f+FLzTtBvtAtU1rzNdOj6RpzeFPDUUrxa\n        TZXuoyaZ4bhsoZ9buTb2MP2t7fC2Vv5W4fKtFFcmIwmHqU6cZ0lOKtpJya2g+r83/VjrrJQhFxXK3bVa\n        dj//2Q==\n</value>\n  </data>\n  <data name=\"boatTurnAround.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAAB4AAAA6CAYAAACnDemCAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAANPSURBVFhH7Zkh\n        cKNAFIYjkZFYJBKJRSKRa5FI5FrkSmQsEonEIpGRsZGVJ1//fxcuaS/XS9uEnc7cP/Mm0yTst/++tw+y\n        3f3Xj9A+CCQIdrL8uZ3yNJQ42m8LplOCozAAmLGRVBYJI44CCfebgQPRZSxVEUma7Ldw7QBVEYupUmkQ\n        Ko9tnkMLf5pYxYGYOpNDUyCUNHUuRZYsRfYUuHNbwmGrc+lMKV1bS3+oRVcFljx6lmsHNlUCcCalygCL\n        ZRoOdgKqSOE6fLRrBy1QxQ3AhIf7vV327mBk7A2WXDnXj63wxW3NgkpQUJGFMvI8e+f6Ybl2UFbvCo5C\n        55bBz4bOyLC4Th7n2g3OvBJcYiut0BWsilym8eG5RiUXLKjcbiMOeg1eY8Ryv8n19yrcOeKeJbhS6U0o\n        v1OVSuYr10n8LdfMbSIH48B0QtB+qejr4Hvz2MF1e+X6S3cu56Rr0SiM61DXkGsog99tdCXz1GGL6cV1\n        9BXX2Ld5Kn1bwbGSLHVFdQu6RhSGcpwHu70aXdoG80nXzsHQsSVW0qInr8CPwLymbTXgvfRdA9eZ3V6f\n        cM0tkgHcYABtnXPgj6BrJHEsp+No822aSlKs1J2u3cy5NRg98sULOeg9YF479AcLH1BopWJRxveBS1XY\n        hjAOLbZJYQe8B7pGlqXycp6x5KMYo+EavR35XwB/UwBoJxOqk00hWhrGZ8AcY55GOZ+PGKOTEpMnfAHc\n        FtvfPPUWrrE9ONMoiu6Ka7jCqv16OcnxOMF1g12R3s41v0yIg6IqkR9VFBhAYcalff1XFPh+jOJa4afj\n        LOfTbHPOiaxLzs8W7G5XwCnjhBlyeUyjpWkabI/WhjHmrtBa41bpmk1Vqd+5btvG3kKZsuz9sr8gJyfM\n        cBx6QAHGIFrj0aaupa6rS1QlBkWgP7MQ+UoI37dRu2AnO58mwCf72netfX/BXbSV4wX3Vs/O8YL5U5tX\n        9UWe9jEv8ta5GB56NeXl7kQtM9/+fkx5eQKhnAMPz1yUl6dMyjnx8FxNefklQTlHXn472cG3/7VIOcDG\n        v48pB/ZwIkAtrgHd8AyEcmAPpz6Uy+vG51yUc+3hZG/V5meZF3k6vYU/X+fVlJcTesrb/yR+oHa7V4q5\n        kiuq8MxFAAAAAElFTkSuQmCC\n</value>\n  </data>\n  <data name=\"boatBorder.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        iVBORw0KGgoAAAANSUhEUgAAA6YAAALECAYAAAAbyS0OAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO\n        wwAADsMBx2+oZAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xNzNun2MAAEjmSURBVHhe7d0v\n        l6vI2jfg81VGtmwZG4lEYpGRSGxkZGRsZGTLti23PHLs8zF46y4SOn1PZs6fhHme9a5rr3WtdFdTBChC\n        +O2C4h/jrp32QzsdxnY67rtq3DXT0G2rvp915eeu3SyvbdNMTdi+TefzoThOv34dp6+v4/T5sZ8ul6GU\n        7abTqS9l+1I2zmWnUnbsp315n6G87668V98383y7Mt+Yd319n/r4W1WmK9Peft8NZfnK72NZ5qEYx6bM\n        r6zDoSz/savv+/FxKO/7MX1+norL1HelXjH0pU7xX693XffNtNm81fX95z8v1/X+P7CO5T2a5n0R7xPv\n        F+8b6xLLMZT53uYTbXO5lPmUZf783Jd5neq6XM6n2qbN9jqPu/nc1PnVeW6nsczzUOZZl+tunh+XsbzH\n        vrzfUOcT8/tevnn9h917+fu2rMu8DB9lG57PQ6m3m46Hsg3H+21Y3jfe+7Ycddm287zL/MZhU5dnbpfY\n        Hw91npeyHDHP43FX1rsv2/KP7dKG63q23dwu0QbRJnO7zG0TdWrb1DZ50Dansg1i/f/tttn8ddtct8u/\n        0za3bVO3013bxDx/tE2ZZ93OS9tsfyzb0jbDrW3GpW0utW3Ktjzs/rptrr7bZl6euW3mdblv7/u22cW2\n        LtsrPj/juL1b57d/e52X/bF8TuIzuazzeV/eZ6x179c3XmOdd2V/rO95/Uzclu+2P/7cd77f/1XrvOyP\n        ZR63+cSydWWfHIa+Tv8//3Op84t53eYzb6tQ9snYP8sy1uWs+26Z73W/vd+fu3I8DE1Z77pdY5su2/GP\n        ++P3toz9cT7ex3H/D21T5xXbouzb5bXO71HbXPfHeZ7z/ng4DPUz/Ye2KZa2qce+ONZGndI21+1Y98c4\n        jtbt+LhtYtlinsOtbcp61GPF192xIvbvv2yba/vUZYt1ndsm2uD3389123xc9vVzUpfr2jZxrPjRNjHf\n        a9vM7ZPaJda7bsvZv2qX+N591C7xPR3f10u7XF/rNipu33nx/Xf7Lozvxfh+jO9J5wj/4XrXdXeOUOdX\n        5+kcwTnCg7a5+m6beXnmtnGO8GfrvOyPZR63+cSy/f90jvCPeYP8+YHz9sGKBY4FqhukaNq2ih02TiYO\n        x9iQ85dMLGQsbHwYY8WP1wNw3iBjKduXjXgofw9DbPz4EB/KF0LZYY7lYBFO96LBysa+hLLy55imfAj2\n        5UMQ9esGvjZe2EXDF7EhakOWRvx3vjD+bL3nnWF+nXfMeb3/L6zjGDtwMZT3jOlm8zLEzhr2++8Pzv0B\n        81jaLA5K87qMtU3rul7XOda/fsjKjnO/fvPP8wHiUNYpPujzgW0+UF0uh7Ls+7INY+e+tkE175TDuKn1\n        og2+yslh7NA/P0ixjLG88/vEe94+SEubXJcxTjZjftEu8UUTB4rbh/rWLvP8yra/bpNom7Fskz9tl7Ie\n        /7ptxnXbph48n2+bU/lCvLVNbO//qG3KF/hHWefzuaxvPViu3zanss7Hsk++dJ3LyUCcCEXbLOu7zDOW\n        c1O3+f/WOuf9MV7HeN/y92GM8n5e76rsY+V955Og8kVb9pNT2UfOZV0vIZa97KOn4tH+fIj9trjti/f7\n        4205lv2xuD+5un0JPXusmE/Q4lgRx995f/zrtmmu0x+u2zTC33ysqMs4lNfYJnW7lLa5fpn/bJtYrlkc\n        a27t++Pzd13u2j5lnWP+89/7eb4xzbV9aluVE4Jdee/6XXFrm+L7yztOSMt3S5zAXLd/OJb3PpSyED+H\n        fRzry3Z91C61bf6Ndonv47ld7r6ry7rHdojluz9xju+7+N6r32dl28a+f//9+N9+VzpHcI4wi59/fu6d\n        I7y4beJY6hxhXrZn19k5wrIv/2+dI/zjXx0448s0NnysQCxoHPyO5aCwPx6r+CLdlYXpdyVR1zeNg/Ss\n        fugiddcF+P4gxsrNO1XZQNEg140UH+D44t4f4wA71MasJxjXDTtv4PmL4LaB9mUDxDIvH9jrRqonJPG/\n        n/GhX5Zt/kDF63+83nEgLHVuDXYu5bGOm9v/Sv0fWMflxOdeee94z5soO5QPUOxQtw9LLG+sS9025YMX\n        bTmUE8DYWeu6R72qzCvWo6z7/ZfhuN/VZbl9Ocf/sNy2c8xrN27r9pu343VbVmWnLzvtMN5OoKKd5p12\n        3n/mA/Y+Dh4/tuP1w1Tn990uMa/xcD2I1v9B+m6X7xPEOIjftUupV7dLKPN62C7hb2ub2J7/um2W9Y96\n        1X/XNsN929yU3+O1ts3tf0tz25QDyn3bXD6ubVPe/75t6rKV8kdtMx+YUtuUg9mtbfaHckAr9V69zj/2\n        x3D383+yzuf/Yp0f7o91nWNfmOdX94VQyur8rq9jWa5Yty7+17bM53asql9cdR+M/fF6LCtiX7ztR4/2\n        5/gSidAV8z6W9anLUN/v+t71s1COFRHGYn8u6xHrEn7sj2U+p0v5Yquf7es2iHnV9ZnbJuZZ9+3x2ja1\n        XVLb9GW9yvY9xJdzaccqvuzj9/q5iM/lbpn+D8eK0j6xLeLk/vvzVpanfLF+z2ue71g+48M+/ld8PuGK\n        +dyO3bf2qScD5fNd51fqxjxjm8R8YrvUbV23dznhLMsV/1sd4SbmMW/n8n0Soo1KaJ1PNuL4UNoltud1\n        m9627a1tYnvG8WVeh2u7lP3h5hbGH7dLEetS9/Omtsf3d3Vp01I39q3YZ+P7Ld4jli/2pbq+Zb+J42N8\n        L87/WRDHSOcIzhEefO6dI8xtcvO3tU1sT+cI0TbOEebPye31/5dzhH/EDLbpwHmbcSxoXMpyc39Zz7Ar\n        X2jFGD+XaYdSNy6D2ZUG+n4tGyY2zu21GK9uvy+WaTeLXWzcKn4uSsOF/vpaxd/vf78rH0qdm+VEp4gN\n        83O95wPKn633TVzS8/CynvvlL/631vF+vj9d3/O2DPfLfGdXprkZ+k1dv3v7+JBc3cru121u8+951PW5\n        m1etd3Wbx7zvlG0e016nr3VurvMf46SzuF+GmzrPZXlu+978vsvyxTySh2V1W1yX5X6b3pavmrf9j3a7\n        +/2v2+LO7T3Tcv4Qy1Nf7+s9aJs7t7L7edy2a3Vb5q4sb1Gnv9uGt59vbdOXaW/merNl2Yq5fa7LcGuX\n        B/O6vf/9Nqj1r26/V7Utvtuyzu/qvv2X96rv81132R/vlz9+L+r0d/W+6xfl+NXf2vM6/c1tmevyxv5Y\n        6uTt/mNedX53da/1/8y8D8Z08Xr7+c8tbVl974M/f5/L7vfL+vd4rb9/v/8f3dbjtj2zUr/8La97lbbv\n        X87nfnliumX6b3GJbny39OULr3o0n/Bjuf/oNp86rzJ9zOvhfP6FZTn+G028lu+eJvbL7/Lvtvtuqy6C\n        3N8sThziZKueLJXt5RzBOUK4fUbnz6lzhLAsx235qnnb/2i3u9//ui3u3N4zLecPsTz19b6ec4T79l/e\n        q77Pd91lf7xf/vi9qNPf1fuuX9TvoWt7Xqe/uS1zXV7nCEWpX/6W171K2/c2n3/crvuN/5mI/yUr//4B\n        AAAAa8gZNP5jtBbOXcjzJVS5EgAAALxKzqB/CKZxjXuuBAAAAK+SM2gKppt6X0muBAAAAK+SM+gcTDdv\n        tSBGYdq7xxQAAIAV5Qy6BNN4LlcMiR43oOZKAAAA8Co5gy7B9Pbg6BgaPVcCAACAV8kZdAmmH/EQWj2m\n        AAAArCxn0O9LeUvB8djXUZFyJQAAAHiVnEGXYHo67abDoasPOM2VAAAA4FVyBl2CaSTVcWj1mAIAALCq\n        nEHbxqW8AAAA/I1yBnUpLwAAAH+rnEFdygsAAMDfKmfQ+VLe7dt02HfTsGv0mAIAALCqnEHnHtNSGEl1\n        HNtpKK+5EgAAALxKzqA1mLalcFeS6jA00/7QlekeVwYAAIBn5Qy6BNPoPo0/xHW+uRIAAAC8Ss6gy+BH\n        URhdqDEyUq4EAAAAr5Iz6I9gGtf3ns5Dme5xZQAAAHhWzqDfl/J217QqmAIAALCinEHnHtNS2HWbklib\n        6ehSXgAAAFaUM2gNpl3zXh9q2vXb6XAUTAEAAFhPzqA1mPZtKWw3c6EeUwAAAFaUM+h8j2lJq20UlsQq\n        mAIAALCmnEGXwY9qYUmrx5PBjwAAAFhPzqBLMN1u3+dCo/ICAACwopxBl0t5v7720/HY11GRciUAAAB4\n        lZxBl2D669exFjbl51wJAAAAXiVn0OulvHNa3e+7evNprgQAAACvkjPo0mP6+TlO49hOfS+YAgAAsJ6c\n        QWswbUpavVyGaRiaabdzjykAAADryRl0Cabn864WGPwIAACANeUMutxjejrNoyHpMQUAAGBNOYMuPaYx\n        GlIUDGNbpntcGQAAAJ6VM+jSY7rft/X63hgVKVcCAACAV8kZdAmmUTCWPxwOfZnucWUAAAB4Vs6gSzCN\n        LtQoOB53ZbrHlQEAAOBZOYMuwTRuOo1rfI8nwRQAAID15Ay6DH7UddvpIJgCAACwspxB52DaROFmGved\n        YAoAAMCqcgadL+UthW27qcP0RmLNlQAAAOBVcgb9EUwjrRqVFwAAgDXlDLpcyhvGUiCYAgAAsKacQX8E\n        030UupQXAACAFeUM+iOYHo47wRQAAIBV5Qxag2nfberDTSOthlwJAAAAXiVn0BpMx7Gdfv/9c2raTSnY\n        lOkeVwYAAIBn5Qw6B9OhmX79OtVRkXb9tkz3uDIAAAA8K2fQGkyHXTN9fu6nrhTEz7kSAAAAvErOoDWY\n        RkK9nIep75t6nW+uBAAAAK+SM+gSTI/HfupLgR5TAAAA1pQzaA2mMSLSft9N/VAKh7ZM97gyAAAAPCtn\n        0Ltg2k5j+cNQ/pArAQAAwKvkDFqDaQzPG8P1ns6DHlMAAABWlTNoDaZt815/OV8EUwAAANaVM2gNpk0p\n        jLR6/hhLoUt5AQAAWE/OoHMw3b7XG0/PH3uPiwEAAGBVOYNeg+lbTauXz/3U99sy3ePKAAAA8KycQedg\n        unmrKTW6UbtOMAUAAGA9OYMuwTQebHq8jHpMAQAAWFXOoDWYbt5/m4axm47noaRWwRQAAID15Axag2m7\n        fZu+vvb15tO+N/gRAAAA68kZtAbT7eZt+vXrOB0O3dS6xxQAAIAV5Qw6B9P3t+n3f16m02k3bbfvZbrH\n        lQEAAOBZOYNe7zGd02oUdjuX8gIAALCenEFrMH1/+23abkpK7Zvp9LEv0z2uDAAAAM/KGXTuMS2Fbbsp\n        hdvpdBnLdI8rAwAAwLNyBl3uMa2FnWAKAADAunIGXYJp181pNR5wmisBAADAq+QMeh386LeaVGvheSjT\n        Pa4MAAAAz8oZdBn8KArjwaZnPaYAAACsKGfQZfCjvhQOYztdjMoLAADAinIG/Q6m/XYa910p1GMKAADA\n        enIGXQY/qoUlrbqUFwAAgDXlDPojmA5DM50MfgQAAMCKcgZdgulu15TCdjoc+zLd48oAAADwrJxB52C6\n        eatdqCFuPs2VAAAA4FVyBq3BtCmFh0NXu1G7vinTPa4MAAAAz8oZtAbTdvs2nU67mlbjWTK5EgAAALxK\n        zqBLML2ch+l47Kd4wGmuBAAAAK+SM+hyKe/lMtTEqscUAACANeUMugTTz8+x/qFpNmW6x5UBAADgWTmD\n        1mAaQ/V+fe2nj49x2m7fy3SPKwMAAMCzcgZdgmkUhKbVYwoAAMB6cgZdLuXt++20G5rpcBrKdI8rAwAA\n        wLNyBl2CadO8T223nU6XsUz3uDIAAAA8K2fQH8E0RkM6nvWYAgAAsJ6cQed7TEthG9f19oIpAAAA68oZ\n        dAmmekwBAAD4O+QM6lJeAAAA/lYPL+WthVuDHwEAALC+nEGXYBpJdbeLoXp3ZbrHlQEAAOBZOYMuwfRy\n        3k2Xy1AfbporAQAAwKvkDDoPfvT+2/T5OU4fH+O03b6X6R5XBgAAgGflDHoNpm+lYJjOJbE2jR5TAAAA\n        1pMz6BxMr92op1Nfr/PNlQAAAOBVcgZd7jGNpHo4dFPfC6YAAACsJ2fQJZiejv00jq0eUwAAAFaVM+gc\n        TLdv02HfTcPQTJ0eUwAAAFaUM+gSTMehrWl1KK+5EgAAALxKzqA1mLalMB5sGml1f+jLdI8rAwAAwLNy\n        Bl2CadxwGoXH065M97gyAAAAPCtn0GXwo7mwnU7noUz3uDIAAAA8K2fQH8E0ru89XwRTAAAA1pMz6HIp\n        bwzRq8cUAACAteUMOveY1sJNSazuMQUAAGBdOYPWYNo177Uwnh9zOAqmAAAArCdn0BpM+7YUttdCPaYA\n        AACsKGfQ+R7TklbbKOwEUwAAANaVM+gy+FEt1GMKAADAynIGXYLpdvteh+s9GpUXAACAFeUMulzK+/W5\n        n46Hvo6KlCsBAADAq+QM+h1Mvw7T8dhPTfk5VwIAAIBXyRn0einvnFb3+7YO2ZsrAQAAwKvkDLr0mH58\n        jNM4tvUa31wJAAAAXiVn0KXH9HLZTcPQTLude0wBAABYT86gSzA9nfpaoMcUAACANeUMugTTuOk0CvSY\n        AgAAsKacQbvmGkwPh64WDENbpntcGQAAAJ6VM+jSYxo3nQ6lcL/vynSPKwMAAMCzcgZdgmkUxB/2JbXm\n        SgAAAPAqOYMuwTS6UCOpHg59me5xZQAAAHhWzqBLMI2bTqPgcBRMAQAAWE/OoDWYNqWw66JQjykAAADr\n        yhl0GZW36zb1+l7BFAAAgDXlDDoH06YUtptpNxj8CAAAgHXlDDrfY1oK21I4xIhIHhcDAADAinIG/Q6m\n        xVgKBFMAAADWlDNoe7uUtxFMAQAA+BvkDFrvMY2CptlM+0PvHlMAAABWlTNo7THtu019uGmk1XEUTAEA\n        AFhPzqD1HtNxaKZ//jrVm09jZKRcCQAAAF4lZ9AaTIeSVL++9rVw12/LdI8rAwAAwLNyBr0G0+30cRmm\n        rtsKpgAAAKwqZ9AaTOOH02k39eVVMAUAAGBNOYPOwbTbTIdDVwqbegNqrgQAAACvkjNoDaYxItJ+3059\n        KRBMAQAAWFPOoEswHce2iptQcyUAAAB4lZxBazCN4XmHoZ2Ox768CqYAAACsJ2fQGkzb5r3+cjrvBFMA\n        AABWlTNo12xvhW0pHFzKCwAAwKpyBm1vwTSu7T1dBoMfAQAAsKqcQWswbbZvNa2eL+PUd55jCgAAwHpy\n        Bl2CaQzTeyxptes2ZbrHlQEAAOBZOYO2TXMt7JvpcBrKqx5TAAAA1pMzaO0x3b6/TcPYlsLdtBNMAQAA\n        WFHOoHMw3bxNu6EUnvWYAgAAsK6cQed7TEthXN8badXgRwAAAKwpZ9DvwY/i+l49pgAAAKwsZ9AlmDbx\n        HJlDPx2KXAkAAABeJWfQGkzj4aZtu6k3n+73XZnucWUAAAB4Vs6gSzDtSmG9+fQgmAIAALCenEG/g2m3\n        mcYYrtelvAAAAKwoZ9DrPaZRuK1JVTAFAABgTTmDLj2mMRJSFByPgikAAADryRl0DqYlre52Tb3pVI8p\n        AAAAa8oZtN1ee0yHUjhf32vwIwAAANaTM+hyKW8UxB88LgYAAIA15Qy6XMobKTW6UoehLdM9rgwAAADP\n        yhl0CaZxw2ncfBp/yJUAAADgVXIGXYLp6dTXgr4XTAEAAFhPzqBLML1cdtMwNHpMAQAAWFXOoG3TlMLm\n        ffr4GOvNp9GVmisBAADAq+QMugTTr8/9tN+3U9dtynSPKwMAAMCzcgb9DqZfh3rzaVN+zpUAAADgVXIG\n        XZ5jGmn1eIhRkdxjCgAAwHpyBr0OfvQ2bbfv9dre43ko0z2uDAAAAM/KGXQJpm27mbooPO3KdI8rAwAA\n        wLNyBl0u5a2F3XY6CKYAAACsKGfQGkz79n3qrmlVMAUAAGBNOYPWYNqVtBpD9AqmAAAArC1n0Pq4mGb7\n        VgtjNKTjWTAFAABgPTmDzs8xrYXbaRja6XwxKi8AAADryRm0a6PHdPNWh+kdR8EUAACAdeUM+iOYRlo9\n        eY4pAAAAK8oZtAbT6EadCxvPMQUAAGBVOYN2t3tMd7umFh4OfZnucWUAAAB4Vs6g9XExMSLSOLT1+t7o\n        Ss2VAAAA4FVyBl2C6WHf1bQaz5HJlQAAAOBVcgadg+nmbTod+5pWY8jeXAkAAABeJWfQ7hZMz+fddDh0\n        9QbUXAkAAABeJWfQGky3pfBSCk+nXo8pAAAAq8oZdA6m72/Tx8dQE2vTbMp0jysDAADAs3IGrfeYbt9/\n        mz4/x/KHcdpu38t0jysDAADAs3IGXQY/im7Uy2WY2laPKQAAAOvJGXQJpnFdbzzg9HDalekeVwYAAIBn\n        5Qy6BNMmuk/LH06XsUz3uDIAAAA8K2fQ72DavNfEerwMZbrHlQEAAOBZOYPOgx/dF54FUwAAANaTM+gS\n        TOOG064XTAEAAFhXzqB/uJTXPaYAAACsKWfQH8HU4EcAAACsLWfQJZj2/XbaDTFUr0t5AQAAWE/OoPM9\n        pu9v08fHWMV1vrkSAAAAvErOoEsw/fra18Lt9r1M97gyAAAAPCtn0OVS3s/PcbpchqnRYwoAAMCKcgZd\n        gmkUnE67OipSrgQAAACvkjNoDabtthSeh+l47Ke+b8p0jysDAADAs3IG7dpmLoykOo6tHlMAAABWlTNo\n        DabRjXo4dNMwlKSqxxQAAIAV5Qxag+m2FEZSDUORKwEAAMCr5Aw6B9P3t2m3a0pabafDsS/TPa4MAAAA\n        z8oZtG2uwbTvt7Ub9XQeynSPKwMAAMCzcgato/LeCqMb9fIxlukeVwYAAIBn5Qxag+nm7be5cN9Nl899\n        me5xZQAAAHhWzqDfwbTb1ptOBVMAAADWlDNoDabvpTCeHRMPNj27lBcAAIAV5Qw695i+z4Vdv52OBj8C\n        AABgRTmDLoMfdd2mFp4uekwBAABYT86gSzBt21JYEqtgCgAAwJpyBl0GP6qFkVbdYwoAAMCKcgZdBj/a\n        bt5LYVMKjcoLAADAenIGvQ5+9Db9+nWcTqdd/UOuBAAAAK+SM2h3u8f0939eauF2+16me1wZAAAAnpUz\n        aNc2pXAzp9XDoZvablume1wZAAAAnpUzaA2m7fZt+vraT/t9Vx9wmisBAADAq+QMWi/ljYebDmNXH2y6\n        2+kxBQAAYD05g3ZtCabN5m3qd810vIwlrQqmAAAArCdn0DoqbxTuSuH5Y6wPOM2VAAAA4FVyBp2D6fZt\n        Gsd2unzu9ZgCAACwqpxBr8H0vd50ev7YT0NJrbkSAAAAvErOoHMwbd5rWo1u1HFoy3SPKwMAAMCzcgat\n        wbQthUP55XwZ6h9zJQAAAHiVnEFrMO3aTf3ldB6mQTAFAABgRTmD1mDad5tpv2+ncd/V1JorAQAAwKvk\n        DNp9B9Nu6odGMAUAAGBVOYPWHtNdv52Ox74+4NSovAAAAKwpZ9AlmF7Ow9T3gikAAADryhm0BtP44fNz\n        P3Xlj4IpAAAAa8oZdA6mQzP9+nWa2nYz7UpizZUAAADgVXIGrYMfxTC9v//+OTWlMIbtzZUAAADgVXIG\n        XR4Xs9s10/7QF12Z7nFlAAAAeFbOoDWYNs37FA7HXdGX6R5XBgAAgGflDFov5b0VRloVTAEAAFhTzqBd\n        03wXjlFY5EoAAADwKjmD1mDaloIYDWncd4IpAAAAq8oZtGvvgukwti7lBQAAYFU5g9ZgGl2oXTen1eNp\n        V6Z7XBkAAACelTNoW+8x3bzV63u7bjsdz0OZ7nFlAAAAeFbOoHOPaRRu36e2FJ4uY5nucWUAAAB4Vs6g\n        SzCNpBoPOD24lBcAAIAV5Qy6BNPLeTddLsPUtJsy3ePKAAAA8KycQWsw3b7/Nn1+jtPHxzhtt+9luseV\n        AQAA4Fk5g16D6VspGKZzSaxNo8cUAACA9eQMOgfTazfq6dTX63xzJQAAAHiVnEGXe0wjqR4O3dT3gikA\n        AADryRl0CaanYz+NY6vHFAAAgFXlDDoH0+3bdNh30zA0U6fHFAAAgBXlDLoE03Foa1odymuuBAAAAK+S\n        M2gNpm0pjAebRlrdH/oy3ePKAAAA8KycQZdgGjecRuHxtCvTPa4MAAAAz8oZdBn8aC5sp9N5KNM9rgwA\n        AADPyhn0RzCN63vPF8EUAACA9eQMulzKG0P06jEFAABgbTmDzj2mtXBTEqt7TAEAAFhXzqA1mHbNey2M\n        58ccjoIpAAAA68kZtAbTvi2F7bVQjykAAAAryhl0vse0pNU2CjvBFAAAgHXlDLoMflQL9ZgCAACwspxB\n        l2C63b7X4XqPRuUFAABgRTmDLpfyfn3up+Ohr6Mi5UoAAADwKjmDfgfTr8N0PPZTU37OlQAAAOBVcga9\n        Xso7p9X9vq1D9uZKAAAA8Co5gy49ph8f4zSObb3GN1cCAACAV8kZdOkxvVx20zA0027nHlMAAADWkzPo\n        EkxPp74W6DEFAABgTTmDLsE0bjqNAj2mAAAArCln0K65BtPDoasFw9CW6R5XBgAAgGflDLr0mMZNp0Mp\n        3O+7Mt3jygAAAPCsnEGXYBoF8Yd9Sa25EgAAALxKzqBLMI0u1Eiqh0NfpntcGQAAAJ6VM+gSTOOm0yg4\n        HAVTAAAA1pMzaA2mTSnsuijUYwoAAMC6cgZdRuXtuk29vlcwBQAAYE05g87BtCmF7WbaDQY/AgAAYF05\n        g873mJbCthQOMSKSx8UAAACwopxBv4NpMZYCwRQAAIA15Qza3i7lbQRTAAAA/gY5g9Z7TKOgaTbT/tC7\n        xxQAAIBV5Qxae0z7blMfbhppdRwFUwAAANaTM2i9x3Qcmumfv0715tMYGSlXAgAAgFfJGbQG06Ek1a+v\n        fS3c9dsy3ePKAAAA8KycQa/BdDt9XIap67aCKQAAAKvKGbQG0/jhdNpNfXkVTAEAAFhTzqBzMO020+HQ\n        lcKm3oCaKwEAAMCr5Axag2mMiLTft1NfCgRTAAAA1pQz6BJMx7Gt4ibUXAkAAABeJWfQGkxjeN5haKfj\n        sS+vgikAAADryRm0BtO2ea+/nM47wRQAAIBV5QzaNdtbYVsKB5fyAgAAsKqcQdtbMI1re0+XweBHAAAA\n        rCpn0BpMm+1bTavnyzj1neeYAgAAsJ6cQZdgGsP0Hkta7bpNme5xZQAAAHhWzqBt01wL+2Y6nIbyqscU\n        AACA9eQMWntMt+9v0zC2pXA37QRTAAAAVpQz6BxMN2/TbiiFZz2mAAAArCtn0Pke01IY1/dGWjX4EQAA\n        AGvKGfR78KO4vlePKQAAACvLGXQJpk08R+bQT4ciVwIAAIBXyRm0BtN4uGnbburNp/t9V6Z7XBkAAACe\n        lTPoEky7UlhvPj0IpgAAAKwnZ9DvYNptpjGG63UpLwAAACvKGfR6j2kUbmtSFUwBAABYU86gS49pjIQU\n        BcejYAoAAMB6cgadg2lJq7tdU2861WMKAADAmnIGbbfXHtOhFM7X9xr8CAAAgPXkDLpcyhsF8QePiwEA\n        AGBNOYMul/JGSo2u1GFoy3SPKwMAAMCzcgZdgmnccBo3n8YfciUAAAB4lZxBl2B6OvW1oO8FUwAAANaT\n        M+gSTC+X3TQMjR5TAAAAVpUzaNs0pbB5nz4+xnrzaXSl5koAAADwKjmDLsH063M/7fft1HWbMt3jygAA\n        APCsnEG/g+nXod582pSfcyUAAAB4lZxBl+eYRlo9HmJUJPeYAgAAsJ6cQa+DH71N2+17vbb3eB7KdI8r\n        AwAAwLNyBl2Cadtupi4KT7sy3ePKAAAA8KycQZdLeWtht50OgikAAAAryhm0BtO+fZ+6a1oVTAEAAFhT\n        zqA1mHYlrcYQvYIpAAAAa8sZtD4uptm+1cIYDel4FkwBAABYT86g83NMa+F2GoZ2Ol+MygsAAMB6cgbt\n        2ugx3bzVYXrHUTAFAABgXTmD/gimkVZPnmMKAADAinIGrcE0ulHnwsZzTAEAAFhVzqDd7R7T3a6phYdD\n        X6Z7XBkAAACelTNofVxMjIg0Dm29vje6UnMlAAAAeJWcQZdgeth3Na3Gc2RyJQAAAHiVnEHnYLp5m07H\n        vqbVGLI3VwIAAIBXyRm0uwXT83k3HQ5dvQE1VwIAAIBXyRm0BtNtKbyUwtOp12MKAADAqnIGnYPp+9v0\n        8THUxNo0mzLd48oAAADwrJxB6z2m2/ffps/PsfxhnLbb9zLd48oAAADwrJxBl8GPohv1chmmttVjCgAA\n        wHpyBl2CaVzXGw84PZx2ZbrHlQEAAOBZOYMuwbSJ7tPyh9NlLNM9rgwAAADPyhn0O5g27zWxHi9Dme5x\n        ZQAAAHhWzqDz4Ef3hWfBFAAAgPXkDLoE07jhtOsFUwAAANaVM+gfLuV1jykAAABryhn0RzA1+BEAAABr\n        yxl0CaZ9v512QwzV61JeAAAA1pMz6HyP6fvb9PExVnGdb64EAAAAr5Iz6BJMv772tXC7fS/TPa4MAAAA\n        z8oZdLmU9/NznC6XYWr0mAIAALCinEGXYBoFp9OujoqUKwEAAMCr5Axag2m7LYXnYToe+6nvmzLd48oA\n        AADwrJxBu7aZCyOpjmOrxxQAAIBV5Qxag2l0ox4O3TQMJanqMQUAAGBFOYPWYLothZFUw1DkSgAAAPAq\n        OYPOwfT9bdrtmpJW2+lw7Mt0jysDAADAs3IGbZtrMO37be1GPZ2HMt3jygAAAPCsnEHrqLy3wuhGvXyM\n        ZbrHlQEAAOBZOYPWYLp5+20u3HfT5XNfpntcGQAAAJ6VM+h3MO229aZTwRQAAIA15Qxag+l7KYxnx8SD\n        Tc8u5QUAAGBFOYPOPabvc2HXb6ejwY8AAABYUc6gy+BHXbephaeLHlMAAADWkzPoEkzbthSWxCqYAgAA\n        sKacQZfBj2phpFX3mAIAALCinEGXwY+2m/dS2JRCo/ICAACwnpxBr4MfvU2/fh2n02lX/5ArAQAAwKvk\n        DNrd7jH9/Z+XWrjdvpfpHlcGAACAZ+UM2rVNKdzMafVw6Ka225bpHlcGAACAZ+UMWoNpu32bvr72037f\n        1Qec5koAAADwKjmD1kt54+Gmw9jVB5vudnpMAQAAWE/OoF1bgmmzeZv6XTMdL2NJq4IpAAAA68kZtI7K\n        G4W7Unj+GOsDTnMlAAAAeJWcQedgun2bxrGdLp97PaYAAACsKmfQazB9rzednj/201BSa64EAAAAr5Iz\n        6BxMm/eaVqMbdRzaMt3jygAAAPCsnEFrMG1L4VB+OV+G+sdcCQAAAF4lZ9AaTLt2U385nYdpEEwBAABY\n        Uc6gNZj23Wba79tp3Hc1teZKAAAA8Co5g3bfwbSb+qERTAEAAFhVzqC1x3TXb6fjsa8PODUqLwAAAGvK\n        GXQJppfzMPW9YAoAAMC6cgatwTR++PzcT135o2AKAADAmnIGnYPp0Ey/fp2mtt1Mu5JYcyUAAAB4lZxB\n        6+BHMUzv779/Tk0pjGF7cyUAAAB4lZxBl8fF7HbNtD/0RVeme1wZAAAAnpUzaA2mTfM+hcNxV/RluseV\n        AQAA4Fk5g9ZLeW+FkVYFUwAAANaUM2jXNN+FYxQWuRIAAAC8Ss6gNZi2pSBGQxr3nWAKAADAqnIG7dq7\n        YDqMrUt5AQAAWFXOoDWYRhdq181p9XjalekeVwYAAIBn5Qza1ntMt281rfb9tqRVwRQAAID15Aw695iW\n        wjmxlkI9pgAAAKwoZ9A/BFOX8gIAALCmnEFTMN1Mx/NQpntcGQAAAJ6VM+gcTDdvtWC3a6a9e0wBAABY\n        Uc6gSzA9n3bT+byrN6DmSgAAAPAqOYMuwfTzY5wul2Habt/LdI8rAwAAwLNyBl2C6Ucp0GMKAADA2nIG\n        /b6UtxQcj30dFSlXAgAAgFfJGXQJpqfTbjocuvqA01wJAAAAXiVn0CWYRlIdh1aPKQAAAKvKGbRtXMoL\n        AADA3yhnUJfyAgAA8LfKGdSlvAAAAPytcgadL+Xdvk2HfTcNu0aPKQAAAKvKGXTuMS2FkVTHsZ2G8por\n        AQAAwKvkDFqDaVsKdyWpDkMz7Q9dme5xZQAAAHhWzqBLMI3u0/hDXOebKwEAAMCr5Ay6DH4UhdGFGiMj\n        5UoAAADwKjmD/gimcX3v6TyU6R5XBgAAgGflDPp9KW93TauCKQAAACvKGXTuMS2FXbcpibWZji7lBQAA\n        YEU5g9Zg2jXv9aGmXb+dDkfBFAAAgPXkDFqDad+WwnYzF+oxBQAAYEU5g873mJa02kZhSayCKQAAAGvK\n        GXQZ/KgWlrR6PBn8CAAAgPXkDLoE0+32fS40Ki8AAAAryhl0uZT362s/HY99HRUpVwIAAIBXyRl0Caa/\n        fh1rYVN+zpUAAADgVXIGvV7KO6fV/b6rN5/mSgAAAPAqOYMuPaafn+M0ju3U94IpAAAA68kZtAbTpqTV\n        y2WYhqGZdjv3mAIAALCenEGXYHo+72qBwY8AAABYU86gyz2mp9M8GpIeUwAAANaUM+jSYxqjIUXBMLZl\n        useVAQAA4Fk5gy49pvt9W6/vjVGRciUAAAB4lZxBl2AaBWP5w+HQl+keVwYAAIBn5Qy6BNPoQo2C43FX\n        pntcGQAAAJ6VM+gSTOOm07jG93gSTAEAAFhPzqDL4Eddt50OgikAAAAryxl0DqZNFG6mcd8JpgAAAKwq\n        Z9D5Ut5S2LabOkxvJNZcCQAAAF4lZ9AfwTTSqlF5AQAAWFPOoMulvGEsBYIpAAAAa8oZ9Ecw3UehS3kB\n        AABYUc6gP4Lp4bgTTAEAAFhVzqA1mPbdpj7cNNJqyJUAAADgVXIGrcF0HNvp998/p6bdlIJNme5xZQAA\n        AHhWzqBzMB2a6devUx0Vaddvy3SPKwMAAMCzcgatwXTYNdPn537qSkH8nCsBAADAq+QMWoNpJNTLeZj6\n        vqnX+eZKAAAA8Co5gy7B9Hjsp74U6DEFAABgTTmD1mAaIyLt993UD6VwaMt0jysDAADAs3IGvQum7TSW\n        PwzlD7kSAAAAvErOoDWYxvC8MVzv6TzoMQUAAGBVOYPWYNo27/WX80UwBQAAYF05g9Zg2pTCSKvnj7EU\n        upQXAACA9eQMOgfT7Xu98fT8sfe4GAAAAFaVM+g1mL7VtHr53E99vy3TPa4MAAAAz8oZdA6mm7eaUqMb\n        tesEUwAAANaTM+gSTOPBpsfLqMcUAACAVeUMWoPp5v23aRi76XgeSmoVTAEAAFhPzqA1mLbbt+nra19v\n        Pu17gx8BAACwnpxBazDdbt6mX7+O0+HQTa17TAEAAFhRzqBzMH1/m37/52U6nXbTdvtepntcGQAAAJ6V\n        M+j1HtM5rUZht3MpLwAAAOvJGbQG0/e336btpqTUvplOH/sy3ePKAAAA8KycQece01LYtptSuJ1Ol7FM\n        97gyAAAAPCtn0OUe01rYCaYAAACsK2fQJZh23ZxW4wGnuRIAAAC8Ss6g18GPfqtJtRaehzLd48oAAADw\n        rJxBl8GPojAebHrWYwoAAMCKcgZdBj/qS+EwttPFqLwAAACsKGfQ72Dab6dx35VCPaYAAACsJ2fQZfCj\n        WljSqkt5AQAAWFPOoD+C6TA008ngRwAAAKwoZ9AlmO52TSlsp8OxL9M9rgwAAADPyhl0Dqabt9qFGuLm\n        01wJAAAAXiVn0BpMm1J4OHS1G7XrmzLd48oAAADwrJxBazBtt2/T6bSraTWeJZMrAQAAwKvkDLoE08t5\n        mI7HfooHnOZKAAAA8Co5gy6X8l4uQ02sekwBAABYU86gSzD9/BzrH5pmU6Z7XBkAAACelTNoDaYxVO/X\n        1376+Bin7fa9TPe4MgAAADwrZ9AlmEZBaFo9pgAAAKwnZ9DlUt6+3067oZkOp6FM97gyAAAAPCtn0CWY\n        Ns371Hbb6XQZy3SPKwMAAMCzcgb9EUxjNKTjWY8pAAAA68kZdL7HtBS2cV1vL5gCAACwrpxBl2CqxxQA\n        AIC/Q86gLuUFAADgb/XwUt5auDX4EQAAAOvLGXQJppFUd7sYqndXpntcGQAAAJ6VM+gSTC/n3XS5DPXh\n        prkSAAAAvErOoPPgR++/TZ+f4/TxMU7b7XuZ7nFlAAAAeFbOoNdg+lYKhulcEmvT6DEFAABgPTmDzsH0\n        2o16OvX1Ot9cCQAAAF4lZ9DlHtNIqodDN/W9YAoAAMB6cgZdgunp2E/j2OoxBQAAYFU5g87BdPs2Hfbd\n        NAzN1OkxBQAAYEU5gy7BdBzamlaH8porAQAAwKvkDFqDaVsK48GmkVb3h75M97gyAAAAPCtn0CWYxg2n\n        UXg87cp0jysDAADAs3IGXQY/mgvb6XQeynSPKwMAAMCzcgb9EUzj+t7zRTAFAABgPTmDLpfyxhC9ekwB\n        AABYW86gc49pLdyUxOoeUwAAANaVM2gNpl3zXgvj+TGHo2AKAADAenIGrcG0b0they3UYwoAAMCKcgad\n        7zEtabWNwk4wBQAAYF05gy6DH9VCPaYAAACsLGfQJZhut+91uN6jUXkBAABYUc6gy6W8X5/76Xjo66hI\n        uRIAAAC8Ss6g38H06zAdj/3UlJ9zJQAAAHiVnEGvl/LOaXW/b+uQvbkSAAAAvErOoEuP6cfHOI1jW6/x\n        zZUAAADgVXIGXXpML5fdNAzNtNu5xxQAAID15Ay6BNPTqa8FekwBAABYU86gSzCNm06jQI8pAAAAa8oZ\n        tGuuwfRw6GrBMLRluseVAQAA4Fk5gy49pnHT6VAK9/uuTPe4MgAAADwrZ9AlmEZB/GFfUmuuBAAAAK+S\n        M+gSTKMLNZLq4dCX6R5XBgAAgGflDLoE07jpNAoOR8EUAACA9eQMWoNpUwq7Lgr1mAIAALCunEGXUXm7\n        blOv7xVMAQAAWFPOoHMwbUphu5l2g8GPAAAAWFfOoPM9pqWwLYVDjIjkcTEAAACsKGfQ72BajKVAMAUA\n        AGBNOYO2t0t5G8EUAACAv0HOoPUe0yhoms20P/TuMQUAAGBVOYPWHtO+29SHm0ZaHUfBFAAAgPXkDFrv\n        MR2HZvrnr1O9+TRGRsqVAAAA4FVyBq3BdChJ9etrXwt3/bZM97gyAAAAPCtn0Gsw3U4fl2Hquq1gCgAA\n        wKpyBq3BNH44nXZTX14FUwAAANaUM+gcTLvNdDh0pbCpN6DmSgAAAPAqOYPWYBojIu337dSXAsEUAACA\n        NeUMugTTcWyruAk1VwIAAIBXyRm0BtMYnncY2ul47MurYAoAAMB6cgatwbRt3usvp/NOMAUAAGBVOYN2\n        zfZW2JbCwaW8AAAArCpn0PYWTOPa3tNlMPgRAAAAq8oZtAbTZvtW0+r5Mk595zmmAAAArCdn0CWYxjC9\n        x5JWu25TpntcGQAAAJ6VM2jbNNfCvpkOp6G86jEFAABgPTmD1h7T7fvbNIxtKdxNO8EUAACAFeUMOgfT\n        zdu0G0rhWY8pAAAA68oZdL7HtBTG9b2RVg1+BAAAwJpyBv0e/Ciu79VjCgAAwMpyBl2CaRPPkTn006HI\n        lQAAAOBVcgatwTQebtq2m3rz6X7flekeVwYAAIBn5Qy6BNOuFNabTw+CKQAAAOvJGfQ7mHabaYzhel3K\n        CwAAwIpyBr3eYxqF25pUBVMAAADWlDPo0mMaIyFFwfEomAIAALCenEHnYFrS6m7X1JtO9ZgCAACwppxB\n        2+21x3QohfP1vQY/AgAAYD05gy6X8kZB/MHjYgAAAFhTzqDLpbyRUqMrdRjaMt3jygAAAPCsnEGXYBo3\n        nMbNp/GHXAkAAABeJWfQJZieTn0t6HvBFAAAgPXkDLoE08tlNw1Do8cUAACAVeUM2jZNKWzep4+Psd58\n        Gl2puRIAAAC8Ss6gSzD9+txP+307dd2mTPe4MgAAADwrZ9DvYPp1qDefNuXnXAkAAABeJWfQ5TmmkVaP\n        hxgVyT2mAAAArCdn0OvgR2/Tdvter+09nocy3ePKAAAA8KycQZdg2rabqYvC065M97gyAAAAPCtn0OVS\n        3lrYbaeDYAoAAMCKcgatwbRv36fumlYFUwAAANaUM2gNpl1JqzFEr2AKAADA2nIGrY+LabZvtTBGQzqe\n        BVMAAADWkzPo/BzTWridhqGdzhej8gIAALCenEG7NnpMN291mN5xFEwBAABYV86gP4JppNWT55gCAACw\n        opxBazCNbtS5sPEcUwAAAFaVM2h3u8d0t2tq4eHQl+keVwYAAIBn5QxaHxcTIyKNQ1uv742u1FwJAAAA\n        XiVn0CWYHvZdTavxHJlcCQAAAF4lZ9A5mG7eptOxr2k1huzNlQAAAOBVcgbtbsH0fN5Nh0NXb0DNlQAA\n        AOBVcgatwXRbCi+l8HTq9ZgCAACwqpxB52D6/jZ9fAw1sTbNpkz3uDIAAAA8K2fQeo/p9v236fNzLH8Y\n        p+32vUz3uDIAAAA8K2fQZfCj6Ea9XIapbfWYAgAAsJ6cQZdgGtf1xgNOD6ddme5xZQAAAHhWzqBLMG2i\n        +7T84XQZy3SPKwMAAMCzcgb9DqbNe02sx8tQpntcGQAAAJ6VM+g8+NF94VkwBQAAYD05gy7BNG447XrB\n        FAAAgHXlDPqHS3ndYwoAAMCacgb9EUwNfgQAAMDacgZdgmnfb6fdEEP1upQXAACA9eQMOt9j+v42fXyM\n        VVznmysBAADAq+QMugTTr699Ldxu38t0jysDAADAs3IGXS7l/fwcp8tlmBo9pgAAAKwoZ9AlmEbB6bSr\n        oyLlSgAAAPAqOYPWYNpuS+F5mI7Hfur7pkz3uDIAAAA8K2fQrm3mwkiq49jqMQUAAGBVOYPWYBrdqIdD\n        Nw1DSap6TAEAAFhRzqA1mG5LYSTVMBS5EgAAALxKzqBzMH1/m3a7pqTVdjoc+zLd48oAAADwrJxB2+Ya\n        TPt+W7tRT+ehTPe4MgAAADwrZ9A6Ku+tMLpRLx9jme5xZQAAAHhWzqA1mG7efpsL9910+dyX6R5XBgAA\n        gGflDPodTLttvelUMAUAAGBNOYPWYPpeCuPZMfFg07NLeQEAAFhRzqBzj+n7XNj12+lo8CMAAABWlDPo\n        MvhR121q4emixxQAAID15Ay6BNO2LYUlsQqmAAAArCln0GXwo1oYadU9pgAAAKwoZ9Bl8KPt5r0UNqXQ\n        qLwAAACsJ2fQ6+BHb9OvX8fpdNrVP+RKAAAA8Co5g3a3e0x//+elFm6372W6x5UBAADgWTmDdm1TCjdz\n        Wj0cuqnttmW6x5UBAADgWTmD1mDabt+mr6/9tN939QGnuRIAAAC8Ss6g9VLeeLjpMHb1waa7nR5TAAAA\n        1pMzaNeWYNps3qZ+10zHy1jSqmAKAADAenIGraPyRuGuFJ4/xvqA01wJAAAAXiVn0DmYbt+mcWyny+de\n        jykAAACryhn0Gkzf602n54/9NJTUmisBAADAq+QMOgfT5r2m1ehGHYe2TPe4MgAAADwrZ9AaTNtSOJRf\n        zpeh/jFXAgAAgFfJGbQG067d1F9O52EaBFMAAABWlDNoDaZ9t5n2+3Ya911NrbkSAAAAvErOoN13MO2m\n        fmgEUwAAAFaVM2jtMd312+l47OsDTo3KCwAAwJpyBl2C6eU8TH0vmAIAALCunEFrMI0fPj/3U1f+KJgC\n        AACwppxB52A6NNOvX6epbTfTriTWXAkAAABeJWfQOvhRDNP7+++fU1MKY9jeXAkAAABeJWfQ5XExu10z\n        7Q990ZXpHlcGAACAZ+UMWoNp07xP4XDcFX2Z7nFlAAAAeFbOoPVS3lthpFXBFAAAgDXlDNo1zXfhGIVF\n        rgQAAACvkjNoDaZtKYjRkMZ9J5gCAACwqpxBu/YumA5j61JeAAAAVpUzaA2m0YXadXNaPZ52ZbrHlQEA\n        AOBZOYO29R7TzVu9vrfrttPxPJTpHlcGAACAZ+UMOveYRuH2fWpL4ekylukeVwYAAIBn5Qy6BNNIqvGA\n        04NLeQEAAFhRzqBLML2cd9PlMkxNuynTPa4MAAAAz8oZtAbT7ftv0+fnOH18jNN2+16me1wZAAAAnpUz\n        6DWYvpWCYTqXxNo0ekwBAABYT86gczC9dqOeTn29zjdXAgAAgFfJGXS5xzSS6uHQTX0vmAIAALCenEGX\n        YHo69tM4tnpMAQAAWFXOoHMw3b5Nh303DUMzdXpMAQAAWFHOoEswHYe2ptWhvOZKAAAA8Co5g9Zg2pbC\n        eLBppNX9oS/TPa4MAAAAz8oZdAmmccNpFB5PuzLd48oAAADwrJxBl8GP5sJ2Op2HMt3jygAAAPCsnEF/\n        BNO4vvd8EUwBAABYT86gy6W8MUSvHlMAAADWljPo3GNaCzclsbrHFAAAgHXlDFqDade818J4fszhKJgC\n        AACwnpxBazDt21LYXgv1mAIAALCinEHne0xLWm2jsBNMAQAAWFfOoMvgR7VQjykAAAAryxl0Cabb7Xsd\n        rvdoVF4AAABWlDPocinv1+d+Oh76OipSrgQAAACvkjPodzD9OkzHYz815edcCQAAAF4lZ9DrpbxzWt3v\n        2zpkb64EAAAAr5Iz6NJj+vExTuPY1mt8cyUAAAB4lZxBlx7Ty2U3DUMz7XbuMQUAAGA9OYMuwfR06muB\n        HlMAAADWlDPoEkzjptMo0GMKAADAmnIG7ZprMD0culowDG2Z7nFlAAAAeFbOoEuPadx0OpTC/b4r0z2u\n        DAAAAM/KGXQJplEQf9iX1JorAQAAwKvkDLoE0+hCjaR6OPRluseVAQAA4Fk5gy7BNG46jYLDUTAFAABg\n        PTmD1mDalMKui0I9pgAAAKwrZ9BlVN6u29TrewVTAAAA1pQz6BxMm1LYbqbdYPAjAAAA1pUz6HyPaSls\n        S+EQIyJ5XAwAAAAryhn0O5gWYykQTAEAAFhTzqDt7VLeRjAFAADgb5AzaL3HNAqaZjPtD717TAEAAFhV\n        zqC1x7TvNvXhppFWx1EwBQAAYD05g9Z7TMehmf7561RvPo2RkXIlAAAAeJWcQWswHUpS/fra18Jdvy3T\n        Pa4MAAAAz8oZ9BpMt9PHZZi6biuYAgAAsKqcQWswjR9Op93Ul1fBFAAAgDXlDDoH024zHQ5dKWzqDai5\n        EgAAALxKzqA1mMaISPt9O/WlQDAFAABgTTmDLsF0HNsqbkLNlQAAAOBVcgatwTSG5x2Gdjoe+/IqmAIA\n        ALCenEFrMG2b9/rL6bwTTAEAAFhVzqBds70VtqVwcCkvAAAAq8oZtL0F07i293QZDH4EAADAqnIGrcG0\n        2b7VtHq+jFPfeY4pAAAA68kZdAmmMUzvsaTVrtuU6R5XBgAAgGflDNo2zbWwb6bDaSivekwBAABYT86g\n        tcd0+/42DWNbCnfTTjAFAABgRTmDzsF08zbthlJ41mMKAADAunIGne8xLYVxfW+kVYMfAQAAsKacQb8H\n        P4rre/WYAgAAsLKcQZdg2sRzZA79dChyJQAAAHiVnEFrMI2Hm7btpt58ut93ZbrHlQEAAOBZOYMuwbQr\n        hfXm04NgCgAAwHpyBv0Opt1mGmO4XpfyAgAAsKKcQa/3mEbhtiZVwRQAAIA15Qy69JjGSEhRcDwKpgAA\n        AKwnZ9A5mJa0uts19aZTPaYAAACsKWfQdnvtMR1K4Xx9r8GPAAAAWE/OoMulvFEQf/C4GAAAANaUM+hy\n        KW+k1OhKHYa2TPe4MgAAADwrZ9AlmMYNp3HzafwhVwIAAIBXyRl0CaanU18L+l4wBQAAYD05gy7B9HLZ\n        TcPQ6DEFAABgVTmDtk0z/WPctdN+aKfD2E7HfVeN5Y9Dt62iezXEA1C7drO8RuUmbN+m8/lQHKdfv47T\n        19dx+vzYlzcaStmuJuGvr30pG+eyUyk79vUm17ie+JaS63y7Mt+Yd319n/r4W1WmK9Peft+VFYi69YbZ\n        Yhzjptl5RKfjsavv+/FxKO/7MX1+norL1HelXjH0pU7xX693XffNtNm81fX95z8v1/X+P7CO5T2a5n0R\n        7xPvF+976yaPxr/NJ9omdoiPssyfn/syr1Ndl8v5VNs0Hnxb53E3n5s6vzrP7TSWeR7KPOty3c3z4zKW\n        99iX9xvqfGJ+38s3r/+wey9/35Z1mZfho2zD83ko9XbT8VC24Xi/Dcv7xnvflqMu23aed5nfOGzq8szt\n        Evvjoc7zUpYj5nk87sp692Vb/rFd2nBdz7ab2yXaINpkbpe5baJObZvaJg/a5lS2Qaz/v902m79um+t2\n        +Xfa5rZt6na6a5uY54+2KfOs23lpm+2PZVvaZri1zbi0zaW2TdmWh91ft83Vd9vMyzO3zbwu9+193za7\n        2NZle8XnZxy3d+v89m+v87I/ls9JfCaXdT7vy/uMte79+sZrrPOu7I/1Pa+fidvy3fbHn/vO9/u/ap2X\n        /bHM4zafWLau7JPD0Nfp/+d/LnV+Ma/bfOZtFco+GftnWca6nHXfLfO97rf3+3NXjoehKetdt2ts02U7\n        /nF//N6WsT/Ox/s47v+hbeq8YluUfbu81vk9apvr/jjPc94fD4ehfqb/0DbF0jb12BfH2qhT2ua6Hev+\n        GMfRuh0ft00sW8xzuLVNWY96rPi6O1bE/v2XbXNtn7pssa5z20Qb/P77uW6bj8u+fk7qcl3bJo4VP9om\n        5nttm7l9UrvEetdtOftX7RLfu4/aJb6n4/t6aZfra91Gxe07L77/bt+F8b0Y34/xPekc4T9c77ruzhHq\n        /Oo8nSM4R3jQNlffbTMvz9w2zhH+bJ2X/bHM4zafWLb/n84R/jFvkD8/cN4+WLHAsUB1gxRN21axw8bJ\n        xOEYG3L+komFjIWND2OseFw/PG+UnxtkLGX7shEP5e9hiI0fH+JD+UIoO8yxHCzC6V40WNnYl1BW/hzT\n        lA/BvnwIon7dwNfGC7to+CI2RG3I0oj/zhfGn633vDPMr/OOOa/3/4V1HGMHLobynjHdbF6G2FnDfv/9\n        wbk/YB5Lm8VBaV6XsbZpXdfrOsf61w9Z2XHu12/+eT5AHMo6xQd9PrDNB6rL5VCWfV+2Yezc1zao5p1y\n        GDe1XrTBVzk5jB365wcpljGWd36feM/bB2lpk+syxslmzC/aJb5o4kBx+1Df2mWeX9n2120SbTOWbfKn\n        7VLW41+3zbhu29SD5/NtcypfiLe2ie39H7VN+QL/KOt8Ppf1rQfL9dvmVNb5WPbJl65zORmIE6Fom2V9\n        l3nGcm7qNv/fWue8P8brGO9b/j6MUT7fizEr+1h53/kkqHzRlv3kVPaRc1nXS4hlL/voqXi0Px9ivy1u\n        ++L9/nhbjmV/LO5Prm5fQs8eK+YTtDhWxPF33h//um2a6/SH6zaN8DcfK+oyDuU1tkndLqVtrl/mP9sm\n        lmsWx5pb+/74/F2Xu7ZPWeeY//z3fp5vTHNtn9pW5YRgV967flfc2qb4/vKOE9Ly3RInMNftH47lvQ+l\n        LMTPYR/H+rJdH7VLbZt/o13i+3hul7vv6rLusR1i+e5PnOP7Lr736vdZ2bax799/P/6335XOEZwjzOLn\n        n5975wgvbps4ljpHmJft2XV2jrDsy/9b5wj/+FcHzvgyjQ0fKxALGge/Yzko7I/HKr5Id2Vh+l1J1PVN\n        4yA9qx+6SN11Ab4/iLFy805VNlA0yHUjxQc4vrj3xzjADrUx6wnGdcPOG3j+IrhtoH3ZALHMywf2upHq\n        CUn872d86Jdlmz9Q8fofr3ccCEudW4OdS3ms4+b2v1L/B9ZxOfG5V9473vMmyg7lAxQ71O3DEssb61K3\n        TfngRVsO5QQwdta67lGvKvOK9Sjrfv9lOO53dVluX87xPyy37Rzz2o3buv3m7XjdllXZ6ctOO4y3E6ho\n        p3mnnfef+YC9j4PHj+14/TDV+X23S8xrPFwPovV/kL7b5fsEMQ7id+1S6tXtEsq8HrZL+NvaJrbnv26b\n        Zf2jXvXftc1w3zY35fd4rW1z+9/S3DblgHLfNpePa9uU979vm7pspfxR28wHptQ25WB2a5v9oRzQSr1X\n        r/OP/THc/fyfrPP5v1jnh/tjXefYF+b51X0hlLI6v+vrWJYr1q2L/7Ut87kdq+oXV90HY3+8HsuK2Bdv\n        +9Gj/Tm+RCJ0xbyPZX3qMtT3u753/SyUY0WEsdify3rEuoQf+2OZz+lSvtjqZ/u6DWJedX3mtol51n17\n        vLZNbZfUNn1Zr7J9D/HlXNqxii/7+L1+LuJzuVum/8OxorRPbIs4uf/+vJXlKV+s3/Oa5zuWz/iwj/8V\n        n0+4Yj63Y/etferJQPl81/mVujHP2CYxn9gudVvX7V1OOMtyxf9WR7iJeczbuXyfhGijElrnk404PpR2\n        ie153aa3bXtrm9iecXyZ1+HaLmV/uLmF8cftUsS61P28qe3x/V1d2rTUjX0r9tn4fov3iOWLfamub9lv\n        4vgY34vzfxbEMdI5gnOEB5975whzm9z8bW0T29M5QrSNc4T5c3J7/f/lHOEfMYNtOnDeZhwLGpey3Nxf\n        1jPsyhdaMcbPZdqh1I3LYHalgb5fy4aJjXN7Lcar2++LZdrNYhcbt4qfi9Jwob++VvH3+9/vyodS52Y5\n        0Sliw/xc7/mA8mfrfROX9Dy8rOd++Yv/rXW8n+9P1/e8LcP9Mt/ZlWluhn5T1+/ePj4kV7ey+3Wb2/x7\n        HnV97uZV613d5jHvO2Wbx7TX6Wudm+v8xzjpLO6X4abOc1me2743v++yfDGP5GFZ3RbXZbnfprflq+Zt\n        /6Pd7n7/67a4c3vPtJw/xPLU1/t6D9rmzq3sfh637Vrdlrkry1vU6e+24e3nW9v0Zdqbud5sWbZibp/r\n        Mtza5cG8bu9/vw1q/avb71Vti++2rPO7um//5b3q+3zXXfbH++WP34s6/V297/pFOX71t/a8Tn9zW+a6\n        vLE/ljp5u/+YV53fXd1r/T8z74MxXbzefv5zS1tW3/vgz9/nsvv9sv49Xuvv3+//R7f1uG3PrNQvf8vr\n        XqXt+5fzuV+emG6Z/ltcohvfLX35wqsezSf8WO4/us2nzqtMH/N6OJ9/YVmO/0YTr+W7p4n98rv8u+2+\n        26qLIPc3ixOHONmqJ0tlezlHcI4Qbp/R+XPqHCEsy3Fbvmre9j/a7e73v26LO7f3TMv5QyxPfb2v5xzh\n        vv2X96rv81132R/vlz9+L+r0d/W+6xf1e+jantfpb27LXJfXOUJR6pe/5XWv0vad57Od/h9j8UqsDmle\n        QAAAAABJRU5ErkJggg==\n</value>\n  </data>\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAAAAACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAQAAAAAAAAAAAAAAAEAAAAB\n        AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYW\n        FgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAA\n        MwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm\n        /wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/\n        zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNm\n        ZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM\n        /wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYz\n        mQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbM\n        MwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkz\n        MwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnM\n        AACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwA\n        mQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZ\n        MwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/\n        zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9m\n        zADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/\n        ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKy\n        sgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//\n        AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK\n        CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCrcKCgoKCgoKCgoKCgoK\n        CgoKCgoKCgoKCgoKCgoKCgoK+QoKCgoKCgoKCgrSCgoKCgoKCgoKCgoKCgoKCgoKCgr5+QoKCgoKCgr5\n        sQoKCgoKCgoKCgoKCgoKCgoKCgoKCvn5CgoKCgoKsbEKCgoKCgoKCgoKCgoKCgoKCgoKCgoK+ZQKCgoK\n        CuPjCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr5sQoKCgpHsQoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgpq\n        Cgr5QbEKCgqxtwoKCgoKCgr5CgoK+QoKCgoKCgoKCuP5lPmUCgoKCrGxt7f5+fkKCvkK+fkKCgoKCgoK\n        CgoKFkH5lAoK+QoK+bcKCgr5t7cK+fn5CgoKCgoKCgoKCrdB+fkKCgoK0rext7EKCvn5Crf5+QoKCgoK\n        CgoKCgqx+UdBCgoKCgq3+fkKt5QK+fkK0vn5CgoKCgoKCgoKCgq3+UGUCgoKCvmxtwoKsbcK+QqUCvn5\n        +QoKCgoKCgoKCgr5F0f5CgoKCmqxCgoKavn5+eP5arexagoKCgoKCgoKCgqU+Wrj+QoKt7cKRmlq+Qq3\n        lJQXF+MWCgoKCgoKCgoKCvn5+flq4/kKCuvs7O0KCgoKCgoKCgoKCgoKCgoKCgoKCkfjCgoWRxaSku3s\n        7OwKCgoKCgoKCgoKCgoKCgoKCgoK+fkKCgr5bpKS7e3t7eztCgoKCgoKCgoKCgoKCgoKCgr5+ZQKCgqS\n        kpLt7e3t7e3tCgoKCgoKCgoKCgoKCgoKCgr54woK7++SkpLt7e3t7Ozs7fcKCgoKCgoKCgoKCrHjFkEX\n        FhZpku/3kpLt7e3s7Ozs7JIKCgoKCgoKCgoKR/n5+fn5+fkg7e+SkpLt7Ozs7Ozs7ZIKCgoKCgoKCgpH\n        QUFBQUcXahbt95KS7e3s7Ozs7Oztkvf3CgoKCgoKCgoKCgrs6+wKCpKS7e3t7Ozs7Ozt7ZL39+/vCgoK\n        CgoKCgoKCuzr6uzs7ZLt7ezs7Ozs7ZKS9+/v7+/vCgoKCgoKCgrr7JLrbeyS7ezs7Ozs7ZKS9/fv7wcH\n        BwcKCgoKCgoK7BLs7/fs7Ozs7Ozs7O2S9+/v7+8HBwcHBwoKCgoKCgoSbe8H7+zt7Ovs7O2Skvfv7+8H\n        BwcHBwcHCgoKCgoK7ezv7++S7O3v9+zs9/fv7+8HBwcHBwcH8fAKCgoKCuwS6+ztkvfv7+8HB/f3B7y8\n        vPDw8PDwvPP/8/////////////////f////3/v//8/n///Pz///z5///88////sc/u/4PAaf+GziP/Dw\n        ZH/h8SR/8PGVH/h5wA/8GQgP/AYf//5gD//+cAP//jgB//8wAD/4AAAf+AAAD/gAAAP/jAAB/4AAAP8A\n        AAD+AAAA/gAAAPwAAAD4AAAA\n</value>\n  </data>\n</root>"
  },
  {
    "path": "Razor/Client/ClassicUO.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing Assistant.UI;\nusing CUO_API;\nusing System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Threading;\nusing System.Windows.Forms;\nusing Assistant.Core;\nusing Assistant.Scripts;\n\nnamespace Assistant\n{\n    public partial class Engine\n    {\n        public static unsafe void Install(PluginHeader* plugin)\n        {\n            Application.EnableVisualStyles();\n            Application.SetCompatibleTextRenderingDefault(false);\n\n            AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>\n            {\n                string[] fields = e.Name.Split(',');\n                string name = fields[0];\n                string culture = fields[2];\n\n                if (name.EndsWith(\".resources\") && !culture.EndsWith(\"neutral\"))\n                {\n                    return null;\n                }\n\n                AssemblyName askedassembly = new AssemblyName(e.Name);\n\n                bool isdll = File.Exists(Path.Combine(RootPath, askedassembly.Name + \".dll\"));\n\n                return Assembly.LoadFile(Path.Combine(RootPath, askedassembly.Name + (isdll ? \".dll\" : \".exe\")));\n            };\n\n            SplashScreen.Start();\n            m_ActiveWnd = SplashScreen.Instance;\n\n            Client.Init(false);\n\n            if (!(Client.Instance as ClassicUOClient).Install(plugin))\n            {\n                Process.GetCurrentProcess().Kill();\n                return;\n            }\n\n            // load ultimasdk before or the Language.Load will throw the cliloc not found warning every time you run cuo\n            string clientPath =\n                ((OnGetUOFilePath) Marshal.GetDelegateForFunctionPointer(plugin->GetUOFilePath, typeof(OnGetUOFilePath))\n                )();\n\n            // just replicating the static .ctor\n            Ultima.Files.ReLoadDirectory();\n            Ultima.Files.LoadMulPath();\n\n            Ultima.Files.SetMulPath(clientPath);\n            Ultima.Multis.PostHSFormat = UsePostHSChanges;\n            Client.Instance.ClientEncrypted = false;\n            Client.Instance.ServerEncrypted = false;\n\n\n            /* Load localization files */\n            if (!Language.Load(\"ENU\"))\n            {\n                SplashScreen.End();\n                MessageBox.Show(\n                    \"WARNING: Razor was unable to load the file Language/Razor_lang.ENU\\n.\",\n                    \"Language Load Error\", MessageBoxButtons.OK, MessageBoxIcon.Warning);\n                return;\n            }\n\n            m_Running = true;\n\n            Language.LoadCliLoc();\n\n            /* Initialize engine */\n            SplashScreen.Message = LocString.Initializing;\n            Initialize(typeof(Engine).Assembly);\n\n            /* Load Profile */\n            SplashScreen.Message = LocString.LoadingLastProfile;\n            Config.LoadCharList();\n            Overrides.Load();\n            if (!Config.LoadLastProfile())\n                MessageBox.Show(\n                    \"The selected profile could not be loaded, using default instead.\", \"Profile Load Error\",\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\n\n            SplashScreen.Message = LocString.WaitingForClient;\n\n            SplashScreen.End();\n\n            Thread t = new Thread(() => { RunUI(); });\n            t.SetApartmentState(ApartmentState.STA);\n            t.IsBackground = true;\n            t.Start();\n        }\n    }\n\n    public class ClassicUOClient : Client\n    {\n        public override DateTime ConnectionStart => m_ConnectionStart;\n        public override IPAddress LastConnection { get; }\n        public override Process ClientProcess => m_ClientProcess;\n        public override bool ClientRunning => m_ClientRunning;\n        private uint m_In, m_Out;\n\n        private DateTime m_ConnectionStart;\n        private Process m_ClientProcess = null;\n        private bool m_ClientRunning = false;\n        private string m_ClientVersion;\n\n        private static OnPacketSendRecv _sendToClient, _sendToServer, _recv, _send;\n        private static OnGetPacketLength _getPacketLength;\n        private static OnGetPlayerPosition _getPlayerPosition;\n        private static OnCastSpell _castSpell;\n        private static OnGetStaticImage _getStaticImage;\n        private static OnTick _tick;\n        private static RequestMove _requestMove;\n        private static OnSetTitle _setTitle;\n        private static OnGetUOFilePath _uoFilePath;\n\n\n        private static OnHotkey _onHotkeyPressed;\n        private static OnMouse _onMouse;\n        private static OnUpdatePlayerPosition _onUpdatePlayerPosition;\n        private static OnClientClose _onClientClose;\n        private static OnInitialize _onInitialize;\n        private static OnConnected _onConnected;\n        private static OnDisconnected _onDisconnected;\n        private static OnFocusGained _onFocusGained;\n        private static OnFocusLost _onFocusLost;\n        private IntPtr m_ClientWindow;\n\n        public override void SetMapWndHandle(Form mapWnd)\n        {\n        }\n\n        public override void RequestStatbarPatch(bool preAOS)\n        {\n        }\n\n        public override void SetCustomNotoHue(int hue)\n        {\n        }\n\n        public override void SetSmartCPU(bool enabled)\n        {\n        }\n\n        public override void SetGameSize(int x, int y)\n        {\n        }\n\n        public override Loader_Error LaunchClient(string client)\n        {\n            return Loader_Error.SUCCESS;\n        }\n\n        public override bool ClientEncrypted { get; set; }\n\n        public override bool ServerEncrypted { get; set; }\n\n        public static Assembly Assembly { get; set; }\n\n        public unsafe bool Install(PluginHeader* header)\n        {\n            _sendToClient =\n                (OnPacketSendRecv) Marshal.GetDelegateForFunctionPointer(header->Recv, typeof(OnPacketSendRecv));\n            _sendToServer =\n                (OnPacketSendRecv) Marshal.GetDelegateForFunctionPointer(header->Send, typeof(OnPacketSendRecv));\n            _getPacketLength =\n                (OnGetPacketLength) Marshal.GetDelegateForFunctionPointer(header->GetPacketLength,\n                    typeof(OnGetPacketLength));\n            _getPlayerPosition =\n                (OnGetPlayerPosition) Marshal.GetDelegateForFunctionPointer(header->GetPlayerPosition,\n                    typeof(OnGetPlayerPosition));\n            _castSpell = (OnCastSpell) Marshal.GetDelegateForFunctionPointer(header->CastSpell, typeof(OnCastSpell));\n            _getStaticImage =\n                (OnGetStaticImage) Marshal.GetDelegateForFunctionPointer(header->GetStaticImage,\n                    typeof(OnGetStaticImage));\n            _requestMove =\n                (RequestMove) Marshal.GetDelegateForFunctionPointer(header->RequestMove, typeof(RequestMove));\n            _setTitle = (OnSetTitle) Marshal.GetDelegateForFunctionPointer(header->SetTitle, typeof(OnSetTitle));\n            _uoFilePath =\n                (OnGetUOFilePath) Marshal.GetDelegateForFunctionPointer(header->GetUOFilePath, typeof(OnGetUOFilePath));\n            m_ClientVersion = new Version((byte) (header->ClientVersion >> 24), (byte) (header->ClientVersion >> 16),\n                (byte) (header->ClientVersion >> 8), (byte) header->ClientVersion).ToString();\n            m_ClientRunning = true;\n            m_ClientWindow = header->HWND;\n            _tick = Tick;\n            _recv = OnRecv;\n            _send = OnSend;\n            _onHotkeyPressed = OnHotKeyHandler;\n            _onMouse = OnMouseHandler;\n            _onUpdatePlayerPosition = OnPlayerPositionChanged;\n            _onClientClose = OnClientClosing;\n            _onInitialize = OnInitialize;\n            _onConnected = OnConnected;\n            _onDisconnected = OnDisconnected;\n            _onFocusGained = OnFocusGained;\n            _onFocusLost = OnFocusLost;\n            header->Tick = Marshal.GetFunctionPointerForDelegate(_tick);\n            header->OnRecv = Marshal.GetFunctionPointerForDelegate(_recv);\n            header->OnSend = Marshal.GetFunctionPointerForDelegate(_send);\n            header->OnHotkeyPressed = Marshal.GetFunctionPointerForDelegate(_onHotkeyPressed);\n            header->OnMouse = Marshal.GetFunctionPointerForDelegate(_onMouse);\n            header->OnPlayerPositionChanged = Marshal.GetFunctionPointerForDelegate(_onUpdatePlayerPosition);\n            header->OnClientClosing = Marshal.GetFunctionPointerForDelegate(_onClientClose);\n            header->OnInitialize = Marshal.GetFunctionPointerForDelegate(_onInitialize);\n            header->OnConnected = Marshal.GetFunctionPointerForDelegate(_onConnected);\n            header->OnDisconnected = Marshal.GetFunctionPointerForDelegate(_onDisconnected);\n            header->OnFocusGained = Marshal.GetFunctionPointerForDelegate(_onFocusGained);\n            header->OnFocusLost = Marshal.GetFunctionPointerForDelegate(_onFocusLost);\n\n            Assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.StartsWith(\"ClassicUO,\"));\n\n            return true;\n        }\n\n        public unsafe override bool InstallHooks(IntPtr pluginPtr)\n        {\n            Engine.MainWindow.SafeAction((s) => { Engine.MainWindow.MainForm_EndLoad(); });\n            return true;\n        }\n\n        private void Tick()\n        {\n            Timer.Slice();\n        }\n\n        private void OnPlayerPositionChanged(int x, int y, int z)\n        {\n            World.Player.Position = new Point3D(x, y, z);\n        }\n\n        private unsafe bool OnRecv(ref byte[] data, ref int length)\n        {\n            m_In += (uint) length;\n            fixed (byte* ptr = data)\n            {\n                bool result = true;\n                byte id = data[0];\n\n                PacketReader reader = null;\n                Packet packet = null;\n                bool isView = PacketHandler.HasServerViewer(id);\n                bool isFilter = PacketHandler.HasServerFilter(id);\n                \n                if (isView)\n                {\n                    reader = new PacketReader(ptr, length, PacketsTable.IsDynLength(id));\n                    result = !PacketHandler.OnServerPacket(id, reader, packet);\n                }\n\n                if (isFilter)\n                {\n                    packet = new Packet(data, length, PacketsTable.IsDynLength(id));\n                    result = !PacketHandler.OnServerPacket(id, reader, packet);\n\n                    data = packet.Compile();\n                    length = (int) packet.Length;\n                }\n\n                if (Packet.Logging)\n                {\n                    Packet.Log(PacketPath.ServerToClient, ptr, data.Length, !result);\n                }\n\n                return result;\n            }\n        }\n\n        private unsafe bool OnSend(ref byte[] data, ref int length)\n        {\n            m_Out += (uint) length;\n            fixed (byte* ptr = data)\n            {\n                bool result = true;\n                byte id = data[0];\n\n                PacketReader reader = null;\n                Packet packet = null;\n                bool isView = PacketHandler.HasClientViewer(id);\n                bool isFilter = PacketHandler.HasClientFilter(id);\n                \n                if (isView)\n                {\n                    reader = new PacketReader(ptr, length, PacketsTable.IsDynLength(id));\n                    result = !PacketHandler.OnClientPacket(id, reader, packet);\n                }\n                else if (isFilter)\n                {\n                    packet = new Packet(data, length, PacketsTable.IsDynLength(id));\n                    result = !PacketHandler.OnClientPacket(id, reader, packet);\n\n                    data = packet.Compile();\n                    length = (int) packet.Length;\n                }\n\n                if (Packet.Logging)\n                {\n                    Packet.Log(PacketPath.ClientToServer, ptr, data.Length, !result);\n                }\n\n                return result;\n            }\n        }\n\n        private void OnMouseHandler(int button, int wheel)\n        {\n            if (button > 4)\n                button = 3;\n            else if (button > 3)\n                button = 2;\n            else if (button > 2)\n                button = 2;\n            else if (button > 1)\n                button = 1;\n\n            HotKey.OnMouse(button, wheel);\n        }\n\n        private enum SDL_Keymod\n        {\n            KMOD_NONE = 0x0000,\n            KMOD_LSHIFT = 0x0001,\n            KMOD_RSHIFT = 0x0002,\n            KMOD_LCTRL = 0x0040,\n            KMOD_RCTRL = 0x0080,\n            KMOD_LALT = 0x0100,\n            KMOD_RALT = 0x0200,\n            KMOD_LGUI = 0x0400,\n            KMOD_RGUI = 0x0800,\n            KMOD_NUM = 0x1000,\n            KMOD_CAPS = 0x2000,\n            KMOD_MODE = 0x4000,\n            KMOD_RESERVED = 0x8000\n        }\n\n        private enum SDL_Keycode_Ignore\n        {\n            SDLK_LCTRL = 1073742048,\n            SDLK_LSHIFT = 1073742049,\n            SDLK_LALT = 1073742050,\n            SDLK_RCTRL = 1073742052,\n            SDLK_RSHIFT = 1073742053,\n            SDLK_RALT = 1073742054,\n        }\n\n        private bool OnHotKeyHandler(int key, int mod, bool ispressed)\n        {\n            if (ispressed && !Enum.IsDefined(typeof(SDL_Keycode_Ignore), key))\n            {\n                ModKeys cur = ModKeys.None;\n                SDL_Keymod keymod = (SDL_Keymod) mod;\n                if (keymod.HasFlag(SDL_Keymod.KMOD_LCTRL) || keymod.HasFlag(SDL_Keymod.KMOD_RCTRL))\n                    cur |= ModKeys.Control;\n                if (keymod.HasFlag(SDL_Keymod.KMOD_LALT) || keymod.HasFlag(SDL_Keymod.KMOD_RALT))\n                    cur |= ModKeys.Alt;\n                if (keymod.HasFlag(SDL_Keymod.KMOD_LSHIFT) || keymod.HasFlag(SDL_Keymod.KMOD_RSHIFT))\n                    cur |= ModKeys.Shift;\n                return HotKey.OnKeyDown(Win32Platform.MapKey(key), cur);\n            }\n\n            return true;\n        }\n\n        private void OnDisconnected()\n        {\n            PacketHandlers.Party.Clear();\n            //TODO reset window title\n            Engine.MainWindow.UpdateTitle();\n            UOAssist.PostLogout();\n\n            World.Player = null;\n            World.Items.Clear();\n            World.Mobiles.Clear();\n            Macros.MacroManager.Stop();\n            ScriptManager.OnLogout();\n            ActionQueue.Stop();\n            Counter.Reset();\n            GoldPerHourTimer.Stop();\n            BandageTimer.Stop();\n            GateTimer.Stop();\n            WaypointManager.StopTimer();\n            BuffDebuffManager.Stop();\n            CooldownManager.Stop();\n            StealthSteps.Unhide();\n            Engine.MainWindow.OnLogout();\n            if (Engine.MainWindow.MapWindow != null)\n                Engine.MainWindow.MapWindow.Close();\n            PacketHandlers.Party.Clear();\n            PacketHandlers.IgnoreGumps.Clear();\n            Agents.BuyAgent.OnDisconnected();\n            Config.Save();\n        }\n\n        private void OnConnected()\n        {\n            m_ConnectionStart = DateTime.UtcNow;\n        }\n\n        private void OnClientClosing()\n        {\n            var last = Console.BackgroundColor;\n            var lastFore = Console.ForegroundColor;\n            Console.BackgroundColor = ConsoleColor.Red;\n            Console.ForegroundColor = ConsoleColor.Black;\n            Console.WriteLine(\"Closing Razor instance\");\n            Console.BackgroundColor = last;\n            Console.ForegroundColor = lastFore;\n            Engine.Close();\n        }\n\n        private void OnInitialize()\n        {\n            var last = Console.BackgroundColor;\n            var lastFore = Console.ForegroundColor;\n            Console.BackgroundColor = ConsoleColor.Green;\n            Console.ForegroundColor = ConsoleColor.Black;\n            Console.WriteLine(\"Initialized Razor instance\");\n            Console.BackgroundColor = last;\n            Console.ForegroundColor = lastFore;\n        }\n\n        public override void SetConnectionInfo(IPAddress addr, int port)\n        {\n        }\n\n        public override void SetNegotiate(bool negotiate)\n        {\n        }\n\n        public override bool Attach(int pid)\n        {\n            return false;\n        }\n\n        public override void Close()\n        {\n        }\n\n        public override void UpdateTitleBar()\n        {\n            if (!ClientRunning)\n                return;\n\n            if (World.Player != null && Config.GetBool(\"TitleBarDisplay\"))\n            {\n                ResetTitleBarBuilder();\n\n                TitleBarBuilder.Replace(@\"{char}\", World.Player.Name);\n\n                TitleBarBuilder.Replace(@\"{crimtime}\",\n                    World.Player.CriminalTime != 0 ? $\"{World.Player.CriminalTime}\" : \"-\");\n\n                TitleBarBuilder.Replace(@\"{hp}\", $\"{World.Player.Hits}\");\n                TitleBarBuilder.Replace(@\"{mana}\", $\"{World.Player.Mana}\");\n                TitleBarBuilder.Replace(@\"{stam}\", $\"{World.Player.Stam}\");\n\n                TitleBarBuilder.Replace(@\"{weight}\", World.Player.Weight.ToString());\n\n                TitleBarBuilder.Replace(@\"{bandage}\", BandageTimer.Running ? $\"{BandageTimer.Count}\" : \"-\");\n\n                TitleBarBuilder.Replace(@\"{statbar}\", string.Empty);\n                TitleBarBuilder.Replace(@\"{mediumstatbar}\", string.Empty);\n                TitleBarBuilder.Replace(@\"{largestatbar}\", string.Empty);\n\n                foreach (Counter c in Counter.List)\n                {\n                    if (c.Enabled)\n                        TitleBarBuilder.Replace($\"{{{c.Format}}}\", c.GetTitlebarString(false, false));\n                }\n\n                base.UpdateTitleBar();\n            }\n            else\n            {\n                SetTitleStr(string.Empty);\n            }\n        }\n\n\n        public override void SetTitleStr(string str)\n        {\n            _setTitle(str);\n        }\n\n        public override bool OnMessage(MainForm razor, uint wParam, int lParam)\n        {\n            return false;\n        }\n\n        public override bool OnCopyData(IntPtr wparam, IntPtr lparam)\n        {\n            return false;\n        }\n\n        public override void SendToServer(Packet p)\n        {\n            byte[] data = p.Compile();\n            int length = (int) p.Length;\n            _sendToServer(ref data, ref length);\n        }\n\n        public override void SendToServer(PacketReader pr)\n        {\n            SendToServer(MakePacketFrom(pr));\n        }\n\n        public override void SendToClient(Packet p)\n        {\n            byte[] data = p.Compile();\n            int length = (int) p.Length;\n\n            _sendToClient(ref data, ref length);\n        }\n\n        public override void SendPacketToClient(byte[] packet, int length)\n        {\n            _sendToClient(ref packet, ref length);\n        }\n\n        public override unsafe void ForceSendToClient(Packet p)\n        {\n            byte[] data = p.Compile();\n            int length = (int) p.Length;\n\n            _sendToClient(ref data, ref length);\n\n            if (Packet.Logging)\n            {\n                fixed (byte* ptr = data)\n                {\n                    Packet.Log(PacketPath.RazorToClient, ptr, data.Length);\n                }\n            }\n        }\n\n        public override unsafe void ForceSendToServer(Packet p)\n        {\n            byte[] data = p.Compile();\n            int length = (int) p.Length;\n\n            _sendToServer(ref data, ref length);\n\n            if (Packet.Logging)\n            {\n                fixed (byte* ptr = data)\n                {\n                    Packet.Log(PacketPath.RazorToServer, ptr, data.Length);\n                }\n            }\n        }\n\n        public override void SetPosition(uint x, uint y, uint z, byte dir)\n        {\n        }\n\n        public override string GetClientVersion()\n        {\n            return m_ClientVersion;\n        }\n\n        public override string GetUoFilePath()\n        {\n            return _uoFilePath();\n        }\n\n        public override IntPtr GetWindowHandle()\n        {\n            return m_ClientWindow;\n        }\n\n        public override uint TotalDataIn()\n        {\n            return m_In;\n        }\n\n        public override uint TotalDataOut()\n        {\n            return m_Out;\n        }\n\n        internal override void RequestMove(Direction m_Dir)\n        {\n            _requestMove((int) m_Dir, false);\n        }\n\n        public void OnFocusGained()\n        {\n            if (Engine.MainWindow == null)\n                return;\n\n            if (Config.GetBool(\"AlwaysOnTop\"))\n            {\n                if (!Engine.MainWindow.TopMost)\n                {\n                    Platform.SetForegroundWindow(GetWindowHandle());\n\n                    Engine.MainWindow.SafeAction(s =>\n                    {\n                        s.TopMost = true;\n                        s.BringToFront();\n                    });\n                }\n            }\n\n            // always use smartness for the map window\n            if (Engine.MainWindow.MapWindow != null && Engine.MainWindow.MapWindow.Visible)\n            {\n                if (!Engine.MainWindow.MapWindow.TopMost)\n                {\n                    Engine.MainWindow.MapWindow.SafeAction(s =>\n                    {\n                        s.TopMost = true;\n                        s.BringToFront();\n                    });\n                }\n            }\n        }\n\n        public void OnFocusLost()\n        {\n            if (Engine.MainWindow == null)\n                return;\n\n            bool razorfocus = Form.ActiveForm == Engine.MainWindow || Form.ActiveForm == Engine.MainWindow.MapWindow;\n            if (Config.GetBool(\"AlwaysOnTop\"))\n            {\n                if (Engine.MainWindow.TopMost && !razorfocus)\n                {\n                    Engine.MainWindow.SafeAction(s =>\n                    {\n                        s.TopMost = false;\n                        s.SendToBack();\n                    });\n                }\n            }\n\n            // always use smartness for the map window\n            if (Engine.MainWindow.MapWindow != null && Engine.MainWindow.MapWindow.Visible && !razorfocus)\n            {\n                if (Engine.MainWindow.MapWindow.TopMost)\n                {\n                    Engine.MainWindow.MapWindow.SafeAction(s =>\n                    {\n                        s.TopMost = false;\n                        s.SendToBack();\n                    });\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Client/Client.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing Assistant.Core;\nusing System;\nusing System.Diagnostics;\nusing System.Net;\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace Assistant\n{\n    public class FeatureBit\n    {\n        public static readonly int WeatherFilter = 0;\n        public static readonly int LightFilter = 1;\n        public static readonly int SmartLT = 2;\n        public static readonly int RangeCheckLT = 3;\n        public static readonly int AutoOpenDoors = 4;\n        public static readonly int UnequipBeforeCast = 5;\n        public static readonly int AutoPotionEquip = 6;\n        public static readonly int BlockHealPoisoned = 7;\n        public static readonly int LoopingMacros = 8; // includes fors and macros running macros\n        public static readonly int UseOnceAgent = 9;\n        public static readonly int RestockAgent = 10;\n        public static readonly int SellAgent = 11;\n        public static readonly int BuyAgent = 12;\n        public static readonly int PotionHotkeys = 13;\n        public static readonly int RandomTargets = 14;\n        public static readonly int ClosestTargets = 15;\n        public static readonly int OverheadHealth = 16;\n        // These are reserved by Steam, not used in Razor\n        public static readonly int AutolootAgent = 17;\n        public static readonly int BoneCutterAgent = 18;\n        public static readonly int AdvancedMacros = 19;\n        public static readonly int AutoRemount = 20;\n        public static readonly int AutoBandage = 21;\n        public static readonly int EnemyTargetShare = 22;\n        public static readonly int FilterSeason = 23;\n        public static readonly int SpellTargetShare = 24;\n        public static readonly int HumanoidHealthChecks = 25;\n        public static readonly int SpeechJournalChecks = 26;\n\n        public static readonly int MaxBit = 26;\n    }\n\n    public abstract class Client\n    {\n        public static Client Instance;\n        public static bool IsOSI;\n\n        internal static void Init(bool isOSI)\n        {\n            IsOSI = isOSI;\n\n            if (isOSI)\n                Instance = new OSIClient();\n            else\n                Instance = new ClassicUOClient();\n        }\n\n        public const int WM_USER = 0x400;\n\n        public const int WM_COPYDATA = 0x4A;\n        public const int WM_UONETEVENT = WM_USER + 1;\n\n        private ulong m_Features = 0;\n\n        public bool AllowBit(int bit)\n        {\n            return (m_Features & (1U << bit)) == 0;\n        }\n\n        public void SetFeatures(ulong features)\n        {\n            m_Features = features;\n        }\n\n        public abstract DateTime ConnectionStart { get; }\n        public abstract IPAddress LastConnection { get; }\n        public abstract Process ClientProcess { get; }\n\n        public abstract bool ClientRunning { get; }\n\n        public abstract void SetMapWndHandle(Form mapWnd);\n\n        public abstract void RequestStatbarPatch(bool preAOS);\n\n        public abstract void SetCustomNotoHue(int hue);\n\n        public abstract void SetSmartCPU(bool enabled);\n\n        public abstract void SetGameSize(int x, int y);\n\n        public enum Loader_Error\n        {\n            SUCCESS = 0,\n            NO_OPEN_EXE,\n            NO_MAP_EXE,\n            NO_READ_EXE_DATA,\n\n            NO_RUN_EXE,\n            NO_ALLOC_MEM,\n\n            NO_WRITE,\n            NO_VPROTECT,\n            NO_READ,\n\n            UNKNOWN_ERROR = 99\n        };\n\n        public abstract Loader_Error LaunchClient(string client);\n\n        public abstract bool ClientEncrypted { get; set; }\n\n        public abstract bool ServerEncrypted { get; set; }\n\n        public abstract bool InstallHooks(IntPtr mainWindow);\n\n        public abstract void SetConnectionInfo(IPAddress addr, int port);\n\n        public abstract void SetNegotiate(bool negotiate);\n\n        public abstract bool Attach(int pid);\n\n        public abstract void Close();\n\n        public abstract void SetTitleStr(string str);\n\n        public abstract bool OnMessage(MainForm razor, uint wParam, int lParam);\n\n        public abstract bool OnCopyData(IntPtr wparam, IntPtr lparam);\n\n        public abstract void SendToServer(Packet p);\n\n        public abstract void SendToServer(PacketReader pr);\n\n        public abstract void SendToClient(Packet p);\n        public abstract void SendPacketToClient(byte[] packet, int length);\n\n        public abstract void ForceSendToClient(Packet p);\n\n        public abstract void ForceSendToServer(Packet p);\n\n        public abstract void SetPosition(uint x, uint y, uint z, byte dir);\n\n        public abstract string GetClientVersion();\n\n        public abstract string GetUoFilePath();\n\n        public abstract IntPtr GetWindowHandle();\n\n        public abstract uint TotalDataIn();\n\n        public abstract uint TotalDataOut();\n        internal abstract void RequestMove(Direction m_Dir);\n\n\n        public void RequestTitlebarUpdate()\n        {\n            // throttle updates, since things like counters might request 1000000 million updates/sec\n            if (m_TBTimer == null)\n                m_TBTimer = new TitleBarThrottle();\n\n            if (!m_TBTimer.Running)\n                m_TBTimer.Start();\n        }\n\n        private class TitleBarThrottle : Timer\n        {\n            public TitleBarThrottle() : base(TimeSpan.FromSeconds(0.25))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                Instance.UpdateTitleBar();\n            }\n        }\n\n        private Timer m_TBTimer;\n        public StringBuilder TitleBarBuilder = new StringBuilder();\n        private string m_LastPlayerName = \"\";\n\n        public void ResetTitleBarBuilder()\n        {\n            // reuse the same sb each time for less damn allocations\n            TitleBarBuilder.Remove(0, TitleBarBuilder.Length);\n            TitleBarBuilder.Insert(0, $\"{Config.GetString(\"TitleBarText\")}\");\n        }\n\n        public virtual void UpdateTitleBar()\n        {\n            if (!ClientRunning || World.Player == null)\n                return;\n\n            StringBuilder sb = TitleBarBuilder;\n\n            PlayerData p = World.Player;\n\n            if (p.Name != m_LastPlayerName)\n            {\n                m_LastPlayerName = p.Name;\n\n                Engine.MainWindow.UpdateTitle();\n            }\n\n            sb.Replace(@\"{shard}\", World.ShardName);\n\n            sb.Replace(@\"{str}\", p.Str.ToString());\n            sb.Replace(@\"{hpmax}\", p.HitsMax.ToString());\n\n            sb.Replace(@\"{dex}\", World.Player.Dex.ToString());\n            sb.Replace(@\"{stammax}\", World.Player.StamMax.ToString());\n\n            sb.Replace(@\"{int}\", World.Player.Int.ToString());\n            sb.Replace(@\"{manamax}\", World.Player.ManaMax.ToString());\n\n            sb.Replace(@\"{ar}\", p.AR.ToString());\n            sb.Replace(@\"{tithe}\", p.Tithe.ToString());\n\n            sb.Replace(@\"{physresist}\", p.AR.ToString());\n            sb.Replace(@\"{fireresist}\", p.FireResistance.ToString());\n            sb.Replace(@\"{coldresist}\", p.ColdResistance.ToString());\n            sb.Replace(@\"{poisonresist}\", p.PoisonResistance.ToString());\n            sb.Replace(@\"{energyresist}\", p.EnergyResistance.ToString());\n\n            sb.Replace(@\"{luck}\", p.Luck.ToString());\n\n            sb.Replace(@\"{damage}\", $\"{p.DamageMin}-{p.DamageMax}\");\n\n            sb.Replace(@\"{maxweight}\", World.Player.MaxWeight.ToString());\n\n            sb.Replace(@\"{followers}\", World.Player.Followers.ToString());\n            sb.Replace(@\"{followersmax}\", World.Player.FollowersMax.ToString());\n\n            sb.Replace(@\"{gold}\", World.Player.Gold.ToString());\n\n            sb.Replace(@\"{gps}\", GoldPerHourTimer.Running ? $\"{GoldPerHourTimer.GoldPerSecond:N2}\" : \"-\");\n            sb.Replace(@\"{gpm}\", GoldPerHourTimer.Running ? $\"{GoldPerHourTimer.GoldPerMinute:N2}\" : \"-\");\n            sb.Replace(@\"{gph}\", GoldPerHourTimer.Running ? $\"{GoldPerHourTimer.GoldPerHour:N2}\" : \"-\");\n            sb.Replace(@\"{goldtotal}\", GoldPerHourTimer.Running ? $\"{GoldPerHourTimer.GoldSinceStart}\" : \"-\");\n            sb.Replace(@\"{goldtotalmin}\", GoldPerHourTimer.Running ? $\"{GoldPerHourTimer.TotalMinutes:N2} min\" : \"-\");\n\n            sb.Replace(@\"{skill}\", SkillTimer.Running ? $\"{SkillTimer.Count}\" : \"-\");\n            sb.Replace(@\"{gate}\", GateTimer.Running ? $\"{GateTimer.Count}\" : \"-\");\n\n            sb.Replace(@\"{stealthsteps}\", StealthSteps.Counting ? StealthSteps.Count.ToString() : \"-\");\n            sb.Replace(@\"{uptime}\",\n                ConnectionStart != DateTime.MinValue\n                    ? Utility.FormatTime((int) ((DateTime.UtcNow - ConnectionStart).TotalSeconds))\n                    : \"-\");\n\n            sb.Replace(@\"{dps}\", DamageTracker.Running ? $\"{DamageTracker.DamagePerSecond:N2}\" : \"-\");\n            sb.Replace(@\"{maxdps}\", DamageTracker.Running ? $\"{DamageTracker.MaxDamagePerSecond:N2}\" : \"-\");\n            sb.Replace(@\"{maxdamagedealt}\", DamageTracker.Running ? $\"{DamageTracker.MaxSingleDamageDealt}\" : \"-\");\n            sb.Replace(@\"{maxdamagetaken}\", DamageTracker.Running ? $\"{DamageTracker.MaxSingleDamageTaken}\" : \"-\");\n            sb.Replace(@\"{totaldamagedealt}\", DamageTracker.Running ? $\"{DamageTracker.TotalDamageDealt}\" : \"-\");\n            sb.Replace(@\"{totaldamagetaken}\", DamageTracker.Running ? $\"{DamageTracker.TotalDamageTaken}\" : \"-\");\n\n            if (IsOSI)\n            {\n                if (World.Player.BuffsDebuffs.Count > 0)\n                {\n                    StringBuilder buffs = new StringBuilder();\n                    foreach (BuffDebuff buff in World.Player.BuffsDebuffs)\n                    {\n                        int timeLeft = 0;\n\n                        if (buff.Duration > 0)\n                        {\n                            TimeSpan diff = DateTime.UtcNow - buff.Timestamp;\n                            timeLeft = buff.Duration - (int)diff.TotalSeconds;\n                        }\n\n                        buffs.Append(timeLeft <= 0\n                            ? $\"{buff.ClilocMessage1}, \"\n                            : $\"{buff.ClilocMessage1} ({timeLeft}), \");\n                    }\n\n                    buffs.Length = Math.Max(0, buffs.Length - 2);\n                    string buffList = buffs.ToString();\n                    sb.Replace(@\"{buffsdebuffs}\", buffList);\n                }\n                else\n                {\n                    sb.Replace(@\"{buffsdebuffs}\", \"-\");\n                }\n            }\n\n            SetTitleStr(sb.ToString());\n        }\n\n        public Packet MakePacketFrom(PacketReader pr)\n        {\n            byte[] data = pr.CopyBytes(0, pr.Length);\n            return new Packet(data, pr.Length, pr.DynamicLength);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Client/OSI.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing Assistant.Core;\nusing System;\nusing System.Collections.Generic;\nusing System.Configuration;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Net;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading;\nusing System.Windows.Forms;\nusing Assistant.Scripts;\n\nnamespace Assistant\n{\n    public unsafe class OSIClient : Client\n    {\n        public enum UONetMessage\n        {\n            Send = 1,\n            Recv = 2,\n            Ready = 3,\n            NotReady = 4,\n            Connect = 5,\n            Disconnect = 6,\n            KeyDown = 7,\n            Mouse = 8,\n            Activate = 9,\n            Focus = 10,\n            Close = 11,\n            StatBar = 12,\n            NotoHue = 13,\n            DLL_Error = 14,\n            SetGameSize = 19,\n            SmartCPU = 21,\n            Negotiate = 22,\n            SetMapHWnd = 23,\n            OnTick = 24,\n        }\n\n        public enum UONetMessageCopyData\n        {\n            Position = 1,\n        }\n\n        private enum InitError\n        {\n            SUCCESS,\n            NO_UOWND,\n            NO_TID,\n            NO_HOOK,\n            NO_SHAREMEM,\n            LIB_DISABLED,\n            NO_PATCH,\n            NO_MEMCOPY,\n            INVALID_PARAMS,\n\n            UNKNOWN\n        }\n\n        private const int SHARED_BUFF_SIZE = 524288; // 262144; // 250k\n\n        [StructLayout(LayoutKind.Explicit, Size = 8 + SHARED_BUFF_SIZE)]\n        private struct Buffer\n        {\n            [FieldOffset(0)] public int Length;\n            [FieldOffset(4)] public int Start;\n            [FieldOffset(8)] public byte Buff0;\n        }\n\n        [DllImport(\"Crypt.dll\")]\n        private static unsafe extern int InstallLibrary(IntPtr thisWnd, int procid, int features);\n\n        [DllImport(\"Crypt.dll\")]\n        private static unsafe extern void Shutdown(bool closeClient);\n\n        [DllImport(\"Crypt.dll\")]\n        internal static unsafe extern IntPtr FindUOWindow();\n\n        [DllImport(\"Crypt.dll\")]\n        private static unsafe extern IntPtr GetSharedAddress();\n\n        [DllImport(\"Crypt.dll\")]\n        private static unsafe extern IntPtr GetCommMutex();\n\n        [DllImport(\"Crypt.dll\")]\n        internal static unsafe extern uint TotalIn();\n\n        [DllImport(\"Crypt.dll\")]\n        internal static unsafe extern uint TotalOut();\n\n        [DllImport(\"Crypt.dll\")]\n        private static unsafe extern void WaitForWindow(int pid);\n\n        [DllImport(\"Crypt.dll\")]\n        internal static unsafe extern void SetDataPath(string path);\n\n        [DllImport(\"Crypt.dll\")]\n        internal static unsafe extern void CalibratePosition(uint x, uint y, uint z, byte dir);\n\n        [DllImport(\"Crypt.dll\")]\n        private static unsafe extern void SetServer(uint ip, ushort port);\n\n        [DllImport(\"Crypt.dll\")]\n        internal static unsafe extern IntPtr GetUOVersion();\n\n        [DllImport(\"Loader.dll\")]\n        private static unsafe extern uint Load(string exe, string dll, string func, void* dllData, int dataLen,\n            out uint pid);\n\n        private Queue<Packet> m_SendQueue = new Queue<Packet>();\n        private Queue<Packet> m_RecvQueue = new Queue<Packet>();\n\n        private bool m_QueueRecv;\n        private bool m_QueueSend;\n\n        private Buffer* m_InRecv;\n        private Buffer* m_OutRecv;\n        private Buffer* m_InSend;\n        private Buffer* m_OutSend;\n        private byte* m_TitleStr;\n        private Mutex CommMutex;\n        private Process ClientProc;\n\n        private bool m_Ready = false;\n        private string m_LastStr = \"\";\n        private DateTime m_ConnStart;\n        private IPAddress m_LastConnection;\n\n        public override DateTime ConnectionStart\n        {\n            get { return m_ConnStart; }\n        }\n\n        public override IPAddress LastConnection\n        {\n            get { return m_LastConnection; }\n        }\n\n        public override Process ClientProcess\n        {\n            get { return ClientProc; }\n        }\n\n        public override bool ClientRunning\n        {\n            get\n            {\n                try\n                {\n                    return ClientProc != null && !ClientProc.HasExited;\n                }\n                catch\n                {\n                    return ClientProc != null && FindUOWindow() != IntPtr.Zero;\n                }\n            }\n        }\n\n        public override void SetMapWndHandle(Form mapWnd)\n        {\n            Platform.PostMessage(FindUOWindow(), WM_UONETEVENT, (IntPtr) UONetMessage.SetMapHWnd, mapWnd.Handle);\n        }\n\n        public override void RequestStatbarPatch(bool preAOS)\n        {\n            Platform.PostMessage(FindUOWindow(), WM_UONETEVENT, (IntPtr) UONetMessage.StatBar,\n                preAOS ? (IntPtr) 1 : IntPtr.Zero);\n        }\n\n        public override void SetCustomNotoHue(int hue)\n        {\n            Platform.PostMessage(FindUOWindow(), WM_UONETEVENT, (IntPtr) UONetMessage.NotoHue, (IntPtr) hue);\n        }\n\n        public override void SetSmartCPU(bool enabled)\n        {\n            if (enabled)\n                try\n                {\n                    ClientProcess.PriorityClass = System.Diagnostics.ProcessPriorityClass.Normal;\n                }\n                catch\n                {\n                }\n\n            Platform.PostMessage(FindUOWindow(), WM_UONETEVENT, (IntPtr) UONetMessage.SmartCPU,\n                (IntPtr) (enabled ? 1 : 0));\n        }\n\n        public override void SetGameSize(int x, int y)\n        {\n            Platform.PostMessage(FindUOWindow(), WM_UONETEVENT, (IntPtr) UONetMessage.SetGameSize,\n                (IntPtr) ((x & 0xFFFF) | ((y & 0xFFFF) << 16)));\n        }\n\n        public override Loader_Error LaunchClient(string client)\n        {\n            string dll = Path.Combine(Config.GetInstallDirectory(), \"Crypt.dll\");\n            uint pid = 0;\n            Loader_Error err = (Loader_Error) Load(client, dll, \"OnAttach\", null, 0, out pid);\n\n            if (err == Loader_Error.SUCCESS)\n            {\n                try\n                {\n                    ClientProc = Process.GetProcessById((int) pid);\n                }\n                catch\n                {\n                    // ignore\n                }\n            }\n\n            if (ClientProc == null)\n                return Loader_Error.UNKNOWN_ERROR;\n            else\n                return err;\n        }\n\n        private bool m_ClientEnc = false;\n\n        public override bool ClientEncrypted\n        {\n            get { return m_ClientEnc; }\n            set { m_ClientEnc = value; }\n        }\n\n        private bool m_ServerEnc = false;\n\n        public override bool ServerEncrypted\n        {\n            get { return m_ServerEnc; }\n            set { m_ServerEnc = value; }\n        }\n\n        public override bool InstallHooks(IntPtr mainWindow)\n        {\n            InitError error;\n            int flags = 0;\n\n            if (m_Ready)\n                return false; // double init\n\n            if (Config.GetBool(\"Negotiate\"))\n                flags |= 0x04;\n\n            if (ClientEncrypted)\n                flags |= 0x08;\n\n            if (ServerEncrypted)\n                flags |= 0x10;\n\n            WaitForWindow(ClientProc.Id);\n\n            error = (InitError) InstallLibrary(mainWindow, ClientProc.Id, flags);\n            if (error != InitError.SUCCESS)\n            {\n                FatalInit(error);\n                return false;\n            }\n\n            // When InstallLibrary finishes, we get a UONETEVENT saying it's ready.\n            return true;\n        }\n\n        private uint m_ServerIP;\n        private ushort m_ServerPort;\n\n        public override void SetConnectionInfo(IPAddress addr, int port)\n        {\n#pragma warning disable 618\n            m_ServerIP = (uint) addr.Address;\n#pragma warning restore 618\n            m_ServerPort = (ushort) port;\n        }\n\n        public override void SetNegotiate(bool negotiate)\n        {\n            Platform.PostMessage(FindUOWindow(), WM_UONETEVENT, (IntPtr) UONetMessage.Negotiate,\n                (IntPtr) (negotiate ? 1 : 0));\n        }\n\n        public override bool Attach(int pid)\n        {\n            ClientProc = null;\n            ClientProc = Process.GetProcessById(pid);\n            return ClientProc != null;\n        }\n\n        public override void Close()\n        {\n            Shutdown(true);\n            if (ClientProc != null && !ClientProc.HasExited)\n                ClientProc.CloseMainWindow();\n            ClientProc = null;\n        }\n\n        private string EncodeColorStat(int val, int max)\n        {\n            double perc = ((double) val) / ((double) max);\n\n            if (perc <= 0.25)\n                return $\"~#FF0000{val}~#~\";\n\n            if (perc <= 0.75)\n                return $\"~#FFFF00{val}~#~\";\n\n            return val.ToString();\n        }\n\n        public override void UpdateTitleBar()\n        {\n            if (!ClientRunning)\n                return;\n\n            if (World.Player != null && Config.GetBool(\"TitleBarDisplay\"))\n            {\n                ResetTitleBarBuilder();\n\n                TitleBarBuilder.Replace(@\"{char}\",\n                    Config.GetBool(\"ShowNotoHue\")\n                        ? $\"~#{World.Player.GetNotorietyColor() & 0x00FFFFFF:X6}{World.Player.Name}~#~\"\n                        : World.Player.Name);\n\n                TitleBarBuilder.Replace(@\"{crimtime}\",\n                    World.Player.CriminalTime != 0 ? $\"~^C0C0C0{World.Player.CriminalTime}~#~\" : \"-\");\n\n                TitleBarBuilder.Replace(@\"{hp}\",\n                    World.Player.Poisoned\n                        ? $\"~#FF8000{World.Player.Hits}~#~\"\n                        : EncodeColorStat(World.Player.Hits, World.Player.HitsMax));\n                TitleBarBuilder.Replace(@\"{mana}\", EncodeColorStat(World.Player.Mana, World.Player.ManaMax));\n                TitleBarBuilder.Replace(@\"{stam}\", EncodeColorStat(World.Player.Stam, World.Player.StamMax));\n\n                TitleBarBuilder.Replace(@\"{weight}\",\n                    World.Player.Weight >= World.Player.MaxWeight\n                        ? $\"~#FF0000{World.Player.Weight}~#~\"\n                        : World.Player.Weight.ToString());\n\n                TitleBarBuilder.Replace(@\"{bandage}\", BandageTimer.Running ? $\"~#FF8000{BandageTimer.Count}~#~\" : \"-\");\n\n                string statStr =\n                    $\"{(int) (World.Player.GetStatusCode())}{(int) (World.Player.HitsMax == 0 ? 0 : (double) World.Player.Hits / World.Player.HitsMax * 99):X2}{(int) (World.Player.ManaMax == 0 ? 0 : (double) World.Player.Mana / World.Player.ManaMax * 99):X2}{(int) (World.Player.StamMax == 0 ? 0 : (double) World.Player.Stam / World.Player.StamMax * 99):X2}\";\n\n                TitleBarBuilder.Replace(@\"{statbar}\", $\"~SR{statStr}\");\n                TitleBarBuilder.Replace(@\"{mediumstatbar}\", $\"~SL{statStr}\");\n                TitleBarBuilder.Replace(@\"{largestatbar}\", $\"~SX{statStr}\");\n\n                bool dispImg = Config.GetBool(\"TitlebarImages\");\n                for (int i = 0; i < Counter.List.Count; i++)\n                {\n                    Counter c = Counter.List[i];\n                    if (c.Enabled)\n                        TitleBarBuilder.Replace($\"{{{c.Format}}}\",\n                            c.GetTitlebarString(dispImg && c.DisplayImage, true));\n                }\n\n                base.UpdateTitleBar();\n            }\n            else\n            {\n                SetTitleStr(string.Empty);\n            }\n        }\n\n        private const int WM_CUSTOMTITLE = Client.WM_USER + 2;\n\n        public override void SetTitleStr(string str)\n        {\n            if (m_LastStr == str)\n                return;\n\n            m_LastStr = str;\n            byte[] copy = System.Text.Encoding.ASCII.GetBytes(str);\n            int clen = copy.Length;\n            if (clen >= 512)\n                clen = 511;\n\n            CommMutex.WaitOne();\n            if (clen > 0)\n            {\n                fixed (byte* array = copy)\n                    Platform.memcpy(m_TitleStr, array, clen);\n            }\n\n            *(m_TitleStr + clen) = 0;\n            CommMutex.ReleaseMutex();\n\n            Platform.PostMessage(FindUOWindow(), WM_CUSTOMTITLE, IntPtr.Zero, IntPtr.Zero);\n        }\n\n        private void FatalInit(InitError error)\n        {\n            StringBuilder sb = new StringBuilder(Language.GetString(LocString.InitError));\n            sb.AppendFormat(\"{0}\\n\", error);\n            sb.Append(Language.GetString((int) (LocString.InitError + (int) error)));\n\n            MessageBox.Show(Engine.ActiveWindow, sb.ToString(), \"Init Error\", MessageBoxButtons.OK,\n                MessageBoxIcon.Stop);\n        }\n\n        private void OnLogout(bool fake)\n        {\n            if (!fake)\n            {\n                PacketHandlers.Party.Clear();\n\n                SetTitleStr(\"\");\n                Engine.MainWindow.UpdateTitle();\n                UOAssist.PostLogout();\n                m_ConnStart = DateTime.MinValue;\n            }\n\n            World.Player = null;\n            World.Items.Clear();\n            World.Mobiles.Clear();\n            Macros.MacroManager.Stop();\n            ScriptManager.OnLogout();\n            ActionQueue.Stop();\n            Counter.Reset();\n            GoldPerHourTimer.Stop();\n            DamageTracker.Stop();\n            BandageTimer.Stop();\n            GateTimer.Stop();\n            WaypointManager.StopTimer();\n            BuffDebuffManager.Stop();\n            CooldownManager.Stop();\n            StealthSteps.Unhide();\n            Engine.MainWindow.OnLogout();\n            if (Engine.MainWindow.MapWindow != null)\n                Engine.MainWindow.MapWindow.Close();\n            PacketHandlers.Party.Clear();\n            PacketHandlers.IgnoreGumps.Clear();\n            Agents.BuyAgent.OnDisconnected();\n            Config.Save();\n\n            //TranslateEnabled = false;\n        }\n\n        //private DateTime m_LastActivate;\n        public override bool OnMessage(MainForm razor, uint wParam, int lParam)\n        {\n            bool retVal = true;\n\n            switch ((UONetMessage) (wParam & 0xFFFF))\n            {\n                case UONetMessage.Ready: //Patch status\n                    if (lParam == (int) InitError.NO_MEMCOPY)\n                    {\n                        if (MessageBox.Show(Engine.ActiveWindow, Language.GetString(LocString.NoMemCpy),\n                                \"No Client MemCopy\", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) ==\n                            DialogResult.No)\n                        {\n                            m_Ready = false;\n                            ClientProc = null;\n                            Engine.MainWindow.CanClose = true;\n                            Engine.MainWindow.Close();\n                            break;\n                        }\n                    }\n\n                    byte* baseAddr = (byte*) GetSharedAddress().ToPointer();\n\n                    m_InRecv = (Buffer*) baseAddr;\n                    m_OutRecv = (Buffer*) (baseAddr + sizeof(Buffer));\n                    m_InSend = (Buffer*) (baseAddr + sizeof(Buffer) * 2);\n                    m_OutSend = (Buffer*) (baseAddr + sizeof(Buffer) * 3);\n                    m_TitleStr = (byte*) (baseAddr + sizeof(Buffer) * 4);\n\n                    SetServer(m_ServerIP, m_ServerPort);\n\n                    CommMutex = new Mutex();\n#pragma warning disable 618\n                    CommMutex.Handle = GetCommMutex();\n#pragma warning restore 618\n\n                    try\n                    {\n                        string path = Ultima.Files.GetFilePath(\"art.mul\");\n                        if (path != null && path != string.Empty)\n                            SetDataPath(Path.GetDirectoryName(path));\n                        else\n                            SetDataPath(Path.GetDirectoryName(Ultima.Files.Directory));\n                    }\n                    catch\n                    {\n                        SetDataPath(\"\");\n                    }\n\n                    if (Config.GetBool(\"OldStatBar\"))\n                        RequestStatbarPatch(true);\n\n                    m_Ready = true;\n                    Engine.MainWindow.MainForm_EndLoad();\n                    break;\n\n                case UONetMessage.NotReady:\n                    m_Ready = false;\n                    FatalInit((InitError) lParam);\n                    ClientProc = null;\n                    Engine.MainWindow.CanClose = true;\n                    Engine.MainWindow.Close();\n                    break;\n\n                // Network events\n                case UONetMessage.Recv:\n                    OnRecv();\n                    break;\n                case UONetMessage.Send:\n                    OnSend();\n                    break;\n                case UONetMessage.Connect:\n                    m_ConnStart = DateTime.UtcNow;\n                    try\n                    {\n                        m_LastConnection = new IPAddress((uint) lParam);\n                    }\n                    catch\n                    {\n                    }\n\n                    break;\n                case UONetMessage.Disconnect:\n                    OnLogout(false);\n                    break;\n                case UONetMessage.Close:\n                    OnLogout(true);\n                    ClientProc = null;\n                    Engine.MainWindow.CanClose = true;\n                    Engine.MainWindow.Close();\n                    break;\n\n                // Hot Keys\n                case UONetMessage.Mouse:\n                    HotKey.OnMouse((ushort) (lParam & 0xFFFF), (short) (lParam >> 16));\n                    break;\n                case UONetMessage.KeyDown:\n                    retVal = HotKey.OnKeyDown(lParam, ModKeys.None);\n                    break;\n\n                // Activation Tracking\n                case UONetMessage.Activate:\n                    /*if ( Config.GetBool( \"AlwaysOnTop\" ) )\n                    {\n                        if ( (lParam&0x0000FFFF) == 0 && (lParam&0xFFFF0000) != 0 && razor.WindowState != FormWindowState.Minimized && razor.Visible )\n                        {// if uo is deactivating and minimized and we are not minimized\n                            if ( !razor.ShowInTaskbar && razor.Visible )\n                                razor.Hide();\n                            razor.WindowState = FormWindowState.Minimized;\n                            m_LastActivate = DateTime.UtcNow;\n                        }\n                        else if ( (lParam&0x0000FFFF) != 0 && (lParam&0xFFFF0000) != 0 && razor.WindowState != FormWindowState.Normal )\n                        { // is UO is activating and minimized and we are minimized\n                            if ( m_LastActivate+TimeSpan.FromSeconds( 0.2 ) < DateTime.UtcNow )\n                            {\n                                if ( !razor.ShowInTaskbar && !razor.Visible )\n                                    razor.Show();\n                                razor.WindowState = FormWindowState.Normal;\n                                //SetForegroundWindow( FindUOWindow() );\n                            }\n                            m_LastActivate = DateTime.UtcNow;\n                        }\n                    }*/\n                    break;\n\n                case UONetMessage.Focus:\n                    if (Config.GetBool(\"AlwaysOnTop\"))\n                    {\n                        if (lParam != 0 && !razor.TopMost)\n                        {\n                            razor.TopMost = true;\n                            Platform.SetForegroundWindow(FindUOWindow());\n                        }\n                        else if (lParam == 0 && razor.TopMost)\n                        {\n                            razor.TopMost = false;\n                            razor.SendToBack();\n                        }\n                    }\n\n                    // always use smartness for the map window\n                    if (razor.MapWindow != null && razor.MapWindow.Visible)\n                    {\n                        if (lParam != 0 && !razor.MapWindow.TopMost)\n                        {\n                            razor.MapWindow.TopMost = true;\n                            Platform.SetForegroundWindow(FindUOWindow());\n                        }\n                        else if (lParam == 0 && razor.MapWindow.TopMost)\n                        {\n                            razor.MapWindow.TopMost = false;\n                            razor.MapWindow.SendToBack();\n                        }\n                    }\n\n                    break;\n\n                case UONetMessage.DLL_Error:\n                {\n                    string error = \"Unknown\";\n                    switch ((UONetMessage) lParam)\n                    {\n                        case UONetMessage.StatBar:\n                            error = \"Unable to patch status bar.\";\n                            break;\n                    }\n\n                    MessageBox.Show(Engine.ActiveWindow, \"An Error has occured : \\n\" + error, \"Error Reported\",\n                        MessageBoxButtons.OK, MessageBoxIcon.Warning);\n                    break;\n                }\n\n                case UONetMessage.OnTick:\n                    // Game engine tick\n                    Timer.Slice();\n                    break;\n\n                // Unknown\n                default:\n                    MessageBox.Show(Engine.ActiveWindow, \"Unknown message from uo client\\n\" + ((int) wParam).ToString(),\n                        \"Error?\");\n                    break;\n            }\n\n            return retVal;\n        }\n\n        [StructLayout(LayoutKind.Sequential, Pack = 1)]\n        private struct CopyData\n        {\n            public int dwData;\n            public int cbDAta;\n            public IntPtr lpData;\n        };\n\n        [StructLayout(LayoutKind.Sequential, Pack = 1)]\n        private struct Position\n        {\n            public ushort x;\n            public ushort y;\n            public ushort z;\n        };\n\n        public override bool OnCopyData(IntPtr wparam, IntPtr lparam)\n        {\n            CopyData copydata = (CopyData) Marshal.PtrToStructure(lparam, typeof(CopyData));\n\n            switch ((UONetMessageCopyData) copydata.dwData)\n            {\n                case UONetMessageCopyData.Position:\n                    if (World.Player != null)\n                    {\n                        Position pos = (Position) Marshal.PtrToStructure(copydata.lpData, typeof(Position));\n                        Point3D pt = new Point3D();\n\n                        pt.X = pos.x;\n                        pt.Y = pos.y;\n                        pt.Z = pos.z;\n\n                        World.Player.Position = pt;\n                    }\n\n                    return true;\n            }\n\n            return false;\n        }\n\n        public override void SendToServer(Packet p)\n        {\n            if (!m_Ready)\n                return;\n\n            if (!m_QueueSend)\n            {\n                ForceSendToServer(p);\n            }\n            else\n            {\n                m_SendQueue.Enqueue(p);\n            }\n        }\n\n        public override void SendToServer(PacketReader pr)\n        {\n            if (!m_Ready)\n                return;\n\n            SendToServer(MakePacketFrom(pr));\n        }\n\n        public override void SendToClient(Packet p)\n        {\n            if (!m_Ready || p.Length <= 0)\n                return;\n\n            if (!m_QueueRecv)\n            {\n                ForceSendToClient(p);\n            }\n            else\n            {\n                m_RecvQueue.Enqueue(p);\n            }\n        }\n\n        public override void SendPacketToClient(byte[] packet, int length)\n        {\n            //_sendToClient(ref packet, ref length);\n        }\n\n        public override void ForceSendToClient(Packet p)\n        {\n            byte[] data = p.Compile();\n\n            CommMutex.WaitOne();\n            fixed (byte* ptr = data)\n            {\n                Packet.Log(PacketPath.RazorToClient, ptr, data.Length);\n                CopyToBuffer(m_OutRecv, ptr, data.Length);\n            }\n\n            CommMutex.ReleaseMutex();\n        }\n\n        public override void ForceSendToServer(Packet p)\n        {\n            if (p == null || p.Length <= 0)\n                return;\n\n            byte[] data = p.Compile();\n\n            CommMutex.WaitOne();\n            InitSendFlush();\n            fixed (byte* ptr = data)\n            {\n                Packet.Log(PacketPath.RazorToServer, ptr, data.Length);\n                CopyToBuffer(m_OutSend, ptr, data.Length);\n            }\n\n            CommMutex.ReleaseMutex();\n        }\n\n        private void InitSendFlush()\n        {\n            if (m_OutSend->Length == 0)\n                Platform.PostMessage(FindUOWindow(), WM_UONETEVENT, (IntPtr) UONetMessage.Send, IntPtr.Zero);\n        }\n\n        private void CopyToBuffer(Buffer* buffer, byte* data, int len)\n        {\n            //if ( buffer->Length + buffer->Start + len >= SHARED_BUFF_SIZE )\n            //\tthrow new NullReferenceException( String.Format( \"Buffer OVERFLOW in CopyToBuffer [{0} + {1}] <- {2}\", buffer->Start, buffer->Length, len ) );\n\n            Platform.memcpy((&buffer->Buff0) + buffer->Start + buffer->Length, data, len);\n            buffer->Length += len;\n        }\n\n        private void HandleComm(Buffer* inBuff, Buffer* outBuff, Queue<Packet> queue, PacketPath path)\n        {\n            CommMutex.WaitOne();\n            while (inBuff->Length > 0)\n            {\n                byte* buff = (&inBuff->Buff0) + inBuff->Start;\n\n                short len = PacketsTable.GetPacketLength(buff, inBuff->Length);\n                if (len > inBuff->Length || len <= 0)\n                    break;\n\n                inBuff->Start += len;\n                inBuff->Length -= len;\n\n                bool viewer = false;\n                bool filter = false;\n\n                switch (path)\n                {\n                    case PacketPath.ClientToServer:\n                        viewer = PacketHandler.HasClientViewer(buff[0]);\n                        filter = PacketHandler.HasClientFilter(buff[0]);\n                        break;\n                    case PacketPath.ServerToClient:\n                        viewer = PacketHandler.HasServerViewer(buff[0]);\n                        filter = PacketHandler.HasServerFilter(buff[0]);\n                        break;\n                }\n\n                Packet p = null;\n                PacketReader pr = null;\n                if (viewer)\n                {\n                    pr = new PacketReader(buff, len, PacketsTable.IsDynLength(buff[0]));\n                    if (filter)\n                        p = MakePacketFrom(pr);\n                }\n                else if (filter)\n                {\n                    byte[] temp = new byte[len];\n                    fixed (byte* ptr = temp)\n                        Platform.memcpy(ptr, buff, len);\n                    p = new Packet(temp, len, PacketsTable.IsDynLength(buff[0]));\n                }\n\n                bool blocked = false;\n                switch (path)\n                {\n                    // yes it should be this way\n                    case PacketPath.ClientToServer:\n                    {\n                        blocked = PacketHandler.OnClientPacket(buff[0], pr, p);\n                        break;\n                    }\n\n                    case PacketPath.ServerToClient:\n                    {\n                        blocked = PacketHandler.OnServerPacket(buff[0], pr, p);\n                        break;\n                    }\n                }\n\n                if (filter)\n                {\n                    byte[] data = p.Compile();\n                    fixed (byte* ptr = data)\n                    {\n                        Packet.Log(path, ptr, data.Length, blocked);\n                        if (!blocked)\n                            CopyToBuffer(outBuff, ptr, data.Length);\n                    }\n                }\n                else\n                {\n                    Packet.Log(path, buff, len, blocked);\n                    if (!blocked)\n                        CopyToBuffer(outBuff, buff, len);\n                }\n\n                while (queue.Count > 0)\n                {\n                    p = (Packet) queue.Dequeue();\n                    byte[] data = p.Compile();\n                    fixed (byte* ptr = data)\n                    {\n                        CopyToBuffer(outBuff, ptr, data.Length);\n                        Packet.Log((PacketPath) (((int) path) + 1), ptr, data.Length);\n                    }\n                }\n            }\n\n            CommMutex.ReleaseMutex();\n        }\n\n        private void OnRecv()\n        {\n            m_QueueRecv = true;\n            HandleComm(m_InRecv, m_OutRecv, m_RecvQueue, PacketPath.ServerToClient);\n            m_QueueRecv = false;\n        }\n\n        private void OnSend()\n        {\n            m_QueueSend = true;\n            HandleComm(m_InSend, m_OutSend, m_SendQueue, PacketPath.ClientToServer);\n            m_QueueSend = false;\n        }\n\n        public override void SetPosition(uint x, uint y, uint z, byte dir)\n        {\n            CalibratePosition(x, y, z, dir);\n        }\n\n        private static uint WM_KEYDOWN = 0x100, WM_KEYUP = 0x101;\n\n        public void KeyPress(int keyCode)\n        {\n            Platform.SendMessage(FindUOWindow(), WM_KEYDOWN, (IntPtr) keyCode, (IntPtr) 1);\n        }\n\n        public override string GetClientVersion()\n        {\n            return Marshal.PtrToStringAnsi(GetUOVersion());\n        }\n\n        public override string GetUoFilePath()\n        {\n            return Config.GetAppSetting<string>(\"UODataDir\");\n        }\n\n        public override IntPtr GetWindowHandle()\n        {\n            return FindUOWindow();\n        }\n\n        public override uint TotalDataIn()\n        {\n            return TotalIn();\n        }\n\n        public override uint TotalDataOut()\n        {\n            return TotalOut();\n        }\n\n        private enum KeyboardDir\n        {\n            North = 0x21, //page up\n            Right = 0x27, // right\n            East = 0x22, // page down\n            Down = 0x28, // down\n            South = 0x23, // end\n            Left = 0x25, // left\n            West = 0x24, // home\n            Up = 0x26, // up\n        }\n\n        internal override void RequestMove(Direction m_Dir)\n        {\n            int direction;\n\n            switch (m_Dir)\n            {\n                case Direction.Down:\n                    direction = (int) KeyboardDir.Down;\n                    break;\n                case Direction.East:\n                    direction = (int) KeyboardDir.East;\n                    break;\n                case Direction.Left:\n                    direction = (int) KeyboardDir.Left;\n                    break;\n                case Direction.North:\n                    direction = (int) KeyboardDir.North;\n                    break;\n                case Direction.Right:\n                    direction = (int) KeyboardDir.Right;\n                    break;\n                case Direction.South:\n                    direction = (int) KeyboardDir.South;\n                    break;\n                case Direction.Up:\n                    direction = (int) KeyboardDir.Up;\n                    break;\n                case Direction.West:\n                    direction = (int) KeyboardDir.West;\n                    break;\n                default:\n                    direction = (int) KeyboardDir.Up;\n                    break;\n            }\n\n            KeyPress(direction);\n        }\n    }\n};"
  },
  {
    "path": "Razor/Client/UOAssist.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Text;\nusing System.Runtime.InteropServices;\nusing Ultima;\n\nnamespace Assistant\n{\n    public unsafe sealed class UOAssist\n    {\n        public const int WM_USER = 0x400;\n\n        public enum UOAMessage\n        {\n            First = REGISTER,\n\n            //incoming:\n            REGISTER = WM_USER + 200,\n            COUNT_RESOURCES,\n            GET_COORDS,\n            GET_SKILL,\n            GET_STAT,\n            SET_MACRO,\n            PLAY_MACRO,\n            DISPLAY_TEXT,\n            REQUEST_MULTIS,\n            ADD_CMD,\n            GET_UID,\n            GET_SHARDNAME,\n            ADD_USER_2_PARTY,\n            GET_UO_HWND,\n            GET_POISON,\n            SET_SKILL_LOCK,\n            GET_ACCT_ID,\n\n            //outgoing:\n            RES_COUNT_DONE = WM_USER + 301,\n            CAST_SPELL,\n            LOGIN,\n            MAGERY_LEVEL,\n            INT_STATUS,\n            SKILL_LEVEL,\n            MACRO_DONE,\n            LOGOUT,\n            STR_STATUS,\n            DEX_STATUS,\n            ADD_MULTI,\n            REM_MULTI,\n            MAP_INFO,\n            POWERHOUR,\n\n            Last = POWERHOUR\n        }\n\n        private class WndCmd\n        {\n            public WndCmd(uint msg, IntPtr handle, string cmd)\n            {\n                Msg = msg;\n                hWnd = handle;\n                Command.Register(cmd, new CommandCallback(MyCallback));\n            }\n\n            private uint Msg;\n            private IntPtr hWnd;\n\n            private void MyCallback(string[] args)\n            {\n                StringBuilder sb = new StringBuilder();\n                for (int i = 0; i < args.Length; i++)\n                {\n                    if (i != 0)\n                        sb.Append(' ');\n                    sb.Append(args[i]);\n                }\n\n                string str = sb.ToString();\n                ushort atom = 0;\n                if (str != null && str.Length > 0)\n                    atom = GlobalAddAtom(str);\n                PostMessage(hWnd, Msg, (IntPtr) atom, IntPtr.Zero);\n            }\n        }\n\n        private class WndRegEnt\n        {\n            private int m_Handle;\n            private int m_Type; // 1 = get multi notifcations\n\n            public int Handle\n            {\n                get { return m_Handle; }\n            }\n\n            public int Type\n            {\n                get { return m_Type; }\n            }\n\n            public WndRegEnt(int hWnd, int type)\n            {\n                m_Handle = hWnd;\n                m_Type = type;\n            }\n        }\n\n        private static uint m_NextCmdID = WM_USER + 401;\n        private static ArrayList m_WndReg;\n\n        public static int NotificationCount\n        {\n            get { return m_WndReg.Count; }\n        }\n\n        static UOAssist()\n        {\n            m_WndReg = new ArrayList();\n        }\n\n        public static int OnUOAMessage(MainForm razor, int Msg, int wParam, int lParam)\n        {\n            switch ((UOAMessage) Msg)\n            {\n                case UOAMessage.REGISTER:\n                {\n                    for (int i = 0; i < m_WndReg.Count; i++)\n                    {\n                        if (((WndRegEnt) m_WndReg[i]).Handle == wParam)\n                        {\n                            m_WndReg.RemoveAt(i);\n                            return 2;\n                        }\n                    }\n\n                    m_WndReg.Add(new WndRegEnt(wParam, lParam == 1 ? 1 : 0));\n\n                    if (lParam == 1 && World.Items != null)\n                    {\n                        foreach (Item item in World.Items.Values)\n                        {\n                            if (item.ItemID >= 0x4000)\n                                PostMessage((IntPtr) wParam, (uint) UOAMessage.ADD_MULTI,\n                                    (IntPtr) ((int) ((item.Position.X & 0xFFFF) | ((item.Position.Y & 0xFFFF) << 16))),\n                                    (IntPtr) item.ItemID.Value);\n                        }\n                    }\n\n                    return 1;\n                }\n\n                case UOAMessage.COUNT_RESOURCES:\n                {\n                    Counter.FullRecount();\n                    return 0;\n                }\n\n                case UOAMessage.GET_COORDS:\n                {\n                    if (World.Player == null)\n                        return 0;\n                    return (World.Player.Position.X & 0xFFFF) | ((World.Player.Position.Y & 0xFFFF) << 16);\n                }\n\n                case UOAMessage.GET_SKILL:\n                {\n                    if (World.Player == null || lParam > 3 || wParam < 0 || World.Player.Skills == null ||\n                        wParam > World.Player.Skills.Length || lParam < 0)\n                        return 0;\n\n                    switch (lParam)\n                    {\n                        case 3:\n                        {\n                            try\n                            {\n                                return GlobalAddAtom(Skills.GetSkillDisplayName(wParam));\n                            }\n                            catch\n                            {\n                                return 0;\n                            }\n                        }\n\n                        case 2: return (int) (World.Player.Skills[wParam].Lock);\n                        case 1: return World.Player.Skills[wParam].FixedBase;\n                        case 0: return World.Player.Skills[wParam].FixedValue;\n                    }\n\n                    return 0;\n                }\n\n                case UOAMessage.GET_STAT:\n                {\n                    if (World.Player == null || wParam < 0 || wParam > 5)\n                        return 0;\n\n                    switch (wParam)\n                    {\n                        case 0: return World.Player.Str;\n                        case 1: return World.Player.Int;\n                        case 2: return World.Player.Dex;\n                        case 3: return World.Player.Weight;\n                        case 4: return World.Player.HitsMax;\n                        case 5: return World.Player.Tithe;\n                    }\n\n                    return 0;\n                }\n\n                case UOAMessage.SET_MACRO:\n                {\n                    try\n                    {\n                        //if ( wParam >= 0 && wParam < Engine.MainWindow.macroList.Items.Count )\n                        //\tEngine.MainWindow.macroList.SelectedIndex = wParam;\n                    }\n                    catch\n                    {\n                    }\n\n                    return 0;\n                }\n\n                case UOAMessage.PLAY_MACRO:\n                {\n                    if (razor != null)\n                        razor.playMacro_Click(razor, new EventArgs());\n                    return Macros.MacroManager.Playing ? 1 : 0;\n                }\n\n                case UOAMessage.DISPLAY_TEXT:\n                {\n                    if (World.Player == null)\n                        return 0;\n\n                    int hue = wParam & 0xFFFF;\n                    StringBuilder sb = new StringBuilder(256);\n                    if (GlobalGetAtomName((ushort) lParam, sb, 256) == 0)\n                        return 0;\n\n                    if ((wParam & 0x00010000) != 0)\n                        Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, hue, 3,\n                            Language.CliLocName, \"System\", sb.ToString()));\n                    else\n                        World.Player.OverheadMessage(hue, sb.ToString());\n                    GlobalDeleteAtom((ushort) lParam);\n                    return 1;\n                }\n\n                case UOAMessage.REQUEST_MULTIS:\n                {\n                    return World.Player != null ? 1 : 0;\n                }\n\n                case UOAMessage.ADD_CMD:\n                {\n                    StringBuilder sb = new StringBuilder(256);\n                    if (GlobalGetAtomName((ushort) lParam, sb, 256) == 0)\n                        return 0;\n\n                    if (wParam == 0)\n                    {\n                        Command.RemoveCommand(sb.ToString());\n                        return 0;\n                    }\n                    else\n                    {\n                        new WndCmd(m_NextCmdID, (IntPtr) wParam, sb.ToString());\n                        return (int) (m_NextCmdID++);\n                    }\n                }\n\n                case UOAMessage.GET_UID:\n                {\n                    return World.Player != null ? (int) World.Player.Serial.Value : 0;\n                }\n\n                case UOAMessage.GET_SHARDNAME:\n                {\n                    if (World.ShardName != null && World.ShardName.Length > 0)\n                        return GlobalAddAtom(World.ShardName);\n                    else\n                        return 0;\n                }\n\n                case UOAMessage.ADD_USER_2_PARTY:\n                {\n                    return 1; // not supported, return error\n                }\n\n                case UOAMessage.GET_UO_HWND:\n                {\n                    return Client.Instance.GetWindowHandle().ToInt32();\n                }\n\n                case UOAMessage.GET_POISON:\n                {\n                    return World.Player != null && World.Player.Poisoned ? 1 : 0;\n                }\n\n                case UOAMessage.SET_SKILL_LOCK:\n                {\n                    if (World.Player == null || wParam < 0 || wParam > World.Player.Skills.Length || lParam < 0 ||\n                        lParam >= 3)\n                        return 0;\n                    Client.Instance.SendToServer(new SetSkillLock(wParam, (LockType) lParam));\n                    return 1;\n                }\n\n                case UOAMessage.GET_ACCT_ID:\n                {\n                    // free shards don't use account ids... so just return the player's serial number\n                    return World.Player == null ? 0 : (int) World.Player.Serial.Value;\n                }\n\n                default:\n                {\n                    return 0;\n                }\n            }\n        }\n\n        public static void PostCounterUpdate(int counter, int count)\n        {\n            PostToWndReg((uint) UOAMessage.RES_COUNT_DONE, (IntPtr) counter, (IntPtr) count);\n        }\n\n        public static void PostSpellCast(int spell)\n        {\n            PostToWndReg((uint) UOAMessage.CAST_SPELL, (IntPtr) spell, IntPtr.Zero);\n        }\n\n        public static void PostLogin(int serial)\n        {\n            PostToWndReg((uint) UOAMessage.LOGIN, (IntPtr) serial, IntPtr.Zero);\n        }\n\n        public static void PostLogout()\n        {\n            for (int i = 0; i < m_WndReg.Count; i++)\n                PostMessage((IntPtr) ((WndRegEnt) m_WndReg[i]).Handle, (uint) UOAMessage.LOGOUT, IntPtr.Zero,\n                    IntPtr.Zero);\n        }\n\n        public static void PostMacroStop()\n        {\n            PostToWndReg((uint) UOAMessage.MACRO_DONE, IntPtr.Zero, IntPtr.Zero);\n        }\n\n        public static void PostMapChange(int map)\n        {\n            PostToWndReg((uint) UOAMessage.MAP_INFO, (IntPtr) map, IntPtr.Zero);\n        }\n\n        public static void PostSkillUpdate(int skill, int val)\n        {\n            PostToWndReg((uint) UOAMessage.SKILL_LEVEL, (IntPtr) skill, (IntPtr) val);\n            if (skill == Skills.MageryIndex)\n                PostToWndReg((uint) UOAMessage.MAGERY_LEVEL, (IntPtr) ((int) (val / 10)), (IntPtr) (val % 10));\n        }\n\n        public static void PostRemoveMulti(Item item)\n        {\n            if (item == null)\n                return;\n\n            IntPtr pos = (IntPtr) ((int) ((item.Position.X & 0xFFFF) | ((item.Position.Y & 0xFFFF) << 16)));\n\n            if (pos == IntPtr.Zero)\n                return;\n\n            for (int i = 0; i < m_WndReg.Count; i++)\n            {\n                WndRegEnt wnd = (WndRegEnt) m_WndReg[i];\n                if (wnd.Type == 1)\n                    PostMessage((IntPtr) wnd.Handle, (uint) UOAMessage.REM_MULTI, pos, (IntPtr) item.ItemID.Value);\n            }\n        }\n\n        public static void PostAddMulti(ItemID iid, Point3D Position)\n        {\n            IntPtr pos = (IntPtr) ((int) ((Position.X & 0xFFFF) | ((Position.Y & 0xFFFF) << 16)));\n\n            if (pos == IntPtr.Zero)\n                return;\n\n            for (int i = 0; i < m_WndReg.Count; i++)\n            {\n                WndRegEnt wnd = (WndRegEnt) m_WndReg[i];\n                if (wnd.Type == 1)\n                    PostMessage((IntPtr) wnd.Handle, (uint) UOAMessage.ADD_MULTI, pos, (IntPtr) iid.Value);\n            }\n        }\n\n        public static void PostHitsUpdate()\n        {\n            if (World.Player != null)\n                PostToWndReg((uint) UOAMessage.STR_STATUS, (IntPtr) World.Player.HitsMax, (IntPtr) World.Player.Hits);\n        }\n\n        public static void PostManaUpdate()\n        {\n            if (World.Player != null)\n                PostToWndReg((uint) UOAMessage.INT_STATUS, (IntPtr) World.Player.ManaMax, (IntPtr) World.Player.Mana);\n        }\n\n        public static void PostStamUpdate()\n        {\n            if (World.Player != null)\n                PostToWndReg((uint) UOAMessage.DEX_STATUS, (IntPtr) World.Player.StamMax, (IntPtr) World.Player.Stam);\n        }\n\n        private static void PostToWndReg(uint Msg, IntPtr wParam, IntPtr lParam)\n        {\n            ArrayList rem = null;\n            for (int i = 0; i < m_WndReg.Count; i++)\n            {\n                if (PostMessage((IntPtr) ((WndRegEnt) m_WndReg[i]).Handle, Msg, wParam, lParam) == 0)\n                {\n                    if (rem == null)\n                        rem = new ArrayList(1);\n                    rem.Add(m_WndReg[i]);\n                }\n            }\n\n            if (rem != null)\n            {\n                for (int i = 0; i < rem.Count; i++)\n                    m_WndReg.Remove(rem[i]);\n            }\n        }\n\n        [DllImport(\"user32.dll\")]\n        internal static extern uint PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);\n\n        [DllImport(\"kernel32.dll\")]\n        private static extern ushort GlobalAddAtom(string str);\n\n        [DllImport(\"kernel32.dll\")]\n        private static extern ushort GlobalDeleteAtom(ushort atom);\n\n        [DllImport(\"kernel32.dll\")]\n        private static extern uint GlobalGetAtomName(ushort atom, StringBuilder buff, int bufLen);\n    }\n}"
  },
  {
    "path": "Razor/Core/ActionQueue.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing Assistant.Agents;\r\n\r\nnamespace Assistant\r\n{\r\n    public delegate void DropDoneCallback(Serial iser, Serial dser, Point3D newPos);\r\n\r\n    public class DragDropManager\r\n    {\r\n        public enum ProcStatus\r\n        {\r\n            Nothing,\r\n            Success,\r\n            KeepWaiting,\r\n            ReQueue\r\n        }\r\n\r\n        public static bool Debug = false;\r\n\r\n        private static void Log(string str, params object[] args)\r\n        {\r\n            if (Debug)\r\n            {\r\n                try\r\n                {\r\n                    using (StreamWriter w = new StreamWriter(\"DragDrop.log\", true))\r\n                    {\r\n                        w.Write(Engine.MistedDateTime.ToString(\"HH:mm:ss.fff\"));\r\n                        w.Write(\":: \");\r\n                        w.WriteLine(str, args);\r\n                        w.Flush();\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        private class LiftReq\r\n        {\r\n            private static int NextID = 1;\r\n\r\n            public LiftReq(Serial s, int a, bool cli, bool last)\r\n            {\r\n                Serial = s;\r\n                Amount = a;\r\n                FromClient = cli;\r\n                DoLast = last;\r\n                Id = NextID++;\r\n            }\r\n\r\n            public readonly Serial Serial;\r\n            public readonly int Amount;\r\n            public readonly int Id;\r\n            public readonly bool FromClient;\r\n            public readonly bool DoLast;\r\n\r\n            public override string ToString()\r\n            {\r\n                return String.Format(\"{2}({0},{1},{3},{4})\", Serial, Amount, Id, FromClient, DoLast);\r\n            }\r\n        }\r\n\r\n        private class DropReq\r\n        {\r\n            public DropReq(Serial s, Point3D pt)\r\n            {\r\n                Serial = s;\r\n                Point = pt;\r\n            }\r\n\r\n            public DropReq(Serial s, Layer layer)\r\n            {\r\n                Serial = s;\r\n                Layer = layer;\r\n            }\r\n\r\n            public Serial Serial;\r\n            public readonly Point3D Point;\r\n            public readonly Layer Layer;\r\n        }\r\n\r\n        public static void Initialize()\r\n        {\r\n            try\r\n            {\r\n                File.Delete(\"DragDrop.log\");\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            HotKey.Add(HKCategory.Misc, LocString.DropCur, new HotKeyCallback(DropCurrent));\r\n        }\r\n\r\n        public static void DropCurrent()\r\n        {\r\n            Log(\"Drop current requested on {0}\", m_Holding);\r\n\r\n            if (m_Holding.IsItem)\r\n            {\r\n                if (World.Player.Backpack != null)\r\n                    Client.Instance.SendToServer(new DropRequest(m_Holding, Point3D.MinusOne,\r\n                        World.Player.Backpack.Serial));\r\n                else\r\n                    Client.Instance.SendToServer(new DropRequest(m_Holding, World.Player.Position, Serial.Zero));\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.NoHold);\r\n            }\r\n\r\n            Clear();\r\n        }\r\n\r\n        private static int m_LastID;\r\n\r\n        private static Serial m_Pending, m_Holding;\r\n        private static Item m_HoldingItem;\r\n        private static bool m_ClientLiftReq = false;\r\n        private static DateTime m_Lifted = DateTime.MinValue;\r\n\r\n        private static readonly Dictionary<Serial, Queue<DropReq>>\r\n            m_DropReqs = new Dictionary<Serial, Queue<DropReq>>();\r\n\r\n        private static readonly LiftReq[] m_LiftReqs = new LiftReq[256];\r\n        private static byte m_Front, m_Back;\r\n\r\n        public static Item Holding\r\n        {\r\n            get { return m_HoldingItem; }\r\n        }\r\n\r\n        public static Serial Pending\r\n        {\r\n            get { return m_Pending; }\r\n        }\r\n\r\n        public static int LastIDLifted\r\n        {\r\n            get { return m_LastID; }\r\n        }\r\n\r\n        public static void Clear()\r\n        {\r\n            Log(\"Clearing....\");\r\n\r\n            m_DropReqs.Clear();\r\n            for (int i = 0; i < 256; i++)\r\n                m_LiftReqs[i] = null;\r\n            m_Front = m_Back = 0;\r\n            m_Holding = m_Pending = Serial.Zero;\r\n            m_HoldingItem = null;\r\n            m_Lifted = DateTime.MinValue;\r\n        }\r\n\r\n        public static void DragDrop(Item i, Serial to)\r\n        {\r\n            Drag(i, i.Amount);\r\n            Drop(i, to, Point3D.MinusOne);\r\n        }\r\n\r\n        public static void DragDrop(Item i, Item to)\r\n        {\r\n            Drag(i, i.Amount);\r\n            Drop(i, to.Serial, Point3D.MinusOne);\r\n        }\r\n\r\n        public static void DragDrop(Item i, Point3D dest)\r\n        {\r\n            Drag(i, i.Amount);\r\n            Drop(i, Serial.MinusOne, dest);\r\n        }\r\n\r\n        public static void DragDrop(Item i, int amount, Item to)\r\n        {\r\n            Drag(i, amount);\r\n            Drop(i, to.Serial, Point3D.MinusOne);\r\n        }\r\n\r\n        public static void DragDrop(Item i, Mobile to, Layer layer, bool doLast)\r\n        {\r\n            Drag(i, i.Amount, false, doLast);\r\n            Drop(i, to, layer);\r\n        }\r\n\r\n        public static void DragDrop(Item i, Mobile to, Layer layer)\r\n        {\r\n            Drag(i, i.Amount, false);\r\n            Drop(i, to, layer);\r\n        }\r\n\r\n        public static int Drag(Item i, int amount, bool fromClient)\r\n        {\r\n            return Drag(i, amount, fromClient, false);\r\n        }\r\n\r\n        public static int Drag(Item i, int amount)\r\n        {\r\n            return Drag(i, amount, false, false);\r\n        }\r\n\r\n        public static bool Empty\r\n        {\r\n            get { return m_Back == m_Front; }\r\n        }\r\n\r\n        public static bool Full\r\n        {\r\n            get { return ((byte) (m_Back + 1)) == m_Front; }\r\n        }\r\n\r\n        public static int Drag(Item i, int amount, bool fromClient, bool doLast)\r\n        {\r\n            LiftReq lr = new LiftReq(i.Serial, amount, fromClient, doLast);\r\n            LiftReq prev = null;\r\n\r\n            if (Full)\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, LocString.DragDropQueueFull);\r\n                if (fromClient)\r\n                    Client.Instance.SendToClient(new LiftRej());\r\n                return 0;\r\n            }\r\n\r\n            Log(\"Queuing Drag request {0}\", lr);\r\n\r\n            if (m_Back >= m_LiftReqs.Length)\r\n                m_Back = 0;\r\n\r\n            if (m_Back <= 0)\r\n                prev = m_LiftReqs[m_LiftReqs.Length - 1];\r\n            else if (m_Back <= m_LiftReqs.Length)\r\n                prev = m_LiftReqs[m_Back - 1];\r\n\r\n            // if the current last req must stay last, then insert this one in its place\r\n            if (prev != null && prev.DoLast)\r\n            {\r\n                Log(\"Back-Queuing {0}\", prev);\r\n                if (m_Back <= 0)\r\n                    m_LiftReqs[m_LiftReqs.Length - 1] = lr;\r\n                else if (m_Back <= m_LiftReqs.Length)\r\n                    m_LiftReqs[m_Back - 1] = lr;\r\n\r\n                // and then re-insert it at the end\r\n                lr = prev;\r\n            }\r\n\r\n            m_LiftReqs[m_Back++] = lr;\r\n\r\n            ActionQueue.SignalLift(!fromClient);\r\n            return lr.Id;\r\n        }\r\n\r\n        public static bool Drop(Item i, Mobile to, Layer layer)\r\n        {\r\n            if (m_Pending == i.Serial)\r\n            {\r\n                Log(\"Equipping {0} to {1} (@{2})\", i, to.Serial, layer);\r\n                Client.Instance.SendToServer(new EquipRequest(i.Serial, to, layer));\r\n                m_Pending = Serial.Zero;\r\n                EndHolding(i.Serial);\r\n                m_Lifted = DateTime.MinValue;\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                bool add = false;\r\n\r\n                for (byte j = m_Front; j != m_Back && !add; j++)\r\n                {\r\n                    if (m_LiftReqs[j] != null && m_LiftReqs[j].Serial == i.Serial)\r\n                    {\r\n                        add = true;\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                if (add)\r\n                {\r\n                    Log(\"Queuing Equip {0} to {1} (@{2})\", i, to.Serial, layer);\r\n\r\n                    if (!m_DropReqs.TryGetValue(i.Serial, out var q) || q == null)\r\n                        m_DropReqs[i.Serial] = q = new Queue<DropReq>();\r\n\r\n                    q.Enqueue(new DropReq(to == null ? Serial.Zero : to.Serial, layer));\r\n                    return true;\r\n                }\r\n                else\r\n                {\r\n                    Log(\"Drop/Equip for {0} (to {1} (@{2})) not found, skipped\", i,\r\n                        to == null ? Serial.Zero : to.Serial, layer);\r\n                    return false;\r\n                }\r\n            }\r\n        }\r\n\r\n        public static bool Drop(Item i, Serial dest, Point3D pt)\r\n        {\r\n            if (m_Pending == i.Serial)\r\n            {\r\n                Log(\"Dropping {0} to {1} (@{2})\", i, dest, pt);\r\n\r\n                Client.Instance.SendToServer(new DropRequest(i.Serial, pt, dest));\r\n                m_Pending = Serial.Zero;\r\n                EndHolding(i.Serial);\r\n                m_Lifted = DateTime.MinValue;\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                bool add = false;\r\n\r\n                for (byte j = m_Front; j != m_Back && !add; j++)\r\n                {\r\n                    if (m_LiftReqs[j] != null && m_LiftReqs[j].Serial == i.Serial)\r\n                    {\r\n                        add = true;\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                if (add)\r\n                {\r\n                    Log(\"Queuing Drop {0} (to {1} (@{2}))\", i, dest, pt);\r\n\r\n                    if (!m_DropReqs.TryGetValue(i.Serial, out var q) || q == null)\r\n                        m_DropReqs[i.Serial] = q = new Queue<DropReq>();\r\n\r\n                    q.Enqueue(new DropReq(dest, pt));\r\n                    return true;\r\n                }\r\n                else\r\n                {\r\n                    Log(\"Drop for {0} (to {1} (@{2})) not found, skipped\", i, dest, pt);\r\n                    return false;\r\n                }\r\n            }\r\n        }\r\n\r\n        public static bool Drop(Item i, Item to, Point3D pt)\r\n        {\r\n            return Drop(i, to == null ? Serial.MinusOne : to.Serial, pt);\r\n        }\r\n\r\n        public static bool Drop(Item i, Item to)\r\n        {\r\n            return Drop(i, to.Serial, Point3D.MinusOne);\r\n        }\r\n\r\n        public static bool LiftReject()\r\n        {\r\n            Log(\"Server rejected lift for item {0}\", m_Holding);\r\n            if (m_Holding == Serial.Zero)\r\n                return true;\r\n\r\n            m_Holding = m_Pending = Serial.Zero;\r\n            m_HoldingItem = null;\r\n            m_Lifted = DateTime.MinValue;\r\n\r\n            return m_ClientLiftReq;\r\n        }\r\n\r\n        public static bool HasDragFor(Serial s)\r\n        {\r\n            for (byte j = m_Front; j != m_Back; j++)\r\n            {\r\n                if (m_LiftReqs[j] != null && m_LiftReqs[j].Serial == s)\r\n                    return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public static bool CancelDragFor(Serial s)\r\n        {\r\n            if (Empty)\r\n                return false;\r\n\r\n            int skip = 0;\r\n            for (byte j = m_Front; j != m_Back; j++)\r\n            {\r\n                if (skip == 0 && m_LiftReqs[j] != null && m_LiftReqs[j].Serial == s)\r\n                {\r\n                    m_LiftReqs[j] = null;\r\n                    skip++;\r\n                    if (j == m_Front)\r\n                    {\r\n                        m_Front++;\r\n                        break;\r\n                    }\r\n                    else\r\n                    {\r\n                        m_Back--;\r\n                    }\r\n                }\r\n\r\n                if (skip > 0)\r\n                    m_LiftReqs[j] = m_LiftReqs[(byte) (j + skip)];\r\n            }\r\n\r\n            if (skip > 0)\r\n            {\r\n                m_LiftReqs[m_Back] = null;\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static bool EndHolding(Serial s)\r\n        {\r\n            //if ( m_Pending == s )\r\n            //\treturn false;\r\n\r\n            if (m_Holding == s)\r\n            {\r\n                m_Holding = Serial.Zero;\r\n                m_HoldingItem = null;\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        private static DropReq DequeueDropFor(Serial s)\r\n        {\r\n            DropReq dr = null;\r\n            if (m_DropReqs.TryGetValue(s, out var q) && q != null)\r\n            {\r\n                if (q.Count > 0)\r\n                    dr = q.Dequeue();\r\n                if (q.Count <= 0)\r\n                    m_DropReqs.Remove(s);\r\n            }\r\n\r\n            return dr;\r\n        }\r\n\r\n        public static void GracefulStop()\r\n        {\r\n            m_Front = m_Back = 0;\r\n\r\n            if (m_Pending.IsValid)\r\n            {\r\n                m_DropReqs.TryGetValue(m_Pending, out var q);\r\n                m_DropReqs.Clear();\r\n                m_DropReqs[m_Pending] = q;\r\n            }\r\n        }\r\n\r\n        public static ProcStatus ProcessNext(int numPending)\r\n        {\r\n            if (m_Pending != Serial.Zero)\r\n            {\r\n                if (m_Lifted + TimeSpan.FromMinutes(2) < DateTime.UtcNow)\r\n                {\r\n                    Item i = World.FindItem(m_Pending);\r\n\r\n                    Log(\"Lift timeout, forced drop to pack for {0}\", m_Pending);\r\n\r\n                    if (World.Player != null)\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Force, LocString.ForceEndHolding);\r\n\r\n                        if (World.Player.Backpack != null)\r\n                            Client.Instance.SendToServer(new DropRequest(m_Pending, Point3D.MinusOne,\r\n                                World.Player.Backpack.Serial));\r\n                        else\r\n                            Client.Instance.SendToServer(new DropRequest(m_Pending, World.Player.Position,\r\n                                Serial.Zero));\r\n                    }\r\n\r\n                    m_Holding = m_Pending = Serial.Zero;\r\n                    m_HoldingItem = null;\r\n                    m_Lifted = DateTime.MinValue;\r\n                }\r\n                else\r\n                {\r\n                    return ProcStatus.KeepWaiting;\r\n                }\r\n            }\r\n\r\n            if (m_Front == m_Back)\r\n            {\r\n                m_Front = m_Back = 0;\r\n                return ProcStatus.Nothing;\r\n            }\r\n\r\n            LiftReq lr = m_LiftReqs[m_Front];\r\n\r\n            if (numPending > 0 && lr != null && lr.DoLast)\r\n                return ProcStatus.ReQueue;\r\n\r\n            m_LiftReqs[m_Front] = null;\r\n            m_Front++;\r\n            if (lr != null)\r\n            {\r\n                Log(\"Lifting {0}\", lr);\r\n\r\n                Item item = World.FindItem(lr.Serial);\r\n                if (item != null && item.Container == null)\r\n                {\r\n                    // if the item is on the ground and out of range then dont grab it\r\n                    if (Utility.Distance(item.GetWorldPosition(), World.Player.Position) > 3)\r\n                    {\r\n                        Log(\"Item is too far away... uncaching.\");\r\n                        ScavengerAgent.Instance.Uncache(item.Serial);\r\n                        return ProcStatus.Nothing;\r\n                    }\r\n                }\r\n\r\n                Client.Instance.SendToServer(new LiftRequest(lr.Serial, lr.Amount));\r\n\r\n                m_LastID = lr.Id;\r\n                m_Holding = lr.Serial;\r\n                m_HoldingItem = World.FindItem(lr.Serial);\r\n                m_ClientLiftReq = lr.FromClient;\r\n\r\n                DropReq dr = DequeueDropFor(lr.Serial);\r\n                if (dr != null)\r\n                {\r\n                    m_Pending = Serial.Zero;\r\n                    EndHolding(lr.Serial);\r\n                    m_Lifted = DateTime.MinValue;\r\n\r\n                    Log(\"Dropping {0} to {1}\", lr, dr.Serial);\r\n\r\n                    if (dr.Serial.IsMobile && dr.Layer > Layer.Invalid && dr.Layer <= Layer.LastUserValid)\r\n                        Client.Instance.SendToServer(new EquipRequest(lr.Serial, dr.Serial, dr.Layer));\r\n                    else\r\n                        Client.Instance.SendToServer(new DropRequest(lr.Serial, dr.Point, dr.Serial));\r\n                }\r\n                else\r\n                {\r\n                    m_Pending = lr.Serial;\r\n                    m_Lifted = DateTime.UtcNow;\r\n                }\r\n\r\n                return ProcStatus.Success;\r\n            }\r\n            else\r\n            {\r\n                Log(\"No lift to be done?!\");\r\n                return ProcStatus.Nothing;\r\n            }\r\n        }\r\n    }\r\n\r\n    public class ActionQueue\r\n    {\r\n        private static Serial m_Last = Serial.Zero;\r\n        private static readonly Queue m_Queue = new Queue();\r\n        private static readonly ProcTimer m_Timer = new ProcTimer();\r\n        private static int m_Total = 0;\r\n\r\n        public static void DoubleClick(bool silent, Serial s)\r\n        {\r\n            if (s != Serial.Zero)\r\n            {\r\n                if (m_Last != s)\r\n                {\r\n                    m_Queue.Enqueue(s);\r\n                    m_Last = s;\r\n                    m_Total++;\r\n                    if (m_Queue.Count == 1 && !m_Timer.Running)\r\n                        m_Timer.StartMe();\r\n                    else if (!silent && m_Total > 1)\r\n                        World.Player.SendMessage(LocString.ActQueued, m_Queue.Count, TimeLeft);\r\n                }\r\n                else if (!silent)\r\n                {\r\n                    World.Player.SendMessage(LocString.QueueIgnore);\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void SignalLift(bool silent)\r\n        {\r\n            m_Queue.Enqueue(Serial.Zero);\r\n            m_Total++;\r\n            if ( /*m_Queue.Count == 1 &&*/ !m_Timer.Running)\r\n                m_Timer.StartMe();\r\n            else if (!silent && m_Total > 1)\r\n                World.Player.SendMessage(LocString.LiftQueued, m_Queue.Count, TimeLeft);\r\n        }\r\n\r\n        public static void Stop()\r\n        {\r\n            if (m_Timer != null && m_Timer.Running)\r\n                m_Timer.Stop();\r\n            m_Queue.Clear();\r\n            DragDropManager.Clear();\r\n        }\r\n\r\n        public static bool Empty\r\n        {\r\n            get { return m_Queue.Count <= 0 && !m_Timer.Running; }\r\n        }\r\n\r\n        public static string TimeLeft\r\n        {\r\n            get\r\n            {\r\n                if (m_Timer.Running)\r\n                {\r\n                    //Config.GetBool(\"ObjectDelayEnabled\")\r\n                    //double time = Config.GetInt( \"ObjectDelay\" ) / 1000.0;\r\n\r\n                    double time = Config.GetInt(\"ObjectDelay\") / 1000.0;\r\n\r\n                    if (!Config.GetBool(\"ObjectDelayEnabled\"))\r\n                    {\r\n                        time = 0;\r\n                    }\r\n\r\n                    double init = 0;\r\n                    if (m_Timer.LastTick != DateTime.MinValue)\r\n                        init = time - (DateTime.UtcNow - m_Timer.LastTick).TotalSeconds;\r\n                    time = init + time * m_Queue.Count;\r\n                    if (time < 0)\r\n                        time = 0;\r\n                    return $\"{time:F1} seconds\";\r\n                }\r\n                else\r\n                {\r\n                    return \"0.0 seconds\";\r\n                }\r\n            }\r\n        }\r\n\r\n        private class ProcTimer : Timer\r\n        {\r\n            private DateTime m_StartTime;\r\n            private DateTime m_LastTick;\r\n\r\n            public DateTime LastTick\r\n            {\r\n                get { return m_LastTick; }\r\n            }\r\n\r\n            public ProcTimer() : base(TimeSpan.Zero, TimeSpan.Zero)\r\n            {\r\n            }\r\n\r\n            public void StartMe()\r\n            {\r\n                m_LastTick = DateTime.UtcNow;\r\n                m_StartTime = DateTime.UtcNow;\r\n\r\n                OnTick();\r\n\r\n                Delay = Interval;\r\n\r\n                Start();\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                ArrayList requeue = null;\r\n\r\n                m_LastTick = DateTime.UtcNow;\r\n\r\n                if (m_Queue != null && m_Queue.Count > 0)\r\n                {\r\n                    this.Interval =\r\n                        TimeSpan.FromMilliseconds(Config.GetBool(\"ObjectDelayEnabled\")\r\n                            ? Config.GetInt(\"ObjectDelay\")\r\n                            : 0);\r\n\r\n                    //this.Interval = TimeSpan.FromMilliseconds( Config.GetInt( \"ObjectDelay\" ) );\r\n\r\n                    while (m_Queue.Count > 0)\r\n                    {\r\n                        Serial s = (Serial) m_Queue.Peek();\r\n                        if (s == Serial.Zero) // dragdrop action\r\n                        {\r\n                            DragDropManager.ProcStatus status = DragDropManager.ProcessNext(m_Queue.Count - 1);\r\n                            if (status != DragDropManager.ProcStatus.KeepWaiting)\r\n                            {\r\n                                m_Queue.Dequeue(); // if not waiting then dequeue it\r\n\r\n                                if (status == DragDropManager.ProcStatus.ReQueue)\r\n                                    m_Queue.Enqueue(s);\r\n                            }\r\n\r\n                            if (status == DragDropManager.ProcStatus.KeepWaiting ||\r\n                                status == DragDropManager.ProcStatus.Success)\r\n                                break; // don't process more if we're waiting or we just processed something\r\n                        }\r\n                        else\r\n                        {\r\n                            m_Queue.Dequeue();\r\n                            Client.Instance.SendToServer(new DoubleClick(s));\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    if (requeue != null)\r\n                    {\r\n                        for (int i = 0; i < requeue.Count; i++)\r\n                            m_Queue.Enqueue(requeue[i]);\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    Stop();\r\n\r\n                    if (m_Total > 1 && World.Player != null)\r\n                        World.Player.SendMessage(LocString.QueueFinished, m_Total,\r\n                            ((DateTime.UtcNow - m_StartTime) - this.Interval).TotalSeconds);\r\n\r\n                    m_Last = Serial.Zero;\r\n                    m_Total = 0;\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Razor/Core/BandageTimer.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing Assistant.Core;\r\n\r\nnamespace Assistant\r\n{\r\n    public class BandageTimer\r\n    {\r\n        private static int _count;\r\n        private static readonly Timer Timer;\r\n\r\n        private static readonly int[] ClilocNums = {\r\n            500955,\r\n            500962,\r\n            500963,\r\n            500964,\r\n            500965,\r\n            500966,\r\n            500967,\r\n            500968,\r\n            500969,\r\n            503252,\r\n            503253,\r\n            503254,\r\n            503255,\r\n            503256,\r\n            503257,\r\n            503258,\r\n            503259,\r\n            503260,\r\n            503261,\r\n            1010058,\r\n            1010648,\r\n            1010650,\r\n            1060088,\r\n            1060167\r\n        };\r\n\r\n        static BandageTimer()\r\n        {\r\n            Timer = new InternalTimer();\r\n            \r\n            MessageManager.OnSystemMessage += OnSystemMessage;\r\n        }\r\n\r\n        private static void OnSystemMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic, MessageType type, ushort hue, ushort font, string lang, string sourceName, string msg)\r\n        {\r\n            if (Running)\r\n            {\r\n                if (msg == \"You heal what little damage you had.\" ||\r\n                    msg == \"You heal what little damage the patient had.\" ||\r\n                    msg == \"You did not stay close enough to heal your target.\")\r\n                {\r\n                    Stop();\r\n\r\n                    if (Config.GetBool(\"ShowBandageTimer\") && Config.GetBool(\"ShowBandageEnd\"))\r\n                        ShowBandagingStatusMessage(Config.GetString(\"BandageEndMessage\"));\r\n\r\n                    return;\r\n                }\r\n\r\n                if (msg == \"You begin applying the bandages.\") // Timer is running and they start a new bandage\r\n                {\r\n                    Start();\r\n\r\n                    if (Config.GetBool(\"ShowBandageTimer\") && Config.GetBool(\"ShowBandageStart\"))\r\n                        ShowBandagingStatusMessage(Config.GetString(\"BandageStartMessage\"));\r\n\r\n                    return;\r\n                }\r\n\r\n                foreach (var t in ClilocNums)\r\n                {\r\n                    if (Language.GetCliloc(t) == msg)\r\n                    {\r\n                        Stop();\r\n\r\n                        if (Config.GetBool(\"ShowBandageTimer\") && Config.GetBool(\"ShowBandageEnd\"))\r\n                            ShowBandagingStatusMessage(Config.GetString(\"BandageEndMessage\"));\r\n\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                // Start timer as soon as there is the \"You begin applying the bandages.\" message\r\n                if (msg == \"You begin applying the bandages.\")\r\n                {\r\n                    Start();\r\n\r\n                    if (Config.GetBool(\"ShowBandageTimer\") && Config.GetBool(\"ShowBandageStart\"))\r\n                        ShowBandagingStatusMessage(Config.GetString(\"BandageStartMessage\"));\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void OnLocalizedMessage(int num)\r\n        {\r\n            if (Running)\r\n            {\r\n                if (num == 500955 || (num >= 500962 && num <= 500969) || (num >= 503252 && num <= 503261) ||\r\n                    num == 1010058 || num == 1010648 || num == 1010650 || num == 1060088 || num == 1060167)\r\n                {\r\n                    Stop();\r\n\r\n                    if (Config.GetBool(\"ShowBandageTimer\") && Config.GetBool(\"ShowBandageEnd\"))\r\n                        ShowBandagingStatusMessage(Config.GetString(\"BandageEndMessage\"));\r\n\r\n                    return;\r\n                }\r\n\r\n                // Check if they are re-healing before the timer ends\r\n                if (num == 500956)\r\n                {\r\n                    Start();\r\n\r\n                    if (Config.GetBool(\"ShowBandageTimer\") && Config.GetBool(\"ShowBandageStart\"))\r\n                        ShowBandagingStatusMessage(Config.GetString(\"BandageStartMessage\"));\r\n                }\r\n            }\r\n            else\r\n            {\r\n                // Start timer as soon as there is the \"You begin applying the bandages.\" message\r\n                if (num == 500956)\r\n                {\r\n                    Start();\r\n\r\n                    if (Config.GetBool(\"ShowBandageTimer\") && Config.GetBool(\"ShowBandageStart\"))\r\n                        ShowBandagingStatusMessage(Config.GetString(\"BandageStartMessage\"));\r\n                }\r\n            }\r\n        }\r\n\r\n        public static int Count => _count;\r\n\r\n        public static bool Running => Timer.Running;\r\n\r\n        private static void Start()\r\n        {\r\n            _count = 0;\r\n\r\n            if (Timer.Running)\r\n            {\r\n                Timer.Stop();\r\n            }\r\n\r\n            Timer.Start();\r\n            Client.Instance.RequestTitlebarUpdate();\r\n        }\r\n\r\n        public static void Stop()\r\n        {\r\n            Timer.Stop();\r\n            Client.Instance.RequestTitlebarUpdate();\r\n        }\r\n\r\n        private static void ShowBandagingStatusMessage(string msg)\r\n        {\r\n            if (Config.GetInt(\"ShowBandageTimerLocation\") == 0)\r\n            {\r\n                World.Player.OverheadMessage(Config.GetInt(\"ShowBandageTimerHue\"), msg);\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(Config.GetInt(\"ShowBandageTimerHue\"), msg);\r\n            }\r\n        }\r\n\r\n        private class InternalTimer : Timer\r\n        {\r\n            public InternalTimer() : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\r\n            {\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                if (World.Player != null && World.Player.IsGhost)\r\n                {\r\n                    BandageTimer.Stop();\r\n                    return;\r\n                }\r\n\r\n                _count++;\r\n\r\n                if (Config.GetBool(\"ShowBandageTimer\"))\r\n                {\r\n                    bool showMessage = !(Config.GetBool(\"OnlyShowBandageTimerEvery\") &&\r\n                                         _count % Config.GetInt(\"OnlyShowBandageTimerSeconds\") != 0);\r\n\r\n                    if (showMessage)\r\n                        ShowBandagingStatusMessage(Config.GetString(\"ShowBandageTimerFormat\")\r\n                            .Replace(\"{count}\", _count.ToString()));\r\n                }\r\n\r\n                if (_count > 30)\r\n                    Stop();\r\n\r\n                Client.Instance.RequestTitlebarUpdate();\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/BodCapture.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\n\nnamespace Assistant.Core\n{\n    public class BodCapture\n    {\n        private class Bod\n        {\n            public bool IsLarge { get; set; }\n            public string ItemName { get; set; }\n            public bool Exceptional { get; set; }\n            public string Material { get; set; }\n            public string TotalAmount { get; set; }\n            public string CurrentAmount { get; set; }\n        }\n\n        private static readonly uint _largeBodGumpId = 2703603018;\n        private static readonly uint _smallBodGumpId = 1526454082;\n\n        private static readonly string _bodFile = Path.Combine(Config.GetInstallDirectory(), \"BODs.csv\");\n\n        public static bool IsBodGump(uint gumpId)\n        {\n            return gumpId == _largeBodGumpId || gumpId == _smallBodGumpId;\n        }\n\n        public static void CaptureBod(List<string> bodGumpString)\n        {\n            // sort the gump string\n            List<Bod> bods = ParseBodGumpData(bodGumpString);\n\n            CheckFile();\n\n            using (StreamWriter sw = File.AppendText(_bodFile))\n            {\n                foreach (Bod bod in bods)\n                {\n                    sw.WriteLine(\n                        $\"{bod.ItemName},{(bod.IsLarge ? \"large\" : \"small\")},{bod.Exceptional},{bod.Material},{bod.CurrentAmount},{bod.TotalAmount}\");\n                }\n            }\n        }\n\n        public static void CheckFile()\n        {\n            if (File.Exists(_bodFile))\n                return;\n\n            using (StreamWriter sw = File.AppendText(_bodFile))\n            {\n                sw.WriteLine(\"itemname,type,exceptional,material,currentamount,totalamount\");\n            }\n        }\n\n        /*Count = 11               //// SMALL BOD\n        [0]: \"A bulk order\"\n        [1]: \"Amount to make:\"\n        [2]: \"Amount finished:\"\n        [3]: \"Item requested:\"\n        [4]: \"cloak\"\n        [5]: \"Special requirements to meet:\"\n        [6]: \"All items must be exceptional.\"\n        [?]: \"All items must be made with X.\n        [7]: \"Combine this deed with the item requested.\"\n        [8]: \"EXIT\"\n        [9]: \"20\"\n        [10]: \"0\"\n        \n        Count = 19                /// LARGE BOD\n        [0]: \"A large bulk order\"\n        [1]: \"Amount to make:\"\n        [2]: \"Items requested:\"\n        [3]: \"Amount finished:\"\n        [4]: \"war axe\"\n        [5]: \"hammer pick\"\n        [6]: \"mace\"\n        [7]: \"maul\"\n        [8]: \"war hammer\"\n        [9]: \"war mace\"\n        [?]: \"All items must be made with X.\n        [10]: \"Combine this deed with another deed.\"\n        [11]: \"EXIT\"\n        [12]: \"15\"\n        [13]: \"0\"\n        [14]: \"0\"\n        [15]: \"0\"\n        [16]: \"0\"\n        [17]: \"0\"\n        [18]: \"0\"*/\n\n        private static List<Bod> ParseBodGumpData(List<string> gumpData)\n        {\n            List<Bod> bods = new List<Bod>();\n\n            // First item should say large if it is\n            bool isLarge = gumpData[0].Contains(\"large\");\n\n            // EXIT on large/small is an good \"split\" point\n            int exitIndex = gumpData.FindIndex(x => x.Equals(\"EXIT\"));\n\n\n            // This word should exist some place in the array if it's exceptional\n            bool isExceptional = false;\n            string material = \"default\";\n\n            foreach (string data in gumpData)\n            {\n                if (data.Contains(\"exceptional\"))\n                {\n                    isExceptional = true;\n                }\n                else if (data.Contains(\"All items must be made with\"))\n                {\n                    material = data.Substring(data.IndexOf(\"with\", StringComparison.Ordinal) + 5).Replace(\".\", \"\");\n                }\n            }\n\n            // Based on the data above, the total amount is always after EXIT in both small and large\n            string totalAmount = gumpData[exitIndex + 1];\n\n            // BOD requirement data appears at index 4 for both small and large\n            int beginningIndex = 4;\n\n            int currentAmountIndex = 2;\n\n            if (isLarge)\n            {\n                for (int i = beginningIndex; i < gumpData.Count; i++)\n                {\n                    // Keep adding new BODs to the array as long as you don't hit the end\n                    if (!gumpData[i].Contains(\"Combine\") && !gumpData[i].Contains(\"Special\"))\n                    {\n                        bods.Add(new Bod\n                        {\n                            ItemName = gumpData[i],\n                            IsLarge = true,\n                            Exceptional = isExceptional,\n                            CurrentAmount = gumpData[exitIndex + currentAmountIndex],\n                            TotalAmount = totalAmount,\n                            Material = material\n                        });\n\n                        currentAmountIndex++;\n                    }\n                    else\n                    {\n                        break;\n                    }\n                }\n            }\n            else // small!\n            {\n                bods.Add(new Bod\n                {\n                    ItemName = gumpData[beginningIndex],\n                    IsLarge = false,\n                    Exceptional = isExceptional,\n                    CurrentAmount = gumpData[exitIndex + 2],\n                    TotalAmount = totalAmount,\n                    Material = material\n                });\n            }\n\n            return bods;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/BuffDebuffManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing Assistant.Agents;\nusing Assistant.Gumps.Internal;\n\nnamespace Assistant.Core\n{\n    public enum BuffIconType : ushort\n    {\n        DismountPrevention = 0x3E9,\n        NoRearm = 0x3EA,\n        \n        //Currently, no 0x3EB or 0x3EC\n        NightSight = 0x3ED, \n        DeathStrike,\n        EvilOmen,\n        HonoredDebuff,\n        AchievePerfection,\n        DivineFury,         \n        EnemyOfOne,         \n        HidingAndOrStealth,\n        ActiveMeditation,\n        BloodOathCaster,\n        BloodOathCurse,\n        CorpseSkin,\n        Mindrot,\n        PainSpike,\n        Strangle,\n        GiftOfRenewal,\n        AttuneWeapon,\n        Thunderstorm,\n        EssenceOfWind,\n        EtherealVoyage,\n        GiftOfLife,\n        ArcaneEmpowerment,\n        MortalStrike,\n        ReactiveArmor,\n        Protection,\n        ArchProtection,\n        MagicReflection,\n        Incognito,\n        Disguised,\n        AnimalForm,\n        Polymorph,\n        Invisibility,\n        Paralyze, \n        Poison,\n        Bleed,\n        Clumsy, \n        FeebleMind,\n        Weaken,  \n        Curse,   \n        MassCurse,\n        Agility, \n        Cunning, \n        Strength, \n        Bless,   \n        Sleep,\n        StoneForm,\n        SpellPlague,\n        Berserk,\n        MassSleep,\n        Fly,\n        Inspire,\n        Invigorate,\n        Resilience,\n        Perseverance,\n        TribulationTarget,\n        DespairTarget,\n        FishPie = 0x426,\n        HitLowerAttack,\n        HitLowerDefense,\n        DualWield,\n        Block,\n        DefenseMastery,\n        DespairCaster,\n        Healing,\n        SpellFocusingBuff,\n        SpellFocusingDebuff,\n        RageFocusingDebuff,\n        RageFocusingBuff,\n        Warding,\n        TribulationCaster,\n        ForceArrow,\n        Disarm,\n        Surge,\n        Feint,\n        TalonStrike,\n        PsychicAttack,\n        ConsecrateWeapon,\n        GrapesOfWrath,\n        EnemyOfOneDebuff,\n        HorrificBeast,\n        LichForm,\n        VampiricEmbrace,\n        CurseWeapon,\n        ReaperForm,\n        ImmolatingWeapon,\n        Enchant,\n        HonorableExecution,\n        Confidence,\n        Evasion,\n        CounterAttack,\n        LightningStrike,\n        MomentumStrike,\n        OrangePetals,\n        RoseOfTrinsic,\n        PoisonImmunity,\n        Veterinary,\n        Perfection,\n        Honored,\n        ManaPhase,\n        FanDancerFanFire,\n        Rage,\n        Webbing,\n        MedusaStone,\n        TrueFear,\n        AuraOfNausea,\n        HowlOfCacophony,\n        GazeDespair,\n        HiryuPhysicalResistance,\n        RuneBeetleCorruption,\n        BloodwormAnemia,\n        RotwormBloodDisease,\n        SkillUseDelay,\n        FactionStatLoss,\n        HeatOfBattleStatus,\n        CriminalStatus,\n        ArmorPierce,\n        SplinteringEffect,\n        SwingSpeedDebuff,\n        WraithForm,\n        CityTradeDeal = 0x466,\n        HumilityDebuff = 0x467,\n        Spirituality,\n        Humility,\n        // Skill Masteries\n        Rampage,\n        Stagger, // Debuff\n        Toughness,\n        Thrust,\n        Pierce, // Debuff\n        PlayingTheOdds,\n        FocusedEye,\n        Onslaught, // Debuff\n        ElementalFury,\n        ElementalFuryDebuff, // Debuff\n        CalledShot,\n        Knockout,\n        SavingThrow,\n        Conduit,\n        EtherealBurst,\n        MysticWeapon,\n        ManaShield,\n        AnticipateHit,\n        Warcry,\n        Shadow,\n        WhiteTigerForm,\n        Bodyguard,\n        HeightenedSenses,\n        Tolerance,\n        DeathRay,\n        DeathRayDebuff,\n        Intuition,\n        EnchantedSummoning,\n        ShieldBash,\n        Whispering,\n        CombatTraining,\n        InjectedStrikeDebuff,\n        InjectedStrike,\n        UnknownTomato,\n        PlayingTheOddsDebuff,\n        DragonTurtleDebuff,\n        Boarding,\n        Potency,\n        ThrustDebuff,\n        FistsOfFury,\n        BarrabHemolymphConcentrate,\n        JukariBurnPoiltice,\n        KurakAmbushersEssence,\n        BarakoDraftOfMight,\n        UraliTranceTonic,\n        SakkhraProphylaxis,\n        Sparks,\n        Swarm,\n        BoneBreaker,\n        Unknown2,\n        SwarmImmune,\n        BoneBreakerImmune,\n        UnknownGoblin,\n        UnknownRedDrop,\n        UnknownStar,\n        FeintDebuff,\n        CaddelliteInfused,\n        PotionGloriousFortune,\n        MysticalPolymorphTotem,\n        UnknownDebuff\n    }\n\n    public class BuffDebuff\n    {\n        public ushort IconId { get; set; }\n        public int Duration { get; set; }\n        public string ClilocMessage1 { get; set; }\n        public string ClilocMessage2 { get; set; }\n        public BuffIconType BuffIconType { get; set; }\n        public DateTime Timestamp { get; set; }\n\n        public override string ToString()\n        {\n            return ClilocMessage1;\n        }\n    }\n\n    public static class BuffDebuffManager\n    {\n        private static Timer BuffDebuffTimer { get; set; } = new InternalTimer();\n\n        private static List<string> _buffDebuffFilter = new List<string>();\n\n        private static BuffGump _gump;\n\n        public static ushort[] BuffTable { get; } =\n        {\n            0x754C,\n            0x754A,\n            0x0000,\n            0x0000,\n            0x755E,\n            0x7549,\n            0x7551,\n            0x7556,\n            0x753A,\n            0x754D,\n            0x754E,\n            0x7565,\n            0x753B,\n            0x7543,\n            0x7544,\n            0x7546,\n            0x755C,\n            0x755F,\n            0x7566,\n            0x7554,\n            0x7540,\n            0x7568,\n            0x754F,\n            0x7550,\n            0x7553,\n            0x753E,\n            0x755D,\n            0x7563,\n            0x7562,\n            0x753F,\n            0x7559,\n            0x7557,\n            0x754B,\n            0x753D,\n            0x7561,\n            0x7558,\n            0x755B,\n            0x7560,\n            0x7541,\n            0x7545,\n            0x7552,\n            0x7569,\n            0x7548,\n            0x755A,\n            0x753C,\n            0x7547,\n            0x7567,\n            0x7542,\n            0x758A,\n            0x758B,\n            0x758C,\n            0x758D,\n            0x0000,\n            0x758E,\n            0x094B,\n            0x094C,\n            0x094D,\n            0x094E,\n            0x094F,\n            0x0950,\n            0x753E,\n            0x5011,\n            0x7590,\n            0x7591,\n            0x7592,\n            0x7593,\n            0x7594,\n            0x7595,\n            0x7596,\n            0x7598,\n            0x7599,\n            0x759B,\n            0x759C,\n            0x759E,\n            0x759F,\n            0x75A0,\n            0x75A1,\n            0x75A3,\n            0x75A4,\n            0x75A5,\n            0x75A6,\n            0x75A7,\n            0x75C0,\n            0x75C1,\n            0x75C2,\n            0x75C3,\n            0x75C4,\n            0x75F2,\n            0x75F3,\n            0x75F4,\n            0x75F5,\n            0x75F6,\n            0x75F7,\n            0x75F8,\n            0x75F9,\n            0x75FA,\n            0x75FB,\n            0x75FC,\n            0x75FD,\n            0x75FE,\n            0x75FF,\n            0x7600,\n            0x7601,\n            0x7602,\n            0x7603,\n            0x7604,\n            0x7605,\n            0x7606,\n            0x7607,\n            0x7608,\n            0x7609,\n            0x760A,\n            0x760B,\n            0x760C,\n            0x760D,\n            0x760E,\n            0x760F,\n            0x7610,\n            0x7611,\n            0x7612,\n            0x7613,\n            0x7614,\n            0x7615,\n            0x75C5,\n            0x75F6,\n            0x761B,\n            // skill masteries\n            0x9bc9,\n            0x9bb5,\n            0x9bdd,\n            0x9bc6,\n            0x9bcc,\n            0x9bbe,\n            0x9bbd,\n            0x9bcb,\n            0x9bc8,\n            0x9bbf,\n            0x9bcd,\n            0x9bc0,\n            0x9bce,\n            0x9bc1,\n            0x9bc7,\n            0x9bc2,\n            0x9bb7,\n            0x9bca,\n            0x9bb6,\n            0x9bb8,\n            0x9bb9,\n            0x9bba,\n            0x9bbb,\n            0x9bbc,\n            0x9bc3,\n            0x9bc4,\n            0x9bc5,\n            0x9bd2,\n            0x9bd3,\n            0x9bd4,\n            0x9bd5,\n            0x9bd1,\n            0x9bd6,\n            0x9bd7,\n            0x9bcf,\n            0x9bd8,\n            0x9bd9,\n            0x9bdb,\n            0x9bdc,\n            0x9bda,\n            0x9bd0,\n            0x9bde,\n            0x9bdf,\n\n            0xC349,\n            0xC34D,\n            0xC34E,\n            0xC34C,\n            0xC34B,\n            0xC34A,\n            0xC343,\n            0xC345,\n            0xC346,\n            0xC347,\n            0xC348,\n\n            0x9CDE,\n\n            0x5DE1,\n            0x5DDF,\n            0x5DE3,\n            0x5DE5,\n            0x5DE4,\n            0x5DE6,\n            0x5D51,\n\n            0x0951\n        };\n\n        public static ushort[] BuffList { get; } =\n        {\n            //UNKNOWN (COULD NOT FIND A ICON)\n            0x5D51,\n            //GREEN ICONS\n            0x094B, 0x094C, 0x094D, 0x094E, 0x5011, 0x5DDF, 0x5DE1, 0x5DE4, 0x5DE5, 0x5DE6, 0x753C, 0x753D, 0x753E, 0x753E, 0x753F,\n            0x7540, 0x7542, 0x7543, 0x7547, 0x754D, 0x754E, 0x7550, 0x7553, 0x7554, 0x7558, 0x7559, 0x755E, 0x7562, 0x7563, 0x7567,\n            0x758B, 0x758D, 0x7592, 0x7593, 0x7594, 0x7596, 0x7598, 0x759C, 0x759E, 0x759F, 0x75A3, 0x75A4, 0x75A7, 0x75C0, 0x75C2,\n            0x75C3, 0x75C4, 0x75C5, 0x75F2, 0x75F3, 0x75F4, 0x75F5, 0x75F6, 0x75F7, 0x75F8, 0x75F9, 0x75FA, 0x75FB, 0x75FC, 0x75FD,\n            0x75FE, 0x75FF, 0x7600, 0x7601, 0x7602, 0x7617, 0x7618, 0x7619, 0x761A, 0x761B, 0x9bb5, 0x9bb6, 0x9bb7, 0x9bb8, 0x9bb9,\n            0x9bba, 0x9bbb, 0x9bbc, 0x9bbd, 0x9bbe, 0x9bbf, 0x9bc0, 0x9bc1, 0x9bc2, 0x9bc3, 0x9bc4, 0x9bc5, 0x9bc6, 0x9bc7, 0x9bc8,\n            0x9bd0, 0x9bd1, 0x9bd2, 0x9bd4, 0x9bd5, 0x9bd6, 0x9bd7, 0x9bd8, 0x9bd9, 0x9bda, 0x9bdd, 0x9bdf, 0x9CDE, 0xC342, 0xC346,\n            0xC347, 0xC348, 0xC349, 0xC34A, 0xC34B, 0xC34C, 0xC34D, 0xC34E\n        };\n\n        public static ushort[] DebuffList { get; } =\n        {\n            //RED ICONS\n            0x094F, 0x0950, 0x0951, 0x5DE3, 0x753A, 0x7540, 0x7544, 0x7545, 0x7546, 0x7548, 0x7549, 0x754A, 0x754C, 0x754F, 0x7551,\n            0x7552, 0x7555, 0x7556, 0x755A, 0x755B, 0x755C, 0x755D, 0x755F, 0x7560, 0x7564, 0x7566, 0x7568, 0x7569, 0x758A, 0x758C,\n            0x758F, 0x7590, 0x7591, 0x7599, 0x759B, 0x75A0, 0x75A1, 0x75A5, 0x75A6, 0x75A8, 0x75C1, 0x7603, 0x7604, 0x7605, 0x7606,\n            0x7607, 0x7608, 0x7609, 0x760A, 0x760B, 0x760C, 0x760D, 0x760E, 0x760F, 0x7610, 0x7611, 0x7612, 0x7613, 0x7614, 0x7615,\n            0x7616, 0x9bc9, 0x9bca, 0x9bcb, 0x9bcc, 0x9bcd, 0x9bce, 0x9bcf, 0x9bd3, 0x9bdb, 0x9bdc, 0x9bde, 0xC343, 0xC344, 0xC345\n        };\n\n        public static ushort[] StatesList { get; } =\n        {\n            //BLUE ICONS\n            0x753B, 0x754B, 0x7557, 0x7561, 0x7565, 0x758E, 0x7595\n        };\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsBuff(ushort g)\n        {\n            return BuffList.Contains(g);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsDebuff(ushort g)\n        {\n            return DebuffList.Contains(g);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsState(ushort g)\n        {\n            return StatesList.Contains(g);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsValid(ushort g)\n        {\n            return BuffList.Contains(g);\n        }\n        \n        private const ushort BUFF_ICON_START = 0x03E9;\n        private const ushort BUFF_ICON_START_NEW = 0x466;\n\n        public static ushort GetGraphicId(string name)\n        {\n            try\n            {\n                if (Enum.TryParse(name, true, out BuffIconType result))\n                {\n                    ushort iconId = (ushort) result >= BUFF_ICON_START_NEW\n                        ? (ushort) (result - (BUFF_ICON_START_NEW - 125))\n                        : (ushort) ((ushort) result - BUFF_ICON_START);\n\n                    return BuffTable[iconId];\n                }\n            }\n            catch (Exception ex)\n            {\n                // ignored\n            }\n\n            return 0;\n        }\n\n        public static void DisplayOverheadBuff(BuffDebuff buff, bool ignoreAction = false)\n        {\n            if (Config.GetBool(\"ShowBuffDebuffOverhead\") && !IsFiltered(buff.ClilocMessage1))\n            {\n                TimeSpan diff = DateTime.UtcNow - buff.Timestamp;\n                int timeLeft = buff.Duration - (int)diff.TotalSeconds;\n\n                if (Config.GetBool(\"OverrideBuffDebuffFormat\"))\n                {\n                    string format = Config.GetString(\"BuffDebuffFormat\");\n\n                    if (string.IsNullOrEmpty(format))\n                    {\n                        format = \"[{action}{name} {duration}]\";\n                    }\n                    \n                    World.Player.OverheadMessage(Config.GetInt(\"BuffHue\"), format.Replace(\"{action}\", ignoreAction ? string.Empty : \"+\").Replace(\"{name}\", buff.ClilocMessage1)\n                            .Replace(\"{duration}\", timeLeft < 1 ? string.Empty : $\"({timeLeft}s)\"));\n                }\n                else\n                {\n                    World.Player.OverheadMessage(Config.GetInt(\"BuffHue\"), timeLeft < 1 ? $\"[+{buff.ClilocMessage1}]\" : $\"[+{buff.ClilocMessage1} ({timeLeft}s)]\");\n                }\n            }\n        }\n\n        public static void DisplayOverheadDebuff(BuffIconType debuffIconType)\n        {\n            if (Config.GetBool(\"ShowBuffDebuffOverhead\"))\n            {\n                BuffDebuff debuff = World.Player.BuffsDebuffs.FirstOrDefault(b => b.BuffIconType == debuffIconType);\n\n                if (debuff == null)\n                    return;\n\n                if (IsFiltered(debuff.ClilocMessage1))\n                    return;\n\n                if (Config.GetBool(\"OverrideBuffDebuffFormat\"))\n                {\n                    string format = Config.GetString(\"BuffDebuffFormat\");\n\n                    if (string.IsNullOrEmpty(format))\n                    {\n                        format = \"[{action}{name} {duration}]\";\n                    }\n                    \n                    World.Player.OverheadMessage(Config.GetInt(\"DebuffHue\"),\n                        format.Replace(\"{action}\", \"-\").Replace(\"{name}\", debuff.ClilocMessage1)\n                            .Replace(\"{duration}\", string.Empty));\n                }\n                else\n                {\n                    World.Player.OverheadMessage(Config.GetInt(\"DebuffHue\"), $\"[-{debuff.ClilocMessage1}]\");\n                }\n            }\n        }\n\n        public static void ReloadFilter()\n        {\n            _buffDebuffFilter.Clear();\n\n            foreach (string filter in Config.GetString(\"BuffDebuffFilter\").Split(','))\n            {\n                if (!string.IsNullOrEmpty(filter))\n                {\n                    _buffDebuffFilter.Add(filter);\n                }\n            }\n        }\n\n        private static bool IsFiltered(string name)\n        {\n            if (string.IsNullOrEmpty(Config.GetString(\"BuffDebuffFilter\")))\n                return false;\n\n            if (string.IsNullOrEmpty(name))\n                return false;\n\n            foreach (string filter in _buffDebuffFilter)\n            {\n                if (name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) != -1)\n                    return true;\n            }\n\n            return false;\n        }\n        \n        public static bool Running => BuffDebuffTimer.Running;\n\n        public static void Start()\n        {\n            if (BuffDebuffTimer.Running)\n                BuffDebuffTimer.Stop();\n            \n            BuffDebuffTimer.Start();\n\n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        public static void Stop()\n        {\n            BuffDebuffTimer.Stop();\n            \n            _gump?.CloseGump();\n            \n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        private class InternalTimer : Timer\n        {\n            public InternalTimer() : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                if (World.Player == null)\n                {\n                    BuffDebuffTimer.Stop();\n                    return;\n                }\n\n                Client.Instance.RequestTitlebarUpdate();\n                \n                if (Config.GetBool(\"ShowBuffDebuffGump\"))\n                {\n                    _gump?.CloseGump();\n\n                    if (World.Player.BuffsDebuffs.Count > 0)\n                    {\n                        _gump = new BuffGump();\n                        _gump.SendGump();\n                    }\n                }\n\n                if (!Config.GetBool(\"BuffDebuffEveryXSeconds\") || !Config.GetBool(\"ShowBuffDebuffOverhead\"))\n                    return;\n\n                foreach (BuffDebuff buffsDebuff in World.Player.BuffsDebuffs)\n                {\n                    TimeSpan diff = DateTime.UtcNow - buffsDebuff.Timestamp;\n                    int timeLeft = buffsDebuff.Duration - (int)diff.TotalSeconds;\n\n                    if (timeLeft % Config.GetInt(\"BuffDebuffSeconds\") == 0)\n                    {\n                        BuffDebuffManager.DisplayOverheadBuff(buffsDebuff, true);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/ClassicUOManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Assistant.Core\n{\n    public static class ClassicUOManager\n    {\n        private static List<string> ProfileProperties { get; set; } = new List<string>();\n\n        /// <summary>\n        /// Gets all properties.\n        /// </summary>\n        /// <returns></returns>\n        public static List<string> GetAllProperties()\n        {\n            if (!Client.IsOSI)\n            {\n                if (ProfileProperties.Count == 0)\n                {\n                    var currentProfileProperty = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.ProfileManager\")?.GetProperty(\"CurrentProfile\", BindingFlags.Public | BindingFlags.Static);\n                    if (currentProfileProperty != null)\n                    {\n                        var profile = currentProfileProperty.GetValue(null);\n                        if (profile != null)\n                        {\n                            var profileClass = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.Profile\");\n\n                            foreach (var propSearch in profileClass.GetProperties())\n                            {\n                                ProfileProperties.Add(propSearch.Name);\n                            }\n\n                            ProfileProperties.Sort();\n                        }\n                    }\n                }\n\n                return ProfileProperties;\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Determines whether [is valid property] [the specified property].\n        /// </summary>\n        /// <param name=\"property\">The property.</param>\n        /// <returns></returns>\n        public static string IsValidProperty(string property)\n        {\n            foreach (string profileProperty in GetAllProperties())\n            {\n                if (profileProperty.Equals(property, StringComparison.OrdinalIgnoreCase))\n                {\n                    return profileProperty;\n                }\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Set a bool Config property in CUO by name\n        /// </summary>\n        public static void ProfilePropertySet(string propertyName, bool enable)\n        {\n            if (!Client.IsOSI)\n            {\n                var currentProfileProperty = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.ProfileManager\")?.GetProperty(\"CurrentProfile\", BindingFlags.Public | BindingFlags.Static);\n                if (currentProfileProperty != null)\n                {\n                    var profile = currentProfileProperty.GetValue(null);\n                    if (profile != null)\n                    {\n                        var profileClass = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.Profile\");\n                        PropertyInfo property = null;\n\n                        foreach (var propSearch in profileClass.GetProperties())\n                        {\n                            if (propSearch.Name == propertyName)\n                            {\n                                property = propSearch;\n                                break;\n                            }\n                        }\n\n                        if (property != null)\n                        {\n                            property.SetValue(profile, enable);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Set a int Config property in CUO by name\n        /// </summary>\n        public static void ProfilePropertySet(string propertyName, int value)\n        {\n            if (!Client.IsOSI)\n            {\n                var currentProfileProperty = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.ProfileManager\")?.GetProperty(\"CurrentProfile\", BindingFlags.Public | BindingFlags.Static);\n                if (currentProfileProperty != null)\n                {\n                    var profile = currentProfileProperty.GetValue(null);\n                    if (profile != null)\n                    {\n                        var profileClass = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.Profile\");\n                        PropertyInfo property = null;\n\n                        foreach (var propSearch in profileClass.GetProperties())\n                        {\n                            if (propSearch.Name == propertyName)\n                            {\n                                property = propSearch;\n                                break;\n                            }\n                        }\n\n                        if (property != null)\n                        {\n                            property.SetValue(profile, value);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Set a string Config property in CUO by name\n        /// </summary>\n        public static void ProfilePropertySet(string propertyName, string value)\n        {\n            if (!Client.IsOSI)\n            {\n                var currentProfileProperty = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.ProfileManager\")?.GetProperty(\"CurrentProfile\", BindingFlags.Public | BindingFlags.Static);\n                if (currentProfileProperty != null)\n                {\n                    var profile = currentProfileProperty.GetValue(null);\n                    if (profile != null)\n                    {\n                        var profileClass = ClassicUOClient.Assembly?.GetType(\"ClassicUO.Configuration.Profile\");\n                        System.Reflection.PropertyInfo property = null;\n                        foreach (var propSearch in profileClass.GetProperties())\n                        {\n                            if (propSearch.Name == propertyName)\n                            {\n                                property = propSearch;\n                                break;\n                            }\n                        }\n                        if (property != null)\n                        {\n                            property.SetValue(profile, value);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Core/Commands.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Text;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing Assistant.Agents;\r\nusing Assistant.Core;\r\nusing Assistant.Gumps.Internal;\r\nusing Assistant.Macros;\r\nusing Assistant.Scripts;\r\nusing Ultima;\r\n\r\nnamespace Assistant\r\n{\r\n    public class Commands\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            Command.Register(\"AddUseOnce\", AddUseOnce);\r\n            Command.Register(\"Time\", Time);\r\n            Command.Register(\"Where\", Where);\r\n            Command.Register(\"Ping\", Ping);\r\n            Command.Register(\"Help\", Command.ListCommands);\r\n            Command.Register(\"Echo\", Echo);\r\n            Command.Register(\"Macro\", MacroCmd);\r\n            Command.Register(\"Script\", ScriptCmd);\r\n            Command.Register(\"Hue\", GetItemHue);\r\n            Command.Register(\"Item\", GetItemHue);\r\n            Command.Register(\"Resync\", Resync);\r\n            Command.Register(\"Mobile\", GetMobile);\r\n            Command.Register(\"Weather\", SetWeather);\r\n            Command.Register(\"Season\", SetSeason);\r\n            Command.Register(\"Damage\", DamageTrackerReport);\r\n            Command.Register(\"Set\", SetMacroVariable);\r\n            Command.Register(\"Track\", Track);\r\n            Command.Register(\"Waypoint\", Track);\r\n\r\n            Command.Register(\"TestGump\", CreateGump);\r\n            Command.Register(\"Info\", GetGumpInfo);\r\n\r\n            Command.Register(\"SysMsgs\", GetSystemMessages);\r\n            Command.Register(\"SysMessages\", GetSystemMessages);\r\n\r\n            Command.Register(\"HotKeys\", ShowHotKeyGump);\r\n\r\n            Command.Register(\"Boat\", ShowBoatControlGump);\r\n\r\n            Command.Register(\"Skills\", ShowUsableSkills);\r\n\r\n            Command.Register(\"Restock\", ShowRestockGump);\r\n            Command.Register(\"Org\", ShowOrgGump);\r\n            Command.Register(\"Buy\", ShowBuyGump);\r\n\r\n            Command.Register(\"CUO\", ClassicUoProfile);\r\n            \r\n            Command.Register(\"Sound\", PlaySound);\r\n            \r\n            Command.Register(\"Cooldown\", Cooldown);\r\n        }\r\n        \r\n        private static void Cooldown(string[] param)\r\n        {\r\n            if (param.Length <= 0)\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"You must enter a name and seconds.\");\r\n                return;\r\n            }\r\n\r\n            if (param[0].Equals(\"test\"))\r\n            {\r\n                CooldownManager.AddCooldown(\"Test 1\", 25, 0, 0);\r\n                CooldownManager.AddCooldown(\"Test 2\", 20, 0, 0);\r\n                CooldownManager.AddCooldown(\"Test 3\", 18, 0, 0);\r\n                CooldownManager.AddCooldown(\"Bandage 1\", 10, 0, 30037);\r\n                CooldownManager.AddCooldown(\"Attack 1\", 20, 0, 0);\r\n                CooldownManager.AddCooldown(\"Hue 23\", 10, 23, 30051);\r\n                CooldownManager.AddCooldown(\"Hue 94\", 18, 94, 0);\r\n                CooldownManager.AddCooldown(\"Hue 243\", 12, 243, 30042);\r\n                CooldownManager.AddCooldown(\"Stay 1\", 18, 0, 0, 0, true);\r\n                CooldownManager.AddCooldown(\"Stay 2\", 12, 0, 30044, 0, true);\r\n                CooldownManager.AddCooldown(\"Stay 3\", 6, 0, 0, 0, true);\r\n                CooldownManager.AddCooldown(\"Sound 1\", 7, 0, 30037, 61);\r\n                CooldownManager.AddCooldown(\"Sound 2\", 20, 0, 0, 61);\r\n                CooldownManager.AddCooldown(\"Hue 23 1\", 22, 23, 30051);\r\n                CooldownManager.AddCooldown(\"Hue 94 2\", 25, 94, 0);\r\n                CooldownManager.AddCooldown(\"Hue 243 3\", 12, 243, 30042);\r\n                CooldownManager.AddCooldown(\"Test 7\", 25, 0, 0);\r\n                CooldownManager.AddCooldown(\"Test 8\", 9, 0, 30037);\r\n                CooldownManager.AddCooldown(\"Test 9\", 5, 0, 0);\r\n            }\r\n            else\r\n            {\r\n                CooldownManager.AddCooldown(param[0], Convert.ToInt32(param[1]));    \r\n            }\r\n            \r\n        }\r\n        \r\n        private static void PlaySound(string[] param)\r\n        {\r\n            if (param.Length <= 0)\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"You must enter sound id.\");\r\n                return;\r\n            }\r\n\r\n            Client.Instance.SendToClient(new PlaySound(Utility.ToInt32(param[0], 0)));\r\n        }\r\n\r\n        private static void ClassicUoProfile(string[] param)\r\n        {\r\n            if (string.IsNullOrEmpty(param[0]))\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"You must include a valid ClassicUO profile setting. Type `>cuo list` for a list of valid settings.\");\r\n                return;\r\n            }\r\n\r\n            if (param[0].Equals(\"list\"))\r\n            {\r\n                string[] props = ClassicUOManager.GetAllProperties().ToArray();\r\n\r\n                for (var i = 0; i < (float)props.Length / 40; i++)\r\n                {\r\n                    World.Player.SendMessage(MsgLevel.Info, string.Join(\", \", props.Skip(i * 40).Take(40)));\r\n                }\r\n\r\n                return;\r\n            }\r\n\r\n            string property = ClassicUOManager.IsValidProperty(param[0]);\r\n\r\n            if (string.IsNullOrEmpty(property))\r\n            {\r\n                World.Player.SendMessage(\"Unknown ClassicUO setting/property. Type `>cuo list` for a list of valid settings.\");\r\n                return;\r\n            }\r\n\r\n            bool isNumeric = int.TryParse(param[1], out var value);\r\n\r\n            if (isNumeric)\r\n            {\r\n                ClassicUOManager.ProfilePropertySet(property, value);\r\n            }\r\n            else\r\n            {\r\n                switch (param[1])\r\n                {\r\n                    case \"true\":\r\n                        ClassicUOManager.ProfilePropertySet(property, true);\r\n                        break;\r\n                    case \"false\":\r\n                        ClassicUOManager.ProfilePropertySet(property, false);\r\n                        break;\r\n                    default:\r\n                        ClassicUOManager.ProfilePropertySet(property, param[1]);\r\n                        break;\r\n                }\r\n            }\r\n\r\n            World.Player.SendMessage($\"ClassicUO Setting: '{property}' set to '{param[1]}'\");\r\n        }\r\n\r\n        private static void ShowBuyGump(string[] param)\r\n        {\r\n            if (string.IsNullOrEmpty(param[0]))\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"You must include an id or alias\");\r\n                return;\r\n            }\r\n\r\n            if (int.TryParse(param[0], out int agentIndex))\r\n            {\r\n                BuyAgent agent = BuyAgent.Agents[agentIndex - 1];\r\n\r\n                AgentsGump gump = new AgentsGump(agent);\r\n                gump.SendGump();\r\n            }\r\n            else\r\n            {\r\n                foreach (BuyAgent agent in BuyAgent.Agents)\r\n                {\r\n                    if (agent.Alias.Equals(param[0], StringComparison.OrdinalIgnoreCase))\r\n                    {\r\n                        AgentsGump gump = new AgentsGump(agent);\r\n                        gump.SendGump();\r\n\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ShowOrgGump(string[] param)\r\n        {\r\n            if (string.IsNullOrEmpty(param[0]))\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"You must include an id or alias\");\r\n                return;\r\n            }\r\n\r\n            if (int.TryParse(param[0], out int agentIndex))\r\n            {\r\n                OrganizerAgent agent = OrganizerAgent.Agents[agentIndex - 1];\r\n\r\n                AgentsGump gump = new AgentsGump(agent);\r\n                gump.SendGump();\r\n            }\r\n            else\r\n            {\r\n                foreach (OrganizerAgent agent in OrganizerAgent.Agents)\r\n                {\r\n                    if (agent.Alias.Equals(param[0], StringComparison.OrdinalIgnoreCase))\r\n                    {\r\n                        AgentsGump gump = new AgentsGump(agent);\r\n                        gump.SendGump();\r\n\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ShowRestockGump(string[] param)\r\n        {\r\n            if (string.IsNullOrEmpty(param[0]))\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"You must include an id or alias\");\r\n                return;\r\n            }\r\n\r\n            if (int.TryParse(param[0], out int agentIndex))\r\n            {\r\n                RestockAgent agent = RestockAgent.Agents[agentIndex - 1];\r\n\r\n                AgentsGump gump = new AgentsGump(agent);\r\n                gump.SendGump();\r\n            }\r\n            else\r\n            {\r\n                foreach (RestockAgent agent in RestockAgent.Agents)\r\n                {\r\n                    if (agent.Alias.Equals(param[0], StringComparison.OrdinalIgnoreCase))\r\n                    {\r\n                        AgentsGump gump = new AgentsGump(agent);\r\n                        gump.SendGump();\r\n\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ShowUsableSkills(string[] param)\r\n        {\r\n            World.Player.SendMessage(MsgLevel.Info, $\"Usable skills: {string.Join(\", \", Skills.GetUsableSkillNames())}\");\r\n        }\r\n\r\n        private static void GetSystemMessages(string[] param)\r\n        {\r\n            SystemMessagesGump gump = new SystemMessagesGump();\r\n            gump.SendGump();            \r\n        }\r\n\r\n        private static void ShowHotKeyGump(string[] param)\r\n        {\r\n            HotKeyGump gump = new HotKeyGump(true, true, true);\r\n            gump.SendGump();\r\n        }\r\n\r\n        private static void ShowBoatControlGump(string[] param)\r\n        {\r\n            BoatControlGump gump = new BoatControlGump(0);\r\n            gump.SendGump();\r\n        }\r\n\r\n        private static void CreateGump(string[] param)\r\n        {\r\n            StringBuilder message = new StringBuilder();\r\n            message.AppendLine(\"Razor\");\r\n            message.AppendLine();\r\n            message.AppendLine(\"Another message\");\r\n\r\n            TestMessageGump gump =\r\n                new TestMessageGump(message.ToString());\r\n            gump.SendGump();\r\n        }\r\n\r\n        private static DateTime m_LastSync;\r\n        private static string _lastMacroVariable;\r\n\r\n        private static void Resync(string[] param)\r\n        {\r\n            if (DateTime.UtcNow - m_LastSync > TimeSpan.FromSeconds(1.0))\r\n            {\r\n                m_LastSync = DateTime.UtcNow;\r\n\r\n                Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, 0x3B2, 3,\r\n                    Language.CliLocName, \"System\", \"Updating and resyncing with server\"));\r\n\r\n                Client.Instance.SendToServer(new ResyncReq());\r\n            }\r\n        }\r\n\r\n        private static void DamageTrackerReport(string[] param)\r\n        {\r\n            if (DamageTracker.Running)\r\n                DamageTracker.SendReport();\r\n        }\r\n\r\n        private static void Track(string[] param)\r\n        {\r\n            try\r\n            {\r\n                if (param[0].Equals(\"off\"))\r\n                {\r\n                    WaypointManager.ClearWaypoint();\r\n                    return;\r\n                }\r\n\r\n                WaypointManager.Waypoint waypoint = new WaypointManager.Waypoint\r\n                {\r\n                    Name = \"N/A\",\r\n                    X = Convert.ToUInt16(param[0]),\r\n                    Y = Convert.ToUInt16(param[1])\r\n                };\r\n\r\n                WaypointManager.ShowWaypoint(waypoint);\r\n            }\r\n            catch\r\n            {\r\n                WaypointManager.ClearWaypoint();\r\n            }\r\n        }\r\n\r\n        private static void SetMacroVariable(string[] param)\r\n        {\r\n            if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            if (string.IsNullOrEmpty(param[0]))\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"You must pass in a macro variable name.\");\r\n                return;\r\n            }\r\n\r\n            _lastMacroVariable = param[0];\r\n\r\n            Targeting.OneTimeTarget(OnMacroVariableAddTarget);\r\n            World.Player.SendMessage(MsgLevel.Force, $\"Select new target for '{_lastMacroVariable}'\");\r\n        }\r\n\r\n        private static void OnMacroVariableAddTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            TargetInfo t = new TargetInfo\r\n            {\r\n                Gfx = gfx,\r\n                Serial = serial,\r\n                Type = (byte) (ground ? 1 : 0),\r\n                X = pt.X,\r\n                Y = pt.Y,\r\n                Z = pt.Z\r\n            };\r\n\r\n            bool foundVar = false;\r\n\r\n            foreach (MacroVariables.MacroVariable mV in MacroVariables.MacroVariableList\r\n            )\r\n            {\r\n                if (mV.Name.ToLower().Equals(_lastMacroVariable.ToLower()))\r\n                {\r\n                    foundVar = true;\r\n                    // macro exists, update\r\n                    mV.TargetInfo = t;\r\n\r\n                    World.Player.SendMessage(MsgLevel.Force, $\"'{mV.Name}' macro variable updated to '{t.Serial}'\");\r\n\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (!foundVar)\r\n            {\r\n                MacroVariables.MacroVariableList.Add(new MacroVariables.MacroVariable(_lastMacroVariable, t));\r\n                World.Player.SendMessage(MsgLevel.Force,\r\n                    $\"'{_lastMacroVariable}' not found, created variable and set to '{t.Serial}'\");\r\n            }\r\n\r\n            // Save and reload the macros and vars\r\n            Engine.MainWindow.SaveMacroVariables();\r\n        }\r\n\r\n        private static void SetWeather(string[] param)\r\n        {\r\n            Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, 0x3B2, 3,\r\n                Language.CliLocName, \"System\", \"Setting weather..\"));\r\n\r\n            Client.Instance.SendToClient(new SetWeather(Convert.ToInt32(param[0]), Convert.ToInt32(param[1])));\r\n        }\r\n\r\n        private static void SetSeason(string[] param)\r\n        {\r\n            Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, 0x3B2, 3,\r\n                Language.CliLocName, \"System\", \"Setting season..\"));\r\n\r\n            Client.Instance.ForceSendToClient(new SeasonChange(Convert.ToInt32(param[0]), true));\r\n        }\r\n\r\n        private static void GetGumpInfo(string[] param)\r\n        {\r\n            ScriptManager.GetGumpInfo(param);\r\n        }\r\n\r\n        private static void GetItemHue(string[] param)\r\n        {\r\n            Targeting.OneTimeTarget(OnGetItemHueTarget);\r\n            Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, 0x3B2, 3,\r\n                Language.CliLocName, \"System\", \"Select an item to get the hue value\"));\r\n        }\r\n\r\n        private static void OnGetItemHueTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            Item item = World.FindItem(serial);\r\n            if (item != null)\r\n            {\r\n                Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, 0x3B2, 3,\r\n                    Language.CliLocName, \"System\",\r\n                    $\"Item Name: '{item.ItemID.ItemData.Name}' Serial: '{item.Serial}' Id: '{item.ItemID.Value}' Hue: '{item.Hue}'\"));\r\n            }\r\n        }\r\n\r\n        private static void GetMobile(string[] param)\r\n        {\r\n            ScriptManager.GetGumpInfo(param);\r\n        }\r\n\r\n        private static void Echo(string[] param)\r\n        {\r\n            StringBuilder sb = new StringBuilder(\"Note To Self: \");\r\n            for (int i = 0; i < param.Length; i++)\r\n                sb.Append(param[i]);\r\n            Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, 0x3B2, 3,\r\n                Language.CliLocName, \"System\", sb.ToString()));\r\n        }\r\n\r\n        private static void AddUseOnce(string[] param)\r\n        {\r\n            string use = Language.GetString(LocString.UseOnce);\r\n            for (int i = 0; i < Agent.List.Count; i++)\r\n            {\r\n                Agent a = Agent.List[i];\r\n                if (a.Name == use)\r\n                {\r\n                    a.OnButtonPress(1);\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void Time(string[] param)\r\n        {\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.CurTime,\r\n                Engine.MistedDateTime.ToString(\"MM/dd/yy HH:mm:ss.f\"));\r\n        }\r\n\r\n        private static void Where(string[] param)\r\n        {\r\n            string mapStr;\r\n            switch (World.Player.Map)\r\n            {\r\n                case 0:\r\n                    mapStr = \"Felucca\";\r\n                    break;\r\n                case 1:\r\n                    mapStr = \"Trammel\";\r\n                    break;\r\n                case 2:\r\n                    mapStr = \"Ilshenar\";\r\n                    break;\r\n                case 3:\r\n                    mapStr = \"Malas\";\r\n                    break;\r\n                case 4:\r\n                    mapStr = \"Tokuno\";\r\n                    break;\r\n                case 0x7F:\r\n                    mapStr = \"Internal\";\r\n                    break;\r\n                default:\r\n                    mapStr = $\"Unknown (#{World.Player.Map})\";\r\n                    break;\r\n            }\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.CurLoc, World.Player.Position, mapStr);\r\n        }\r\n\r\n        private static void Ping(string[] param)\r\n        {\r\n            int count = 5;\r\n            if (param.Length > 0)\r\n                count = Utility.ToInt32(param[0], 5);\r\n\r\n            if (count > 10)\r\n                count = 10;\r\n\r\n            Assistant.Ping.StartPing(count);\r\n        }\r\n\r\n        private static void MacroCmd(string[] param)\r\n        {\r\n            if (param.Length <= 0)\r\n            {\r\n                World.Player.SendMessage(\"You must enter a macro name.\");\r\n                return;\r\n            }\r\n\r\n            string macroName = string.Join(\" \", param);\r\n\r\n            foreach (Macro m in MacroManager.List)\r\n            {\r\n                if (m.ToString().ToLower().Equals(macroName.ToLower()))\r\n                {\r\n                    MacroManager.HotKeyPlay(m);\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ScriptCmd(string[] param)\r\n        {\r\n            if (param.Length <= 0)\r\n            {\r\n                World.Player.SendMessage(\"You must enter a script name.\");\r\n                return;\r\n            }\r\n\r\n            string name = string.Join(\" \", param);\r\n\r\n            ScriptManager.PlayScript(name);\r\n        }\r\n    }\r\n\r\n    public delegate void CommandCallback(string[] param);\r\n\r\n    public class Command\r\n    {\r\n        private static Dictionary<string, CommandCallback> _commandList;\r\n\r\n        public static List<string> GetCommands => _commandList.Keys.ToList();\r\n\r\n        static Command()\r\n        {\r\n            _commandList = new Dictionary<string, CommandCallback>(16, StringComparer.OrdinalIgnoreCase);\r\n            PacketHandler.RegisterClientToServerFilter(0xAD, OnSpeech);\r\n        }\r\n\r\n        public static void ListCommands(string[] param)\r\n        {\r\n            System.Text.StringBuilder sb = new System.Text.StringBuilder();\r\n            foreach (string cmd in _commandList.Keys)\r\n            {\r\n                sb.Append(cmd);\r\n                sb.Append(\" \");\r\n            }\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.CommandList);\r\n            World.Player.SendMessage(MsgLevel.Force, sb.ToString());\r\n        }\r\n\r\n        public static void Register(string cmd, CommandCallback callback)\r\n        {\r\n            _commandList[cmd] = callback;\r\n        }\r\n\r\n        public static CommandCallback FindCommand(string cmd)\r\n        {\r\n            return _commandList[cmd] as CommandCallback;\r\n        }\r\n\r\n        public static void RemoveCommand(string cmd)\r\n        {\r\n            _commandList.Remove(cmd);\r\n        }\r\n\r\n        public static Dictionary<string, CommandCallback> List\r\n        {\r\n            get { return _commandList; }\r\n        }\r\n\r\n        public static void OnSpeech(Packet pvSrc, PacketHandlerEventArgs args)\r\n        {\r\n            MessageType type = (MessageType) pvSrc.ReadByte();\r\n            ushort hue = pvSrc.ReadUInt16();\r\n            ushort font = pvSrc.ReadUInt16();\r\n            string lang = pvSrc.ReadString(4);\r\n            string text = \"\";\r\n            ArrayList keys = null;\r\n            long txtOffset = 0;\r\n\r\n            World.Player.SpeechHue = hue;\r\n\r\n            if ((type & MessageType.Encoded) != 0)\r\n            {\r\n                int value = pvSrc.ReadInt16();\r\n                int count = (value & 0xFFF0) >> 4;\r\n                keys = new ArrayList();\r\n                keys.Add((ushort) value);\r\n\r\n                for (int i = 0; i < count; ++i)\r\n                {\r\n                    if ((i & 1) == 0)\r\n                    {\r\n                        keys.Add(pvSrc.ReadByte());\r\n                    }\r\n                    else\r\n                    {\r\n                        keys.Add(pvSrc.ReadByte());\r\n                        keys.Add(pvSrc.ReadByte());\r\n                    }\r\n                }\r\n\r\n                txtOffset = pvSrc.Position;\r\n                text = pvSrc.ReadUTF8StringSafe();\r\n                type &= ~MessageType.Encoded;\r\n            }\r\n            else\r\n            {\r\n                txtOffset = pvSrc.Position;\r\n                text = pvSrc.ReadUnicodeStringSafe();\r\n            }\r\n\r\n            text = text.Trim();\r\n\r\n            char commandToggle = Client.IsOSI ? '-' : '>';\r\n\r\n            if (text.Length > 0)\r\n            {\r\n                if (text[0] != commandToggle)\r\n                {\r\n                    Macros.MacroManager.Action(new Macros.SpeechAction(type, hue, font, lang, keys, text));\r\n                    ScriptManager.AddToScript($\"say \\'{text}\\'\");\r\n                }\r\n                else\r\n                {\r\n                    text = text.Substring(1);\r\n                    string[] split = text.Split(' ', '\\t');\r\n\r\n                    if (_commandList.ContainsKey(split[0]))\r\n                    {\r\n                        CommandCallback call = (CommandCallback) _commandList[split[0]];\r\n\r\n                        if (call != null)\r\n                        {\r\n                            string[] param = new string[split.Length - 1];\r\n                            for (int i = 0; i < param.Length; i++)\r\n                                param[i] = split[i + 1];\r\n                            call(param);\r\n\r\n                            args.Block = true;\r\n                        }\r\n                    }\r\n                    else if (HotKey.ExecuteCommand(split[0]))\r\n                    {\r\n                        args.Block = true;\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Force, \"Unknown command\");\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/ContainerLabels.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Xml;\n\nnamespace Assistant.Core\n{\n    public class ContainerLabels\n    {\n        public class ContainerLabel\n        {\n            public string Id { get; set; }\n            public string Type { get; set; }\n            public string Label { get; set; }\n            public int Hue { get; set; }\n            public string Alias { get; set; }\n        }\n\n        public static Serial LastContainerLabelDisplayed;\n\n        public static List<ContainerLabel> ContainerLabelList = new List<ContainerLabel>();\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (var label in ContainerLabelList)\n            {\n                xml.WriteStartElement(\"containerlabel\");\n                xml.WriteAttributeString(\"id\", label.Id);\n                xml.WriteAttributeString(\"type\", label.Type);\n                xml.WriteAttributeString(\"label\", label.Label);\n                xml.WriteAttributeString(\"hue\", label.Hue.ToString());\n                xml.WriteAttributeString(\"alias\", label.Alias);\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"containerlabel\"))\n                {\n                    ContainerLabel label = new ContainerLabel\n                    {\n                        Id = el.GetAttribute(\"id\"),\n                        Type = el.GetAttribute(\"type\"),\n                        Label = el.GetAttribute(\"label\"),\n                        Hue = Convert.ToInt32(el.GetAttribute(\"hue\")),\n                        Alias = el.GetAttribute(\"alias\")\n                    };\n\n                    ContainerLabelList.Add(label);\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n            \n            MessageManager.OnLabelMessage += HandleLabelMessage;\n        }\n        \n        private static void HandleLabelMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\n                         MessageType type, ushort hue, ushort font, string lang, string sourceName,\n                         string text)\n        {\n            if (Config.GetBool(\"ShowContainerLabels\") && source.IsItem)\n            {\n                Item item = World.FindItem(source);\n\n                if (item == null || !item.IsContainer)\n                    return;\n\n                foreach (ContainerLabel label in ContainerLabelList)\n                {\n                    // Check if its the serial match and if the text matches the name (since we override that for the label)\n                    if (Serial.Parse(label.Id) == source &&\n                        (item.ItemID.ItemData.Name.Equals(text) ||\n                         label.Alias.Equals(text, StringComparison.OrdinalIgnoreCase)))\n                    {\n                        string labelDisplay =\n                            $\"{Config.GetString(\"ContainerLabelFormat\").Replace(\"{label}\", label.Label).Replace(\"{type}\", text)}\";\n\n                        //ContainerLabelStyle\n                        if (Config.GetInt(\"ContainerLabelStyle\") == 0)\n                        {\n                            Client.Instance.SendToClient(new AsciiMessage(source, item.ItemID.Value, MessageType.Label,\n                                label.Hue, 3, Language.CliLocName, labelDisplay));\n                        }\n                        else\n                        {\n                            Client.Instance.SendToClient(new UnicodeMessage(source, item.ItemID.Value,\n                                MessageType.Label, label.Hue, 3, Language.CliLocName, \"\", labelDisplay));\n                        }\n\n                        // block the actual message from coming through since we have it in the label\n                        args.Block = true;\n\n                        LastContainerLabelDisplayed = source;\n\n                        break;\n                    }\n                }\n            }\n        }\n\n        public static void ClearAll()\n        {\n            ContainerLabelList.Clear();\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/CooldownManager.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Text;\nusing Assistant.Gumps.Internal;\n\nnamespace Assistant.Core\n{\n    public static class CooldownManager\n    {\n        private static Timer CooldownTimer { get; set; }\n        public static Dictionary<string, Cooldown> Cooldowns { get; private set; }\n\n        private static CooldownGump _gump;\n\n        public static void Initialize()\n        {\n            CooldownTimer = new InternalTimer();\n            Cooldowns = new Dictionary<string, Cooldown>();\n        }\n\n        public static bool Running => CooldownTimer.Running;\n\n        public static void Start()\n        {\n            if (CooldownTimer.Running)\n            {\n                CooldownTimer.Stop();\n            }\n\n            CooldownTimer.Start();\n        }\n\n        public static void Stop()\n        {\n            if (!CooldownTimer.Running)\n                return;\n\n            _gump.CloseGump();\n            Cooldowns.Clear();\n\n            CooldownTimer.Stop();\n        }\n\n        private class InternalTimer : Timer\n        {\n            public InternalTimer() : base(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                if (World.Player == null)\n                {\n                    CooldownTimer.Stop();\n                    return;\n                }\n\n                _gump?.CloseGump();\n                \n                RemoveExpired();\n                \n                if (Cooldowns.Count > 0)\n                {\n                    _gump = new CooldownGump();\n                    _gump.SendGump();    \n                }\n            }\n        }\n\n        public static void AddCooldown(Cooldown cooldown)\n        {\n            Cooldowns[cooldown.Name] = cooldown;\n\n            if (!CooldownTimer.Running)\n            {\n                Start();\n            }\n        }\n\n        public static void AddCooldown(string name, int seconds, int hue = 0, int icon = 0, int sound = 0, bool stayVisible = false)\n        {\n            Cooldowns[name] = new Cooldown\n            {\n                Name = name,\n                Seconds = seconds,\n                EndTime = DateTime.UtcNow.AddSeconds(seconds),\n                Hue = hue,\n                Icon = icon,\n                SoundId = sound,\n                StayVisible = stayVisible\n            };\n\n            if (!CooldownTimer.Running)\n            {\n                Start();\n            }\n        }\n\n        public static void RemoveExpired()\n        {\n            foreach (KeyValuePair<string, Cooldown> cooldown in Cooldowns.ToList())\n            {\n                if (cooldown.Value.StayVisible)\n                {\n                    continue;\n                }\n                \n                TimeSpan diff = cooldown.Value.EndTime - DateTime.UtcNow;\n                int timeLeft = (int)diff.TotalSeconds;\n\n                if (timeLeft <= 0)\n                {\n                    if (cooldown.Value.SoundId > 0)\n                    {\n                        Client.Instance.SendToClient(new PlaySound(cooldown.Value.SoundId));\n                    }\n                    \n                    Cooldowns.Remove(cooldown.Key);\n                }\n            }\n        }\n        \n    }\n\n    public class Cooldown\n    {\n        public string Name { get; set; }\n        public int Seconds { get; set; }\n        public DateTime EndTime { get; set; }\n        public int Hue { get; set; }\n        public int Icon { get; set; } //30010 - 30057\n        public int SoundId { get; set; }\n        public bool StayVisible { get; set; }\n        public Color ForegroundColor { get; set; }\n        public Color BackgroundColor { get; set; }\n\n    }\n}"
  },
  {
    "path": "Razor/Core/Counters.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Text;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Windows.Forms;\r\nusing System.Xml;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant\r\n{\r\n    public class CounterLVIComparer : IComparer\r\n    {\r\n        private static CounterLVIComparer m_Instance;\r\n\r\n        public static CounterLVIComparer Instance\r\n        {\r\n            get\r\n            {\r\n                if (m_Instance == null)\r\n                    m_Instance = new CounterLVIComparer();\r\n                return m_Instance;\r\n            }\r\n        }\r\n\r\n        public CounterLVIComparer()\r\n        {\r\n        }\r\n\r\n        public int Compare(object a, object b)\r\n        {\r\n            return ((IComparable) (((ListViewItem) a).Tag)).CompareTo(((ListViewItem) b).Tag);\r\n        }\r\n    }\r\n\r\n    public class ItemCountCache\r\n    {\r\n        private Dictionary<Item, ulong> _cache = new Dictionary<Item, ulong>();\r\n\r\n        public long Add(Item item)\r\n        {\r\n            if (_cache.TryGetValue(item, out var old))\r\n            {\r\n                var diff = item.Amount - old;\r\n                _cache[item] = item.Amount;\r\n                return (long)diff;\r\n            }\r\n            else\r\n            {\r\n                _cache.Add(item, item.Amount);\r\n                return item.Amount;\r\n            }\r\n        }\r\n\r\n        public long Remove(Item item)\r\n        {\r\n            if (_cache.TryGetValue(item, out var old))\r\n            {\r\n                var diff = Math.Min(item.Amount, old);\r\n                _cache.Remove(item);\r\n                return -(long)diff;\r\n            }\r\n\r\n            // Item was untracked in the first place, hence no change\r\n            return 0;\r\n        }\r\n\r\n        public void Reset()\r\n        {\r\n            _cache.Clear();\r\n        }\r\n    }\r\n\r\n    public struct CounterID\r\n    {\r\n        public CounterID(ItemID itemID, ushort hue = 0xFFFF)\r\n        {\r\n            ItemID = itemID;\r\n            Hue = hue;\r\n        }\r\n\r\n        public ItemID ItemID;\r\n        public ushort Hue;\r\n    }\r\n\r\n    public class CounterChangeSet\r\n    {\r\n        public Dictionary<CounterID, long> Changes = new Dictionary<CounterID, long>();\r\n\r\n        private void AddValue(CounterID id, long diff)\r\n        {\r\n            if (Changes.ContainsKey(id))\r\n            {\r\n                Changes[id] += diff;\r\n            }\r\n            else\r\n            {\r\n                Changes.Add(id, diff);\r\n            }\r\n\r\n            if (Changes[id] == 0)\r\n            {\r\n                Changes.Remove(id);\r\n            }\r\n        }\r\n\r\n        public void Add(CounterChangeSet other)\r\n        {\r\n            foreach (var item in other.Changes)\r\n            {\r\n                AddValue(item.Key, item.Value);\r\n            }\r\n        }\r\n\r\n        public void Add(Item item, long diff)\r\n        {\r\n            AddValue(new CounterID(item.ItemID, item.Hue), diff);\r\n            AddValue(new CounterID(item.ItemID), diff);\r\n        }\r\n\r\n        public void Reset()\r\n        {\r\n            Changes.Clear();\r\n        }\r\n    }\r\n\r\n    public class ItemChangeTracker\r\n    {\r\n        private ItemCountCache _cache = new ItemCountCache();\r\n\r\n        public void Add(Item item, ref CounterChangeSet changes)\r\n        {\r\n            var diff = _cache.Add(item);\r\n            if (diff != 0)\r\n            {\r\n                changes.Add(item, diff);\r\n            }\r\n        }\r\n\r\n        public void Remove(Item item, ref CounterChangeSet changes)\r\n        {\r\n            var diff = _cache.Remove(item);\r\n            if (diff != 0)\r\n            {\r\n                changes.Add(item, diff);\r\n            }\r\n        }\r\n\r\n        public void Reset()\r\n        {\r\n            _cache.Reset();\r\n        }\r\n    }\r\n\r\n    public class RecursiveItemChangeTracker\r\n    {\r\n        private ItemChangeTracker _tracker = new ItemChangeTracker();\r\n\r\n        public void Add(Item item, ref CounterChangeSet changes)\r\n        {\r\n            _tracker.Add(item, ref changes);\r\n\r\n            foreach (var child in item.Contains)\r\n            {\r\n                Add(child, ref changes);\r\n            }\r\n        }\r\n\r\n        public void Remove(Item item, ref CounterChangeSet changes)\r\n        {\r\n            foreach (var child in item.Contains)\r\n            {\r\n                Remove(child, ref changes);\r\n            }\r\n\r\n            _tracker.Remove(item, ref changes);\r\n        }\r\n\r\n        public void Reset()\r\n        {\r\n            _tracker.Reset();\r\n        }\r\n    }\r\n\r\n    public class ItemTypeCounter\r\n    {\r\n        private CounterChangeSet _counters = new CounterChangeSet();\r\n        private RecursiveItemChangeTracker _tracker = new RecursiveItemChangeTracker();\r\n\r\n        public CounterChangeSet Count(Item item)\r\n        {\r\n            var changes = new CounterChangeSet();\r\n            _tracker.Add(item, ref changes);\r\n            _counters.Add(changes);\r\n            return changes;\r\n        }\r\n\r\n        public CounterChangeSet Uncount(Item item)\r\n        {\r\n            var changes = new CounterChangeSet();\r\n            _tracker.Remove(item, ref changes);\r\n            _counters.Add(changes);\r\n            return changes;\r\n        }\r\n\r\n        public ulong GetValue(ItemID itemID, ushort hue)\r\n        {\r\n            return GetValue(new CounterID(itemID, hue));\r\n        }\r\n\r\n        public ulong GetValue(CounterID id)\r\n        {\r\n            if (_counters.Changes.TryGetValue(id, out var value))\r\n            {\r\n                return (value > 0) ? (ulong)value : 0;\r\n            }\r\n\r\n            return 0;\r\n        }\r\n\r\n        public void Reset()\r\n        {\r\n            _counters.Reset();\r\n            _tracker.Reset();\r\n        }\r\n    }\r\n\r\n    public class Counter : IComparable\r\n    {\r\n        private string m_Name;\r\n        private string m_Fmt;\r\n        private ushort m_ItemID;\r\n        private int m_Hue;\r\n        private int m_Count;\r\n        private bool m_Enabled;\r\n        private DateTime m_LastWarning;\r\n        private bool m_Flag;\r\n        private bool m_DispImg;\r\n        private ListViewItem m_LVI;\r\n\r\n        public Counter(string name, string fmt, ushort iid, int hue, bool dispImg)\r\n        {\r\n            m_Name = name;\r\n            m_Fmt = fmt;\r\n            m_ItemID = iid;\r\n            m_Hue = hue;\r\n            m_LVI = new ListViewItem(new string[2]);\r\n            m_LVI.SubItems[0].Text = ToString();\r\n            m_LVI.Tag = this;\r\n            m_LVI.Checked = m_Enabled = false;\r\n            m_Count = 0;\r\n            m_DispImg = dispImg;\r\n\r\n            m_NeedXMLSave = true;\r\n        }\r\n\r\n        public Counter(XmlElement node)\r\n        {\r\n            m_Name = GetText(node[\"name\"], \"\");\r\n            m_Fmt = GetText(node[\"format\"], \"\");\r\n            m_ItemID = (ushort) GetInt(GetText(node[\"itemid\"], \"0\"), 0);\r\n            m_Hue = GetInt(GetText(node[\"hue\"], \"-1\"), -1);\r\n\r\n            m_LVI = new ListViewItem(new string[2] {this.ToString(), \"\"});\r\n            m_LVI.Tag = this;\r\n            m_LVI.Checked = m_Enabled = false;\r\n\r\n            m_DispImg = true;\r\n        }\r\n\r\n        public void Save(XmlTextWriter xml)\r\n        {\r\n            xml.WriteStartElement(\"counter\");\r\n\r\n            xml.WriteStartElement(\"name\");\r\n            xml.WriteString(m_Name);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"format\");\r\n            xml.WriteString(m_Fmt);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"itemid\");\r\n            xml.WriteString(m_ItemID.ToString());\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"hue\");\r\n            xml.WriteString(m_Hue.ToString());\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteEndElement();\r\n        }\r\n\r\n        public string Name\r\n        {\r\n            get { return m_Name; }\r\n        }\r\n\r\n        public string Format\r\n        {\r\n            get { return m_Fmt; }\r\n        }\r\n\r\n        public ushort ItemID\r\n        {\r\n            get { return m_ItemID; }\r\n        }\r\n\r\n        public int Hue\r\n        {\r\n            get { return m_Hue; }\r\n        }\r\n\r\n        public bool Flag\r\n        {\r\n            get { return m_Flag; }\r\n            set { m_Flag = value; }\r\n        }\r\n\r\n        public ListViewItem ViewItem\r\n        {\r\n            get { return m_LVI; }\r\n        }\r\n\r\n        public void Set(ushort iid, int hue, string name, string fmt, bool dispImg)\r\n        {\r\n            m_ItemID = iid;\r\n            m_Hue = hue;\r\n            m_Name = name;\r\n            m_Fmt = fmt;\r\n            m_DispImg = dispImg;\r\n\r\n            m_LVI.SubItems[0].Text = ToString();\r\n            m_NeedXMLSave = true;\r\n        }\r\n\r\n        public string GetTitlebarString(bool dispImg, bool dispColor)\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n            if (dispImg)\r\n            {\r\n                sb.AppendFormat(\"~I{0:X4}\", m_ItemID);\r\n                if (m_Hue > 0 && m_Hue < 0xFFFF)\r\n                    sb.Append(m_Hue.ToString(\"X4\"));\r\n                else\r\n                    sb.Append('~');\r\n                sb.Append(\": \");\r\n            }\r\n\r\n            if (!dispColor)\r\n                sb.Append(m_Count.ToString());\r\n            else if (m_Flag && Config.GetBool(\"HighlightReagents\"))\r\n                sb.AppendFormat(\"~^C00000{0}~#~\", m_Count);\r\n            else if (m_Count == 0 || m_Count < Config.GetInt(\"CounterWarnAmount\"))\r\n                sb.AppendFormat(\"~#FF0000{0}~#~\", m_Count);\r\n            else\r\n                sb.Append(m_Count.ToString());\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public CounterID CounterID\r\n        {\r\n            get\r\n            {\r\n                return new CounterID(ItemID, (ushort)((Hue == -1) ? 0xFFFF : Hue));\r\n            }\r\n        }\r\n\r\n        public static int GetCount(ItemID itemID, int hue)\r\n        {\r\n            ushort fixedHue = (ushort)((hue == -1) ? 0xFFFF : hue);\r\n            return (int)m_PackCounter.GetValue(itemID, fixedHue);\r\n        }\r\n\r\n        public static Counter FindCounter(string name)\r\n        {\r\n            foreach (Counter c in List)\r\n            {\r\n                if (c.Name.Equals(name, StringComparison.OrdinalIgnoreCase))\r\n                {\r\n                    return c.Enabled ? c : null;\r\n                }\r\n            }\r\n\r\n            return null;\r\n        }\r\n        \r\n        private void OnUpdate()\r\n        {\r\n            var newValue = (int)m_PackCounter.GetValue(CounterID);\r\n            if (m_Count != newValue)\r\n            {\r\n                if (m_Enabled)\r\n                {\r\n                    if (!SupressWarnings && m_LastWarning + TimeSpan.FromSeconds(1.0) < DateTime.UtcNow &&\r\n                        World.Player != null && newValue < m_Count && Config.GetBool(\"CounterWarn\") &&\r\n                        newValue < Config.GetInt(\"CounterWarnAmount\"))\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Warning, LocString.CountLow, Name, newValue);\r\n                        m_LastWarning = DateTime.UtcNow;\r\n                    }\r\n\r\n                    if (UOAssist.NotificationCount > 0)\r\n                    {\r\n                        int wp = 0;\r\n                        if (Format == \"bm\")\r\n                            wp = 1;\r\n                        else if (Format == \"bp\")\r\n                            wp = 2;\r\n                        else if (Format == \"gl\")\r\n                            wp = 3;\r\n                        else if (Format == \"gs\")\r\n                            wp = 4;\r\n                        else if (Format == \"mr\")\r\n                            wp = 5;\r\n                        else if (Format == \"ns\")\r\n                            wp = 6;\r\n                        else if (Format == \"sa\")\r\n                            wp = 7;\r\n                        else if (Format == \"ss\")\r\n                            wp = 8;\r\n                        else if (Format == \"bw\")\r\n                            wp = 100;\r\n                        else if (Format == \"db\")\r\n                            wp = 101;\r\n                        else if (Format == \"gd\")\r\n                            wp = 102;\r\n                        else if (Format == \"nc\")\r\n                            wp = 103;\r\n                        else if (Format == \"pi\")\r\n                            wp = 104;\r\n\r\n                        if (wp != 0)\r\n                            UOAssist.PostCounterUpdate(wp, newValue);\r\n                    }\r\n\r\n                    m_Count = newValue;\r\n                    if (m_Count < 0)\r\n                        m_Count = 0;\r\n\r\n                    //Engine.MainWindow.RefreshCounters();\r\n                    Client.Instance.RequestTitlebarUpdate();\r\n                }\r\n\r\n                m_LVI.SubItems[1].Text = m_Count.ToString();\r\n            }\r\n        }\r\n\r\n        public int Amount\r\n        {\r\n            get => m_Count;\r\n        }\r\n\r\n        public void SetEnabled(bool value)\r\n        {\r\n            m_Enabled = value;\r\n            if (m_Enabled)\r\n            {\r\n                if (!SupressChecks)\r\n                    QuickRecount();\r\n                m_LVI.SubItems[1].Text = m_Count.ToString();\r\n            }\r\n            else\r\n            {\r\n                m_LVI.SubItems[1].Text = \"\";\r\n            }\r\n        }\r\n\r\n        public bool Enabled\r\n        {\r\n            get { return m_Enabled; }\r\n            set\r\n            {\r\n                if (m_Enabled != value)\r\n                {\r\n                    m_LVI.Checked = value;\r\n                    SetEnabled(value);\r\n                }\r\n            }\r\n        }\r\n\r\n        public bool DisplayImage\r\n        {\r\n            get { return m_DispImg; }\r\n            set { m_DispImg = value; }\r\n        }\r\n\r\n        public int CompareTo(object comp)\r\n        {\r\n            if (!(comp is Counter))\r\n                return 1;\r\n            else if (this.Enabled && ((Counter) comp).Enabled)\r\n                return this.Name == null ? 1 :\r\n                    ((Counter) comp).Name == null ? -1 : this.Name.CompareTo(((Counter) comp).Name);\r\n            else if (!this.Enabled && ((Counter) comp).Enabled)\r\n                return 1;\r\n            else if (this.Enabled && !((Counter) comp).Enabled)\r\n                return -1;\r\n            else //if ( !this.Enabled && !((Counter)comp).Enabled )\r\n                return this.Name == null ? 1 :\r\n                    ((Counter) comp).Name == null ? -1 : this.Name.CompareTo(((Counter) comp).Name);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"{Name} ({Format})\";\r\n        }\r\n\r\n        private static bool m_NeedXMLSave = false;\r\n        private static List<Counter> m_List = new List<Counter>();\r\n        private static bool m_SupressWarn, m_SupressChecks;\r\n        private static ItemTypeCounter m_PackCounter = new ItemTypeCounter();\r\n\r\n        public static List<Counter> List\r\n        {\r\n            get { return m_List; }\r\n        }\r\n\r\n        static Counter()\r\n        {\r\n            m_List = new List<Counter>();\r\n            Load();\r\n        }\r\n\r\n        public static bool SupressWarnings\r\n        {\r\n            get { return m_SupressWarn; }\r\n            set { m_SupressWarn = value; }\r\n        }\r\n\r\n        public static bool SupressChecks\r\n        {\r\n            get { return m_SupressChecks; }\r\n        }\r\n\r\n        private static void Load()\r\n        {\r\n            string file = Path.Combine(Config.GetUserDirectory(), \"counters.xml\");\r\n            if (!File.Exists(file))\r\n                return;\r\n\r\n            try\r\n            {\r\n                XmlDocument doc = new XmlDocument();\r\n                doc.Load(file);\r\n\r\n                XmlElement root = doc[\"counters\"];\r\n                if (root != null)\r\n                {\r\n                    foreach (XmlElement node in root.GetElementsByTagName(\"counter\"))\r\n                        m_List.Add(new Counter(node));\r\n                }\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(Engine.ActiveWindow, Language.GetString(LocString.CounterFux),\r\n                    \"Counters.xml Load Error\", MessageBoxButtons.OK, MessageBoxIcon.Stop);\r\n            }\r\n\r\n            m_NeedXMLSave = false;\r\n        }\r\n\r\n        public static void Save()\r\n        {\r\n            if (!m_NeedXMLSave)\r\n                return;\r\n\r\n            try\r\n            {\r\n                string file = Path.Combine(Config.GetUserDirectory(), \"counters.xml\");\r\n                using (StreamWriter op = new StreamWriter(file))\r\n                {\r\n                    XmlTextWriter xml = new XmlTextWriter(op);\r\n\r\n                    xml.Formatting = Formatting.Indented;\r\n                    xml.IndentChar = '\\t';\r\n                    xml.Indentation = 1;\r\n\r\n                    xml.WriteStartDocument(true);\r\n\r\n                    xml.WriteStartElement(\"counters\");\r\n\r\n                    foreach (Counter c in m_List)\r\n                        c.Save(xml);\r\n\r\n                    xml.WriteEndElement();\r\n                    xml.Close();\r\n                }\r\n\r\n                m_NeedXMLSave = false;\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public static void SaveProfile(XmlTextWriter xml)\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                Counter c = m_List[i];\r\n                if (c.Enabled)\r\n                {\r\n                    xml.WriteStartElement(\"counter\");\r\n                    xml.WriteAttributeString(\"name\", c.Name);\r\n                    xml.WriteAttributeString(\"enabled\", c.Enabled.ToString());\r\n                    xml.WriteAttributeString(\"image\", c.DisplayImage.ToString());\r\n                    xml.WriteEndElement();\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Default()\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                Counter c = m_List[i];\r\n\r\n                if (c.Format == \"bp\" || c.Format == \"bm\" || c.Format == \"gl\" || c.Format == \"gs\" ||\r\n                    c.Format == \"mr\" || c.Format == \"ns\" || c.Format == \"ss\" || c.Format == \"sa\" ||\r\n                    c.Format == \"aids\")\r\n                {\r\n                    c.Enabled = true;\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void DisableAll()\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n                m_List[i].Enabled = false;\r\n        }\r\n\r\n        public static void LoadProfile(XmlElement xml)\r\n        {\r\n            Reset();\r\n            DisableAll();\r\n\r\n            if (xml == null)\r\n                return;\r\n\r\n            foreach (XmlElement el in xml.GetElementsByTagName(\"counter\"))\r\n            {\r\n                try\r\n                {\r\n                    string name = el.GetAttribute(\"name\");\r\n                    string en = el.GetAttribute(\"enabled\");\r\n                    string img = el.GetAttribute(\"image\");\r\n\r\n                    for (int i = 0; i < m_List.Count; i++)\r\n                    {\r\n                        Counter c = m_List[i];\r\n\r\n                        if (c.Name == name)\r\n                        {\r\n                            c.Enabled = Convert.ToBoolean(en);\r\n                            try\r\n                            {\r\n                                c.DisplayImage = Convert.ToBoolean(img);\r\n                            }\r\n                            catch\r\n                            {\r\n                                c.DisplayImage = true;\r\n                            }\r\n\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        private static string GetText(XmlElement node, string defaultValue)\r\n        {\r\n            if (node == null)\r\n                return defaultValue;\r\n\r\n            return node.InnerText;\r\n        }\r\n\r\n        private static int GetInt(string value, int def)\r\n        {\r\n            try\r\n            {\r\n                return XmlConvert.ToInt32(value);\r\n            }\r\n            catch\r\n            {\r\n                try\r\n                {\r\n                    return Convert.ToInt32(value);\r\n                }\r\n                catch\r\n                {\r\n                    return def;\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Register(Counter c)\r\n        {\r\n            m_List.Add(c);\r\n            m_NeedXMLSave = true;\r\n            Engine.MainWindow.SafeAction(s => s.RedrawCounters());\r\n        }\r\n\r\n        private static void OnCountsChanged(CounterChangeSet changes)\r\n        {\r\n            foreach (var c in m_List)\r\n            {\r\n                if (changes.Changes.ContainsKey(c.CounterID))\r\n                {\r\n                    c.OnUpdate();\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Uncount(Item item)\r\n        {\r\n            var changes = m_PackCounter.Uncount(item);\r\n            OnCountsChanged(changes);\r\n        }\r\n\r\n        public static void Count(Item item)\r\n        {\r\n            var changes = m_PackCounter.Count(item);\r\n            OnCountsChanged(changes);\r\n        }\r\n\r\n        public static void QuickRecount()\r\n        {\r\n            Reset();\r\n\r\n            SupressWarnings = true;\r\n            Item pack = World.Player == null ? null : World.Player.Backpack;\r\n            if (pack != null)\r\n                Count(pack);\r\n            pack = World.Player == null ? null : World.Player.Quiver;\r\n            if (pack != null)\r\n                Count(pack);\r\n            SupressWarnings = false;\r\n        }\r\n\r\n        public static void FullRecount()\r\n        {\r\n            Reset();\r\n\r\n            if (World.Player != null)\r\n            {\r\n                SupressWarnings = true;\r\n\r\n                if (World.Player.Backpack != null)\r\n                {\r\n                    while (World.Player.Backpack.Contains.Count > 0)\r\n                        ((Item) World.Player.Backpack.Contains[0]).Remove();\r\n\r\n                    PacketHandlers.IgnoreGumps.Add(World.Player.Backpack);\r\n                    PlayerData.DoubleClick(World.Player.Backpack);\r\n                }\r\n\r\n                if (World.Player.Quiver != null)\r\n                {\r\n                    while (World.Player.Quiver.Contains.Count > 0)\r\n                        ((Item) World.Player.Quiver.Contains[0]).Remove();\r\n\r\n                    PacketHandlers.IgnoreGumps.Add(World.Player.Quiver);\r\n                    PlayerData.DoubleClick(World.Player.Quiver);\r\n                }\r\n\r\n                if (!Config.GetBool(\"AutoSearch\"))\r\n                    World.Player.SendMessage(MsgLevel.Info, LocString.NoAutoCount);\r\n                SupressWarnings = false;\r\n            }\r\n        }\r\n\r\n        public static void Reset()\r\n        {\r\n            SupressWarnings = true;\r\n            m_PackCounter.Reset();\r\n\r\n            foreach (var c in m_List)\r\n            {\r\n                c.OnUpdate();\r\n            }\r\n            SupressWarnings = false;\r\n        }\r\n\r\n        public static void Redraw(ListView list)\r\n        {\r\n            m_SupressChecks = true;\r\n            list.BeginUpdate();\r\n            list.Items.Clear();\r\n            for (int i = 0; i < m_List.Count; i++)\r\n                list.Items.Add(m_List[i].ViewItem);\r\n            list.EndUpdate();\r\n            m_SupressChecks = false;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/DamageTracker.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Assistant.Gumps.Internal;\n\nnamespace Assistant.Core\n{\n    public class DamageTracker\n    {\n        private static readonly Timer DamageTrackerTimer;\n        private static DateTime StartTime;\n\n        public static double DamagePerSecond { get; set; }\n        public static double MaxDamagePerSecond { get; set; }\n        public static int TotalDamageDealt { get; set; }\n        public static int TotalDamageTaken { get; set; }\n\n        public static int MaxSingleDamageDealt { get; set; }\n        public static string MaxSingleDamageDealtName { get; set; }\n\n        public static int MaxSingleDamageTaken { get; set; }\n\n        public static ConcurrentDictionary<string, int> TotalDamageDealtByName;\n\n        private static DamageTrackerGump _gump;\n\n        static DamageTracker()\n        {\n            DamageTrackerTimer = new InternalTimer();\n            StartTime = DateTime.UtcNow;\n        }\n\n        public static bool Running => DamageTrackerTimer.Running;\n\n        public static void Start()\n        {\n            TotalDamageDealt = 0;\n            MaxSingleDamageDealt = 0;\n            DamagePerSecond = 0;\n            MaxDamagePerSecond = 0;\n\n            TotalDamageDealtByName = new ConcurrentDictionary<string, int>();\n\n            StartTime = DateTime.UtcNow;\n\n            if (DamageTrackerTimer.Running)\n            {\n                DamageTrackerTimer.Stop();\n            }\n\n            DamageTrackerTimer.Start();\n            Client.Instance.RequestTitlebarUpdate();\n\n            if (World.Player != null)\n                World.Player.SendMessage(MsgLevel.Force, \"-- [Damage Tracking Started] ---\");\n        }\n\n        public static void Stop()\n        {\n            if (!DamageTrackerTimer.Running)\n                return;\n\n            _gump.CloseGump();\n\n            DamageTrackerTimer.Stop();\n            Client.Instance.RequestTitlebarUpdate();\n\n            if (World.Player != null)\n            {\n                SendReport();\n            }\n        }\n\n        public static void SendReport()\n        {\n            if (World.Player == null)\n                return;\n\n            World.Player.SendMessage(MsgLevel.Force, \"-- [Damage Tracking Stopped] ---\");\n            World.Player.SendMessage(MsgLevel.Force, $\"Total Damage Dealt: {TotalDamageDealt}\");\n            World.Player.SendMessage(MsgLevel.Force, $\"Total Damage Taken: {TotalDamageTaken}\");\n            World.Player.SendMessage(MsgLevel.Force,\n                $\"Max Single Damage Dealt: {MaxSingleDamageDealt} on '{MaxSingleDamageDealtName}'\");\n            World.Player.SendMessage(MsgLevel.Force, $\"Max Single Damage Taken: {MaxSingleDamageTaken}\");\n            World.Player.SendMessage(MsgLevel.Force, $\"Final DPS: {DamagePerSecond:N2}\");\n            World.Player.SendMessage(MsgLevel.Force, $\"Max DPS: {MaxDamagePerSecond:N2}\");\n\n            List<KeyValuePair<string, int>> topFive =\n                (from mob in TotalDamageDealtByName orderby mob.Value descending select mob)\n                .ToDictionary(pair => pair.Key, pair => pair.Value).Take(5).ToList();\n\n            if (topFive.Count > 0)\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"-- [Top 5 Damage Dealt By Name] ---\");\n\n                int x = 1;\n                foreach (KeyValuePair<string, int> top in topFive)\n                {\n                    World.Player.SendMessage(MsgLevel.Force, $\"{x}) {top.Key} [{top.Value:N2}]\");\n                    x++;\n                }\n            }\n        }\n\n        public static List<KeyValuePair<string, int>> GetTotalDamageList()\n        {\n            List<KeyValuePair<string, int>> sortedList =\n                (from mob in TotalDamageDealtByName orderby mob.Value descending select mob)\n                .ToDictionary(pair => pair.Key, pair => pair.Value).ToList();\n\n            return sortedList;\n        }\n\n        private class InternalTimer : Timer\n        {\n            private StringBuilder _damageInfo = new StringBuilder();\n\n            public InternalTimer() : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                if (World.Player == null)\n                {\n                    DamageTracker.Stop();\n                    return;\n                }\n\n                _gump?.CloseGump();\n\n                TimeSpan span = DateTime.UtcNow.Subtract(StartTime);\n\n                DamagePerSecond = span.Seconds > 0 ? TotalDamageDealt / span.TotalSeconds : 0;\n\n                if (DamagePerSecond > MaxDamagePerSecond)\n                    MaxDamagePerSecond = DamagePerSecond;\n\n                //Client.Instance.RequestTitlebarUpdate();\n\n                _damageInfo.AppendLine($\"Total Damage Dealt: {TotalDamageDealt}\");\n                _damageInfo.AppendLine($\"Total Damage Taken: {TotalDamageTaken}\");\n                _damageInfo.AppendLine($\"Max Damage Dealt: {MaxSingleDamageDealt} on '{MaxSingleDamageDealtName}'\");\n                _damageInfo.AppendLine($\"Max Damage Taken: {MaxSingleDamageTaken}\");\n\n                _gump = new DamageTrackerGump(_damageInfo.ToString());\n                _gump.SendGump();\n\n                _damageInfo.Clear();\n            }\n        }\n\n        public static void AddDamage(uint serial, ushort damage)\n        {\n            Mobile mob = World.FindMobile(serial);\n\n            if (mob == null)\n                return;\n\n            if (World.Player.Serial == serial) // Track damage you taken\n            {\n                if (damage > MaxSingleDamageTaken)\n                {\n                    MaxSingleDamageTaken = damage;\n                }\n\n                TotalDamageTaken += damage;\n            }\n            else // track damage you deal out\n            {\n                if (damage > MaxSingleDamageDealt)\n                {\n                    MaxSingleDamageDealt = damage;\n                    MaxSingleDamageDealtName = mob.Name;\n                }\n\n                TotalDamageDealt += damage;\n\n                if (TotalDamageDealtByName.ContainsKey(mob.Name))\n                {\n                    TotalDamageDealtByName[mob.Name] += damage;\n                }\n                else\n                {\n                    TotalDamageDealtByName.TryAdd(mob.Name, damage);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/Dress.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Assistant.Core\n{\n    public static class Dress\n    {\n        private static Item m_Right, m_Left;\n\n        public static void ToggleRight()\n        {\n            if (World.Player == null)\n                return;\n\n            Item item = World.Player.GetItemOnLayer(Layer.RightHand);\n            if (item == null)\n            {\n                if (m_Right != null)\n                    m_Right = World.FindItem(m_Right.Serial);\n\n                if (m_Right != null && m_Right.IsChildOf(World.Player.Backpack))\n                {\n                    // try to also undress conflicting hand(s)\n                    Item conflict = World.Player.GetItemOnLayer(Layer.LeftHand);\n                    if (conflict != null && (conflict.IsTwoHanded || m_Right.IsTwoHanded))\n                    {\n                        Unequip(DressList.GetLayerFor(conflict));\n                    }\n\n                    Equip(m_Right, DressList.GetLayerFor(m_Right));\n                }\n                else\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.MustDisarm);\n                }\n            }\n            else\n            {\n                Unequip(DressList.GetLayerFor(item));\n                m_Right = item;\n            }\n        }\n\n        public static void ToggleLeft()\n        {\n            if (World.Player == null || World.Player.Backpack == null)\n                return;\n\n            Item item = World.Player.GetItemOnLayer(Layer.LeftHand);\n            if (item == null)\n            {\n                if (m_Left != null)\n                    m_Left = World.FindItem(m_Left.Serial);\n\n                if (m_Left != null && m_Left.IsChildOf(World.Player.Backpack))\n                {\n                    Item conflict = World.Player.GetItemOnLayer(Layer.RightHand);\n                    if (conflict != null && (conflict.IsTwoHanded || m_Left.IsTwoHanded))\n                    {\n                        Unequip(DressList.GetLayerFor(conflict));\n                    }\n\n                    Equip(m_Left, DressList.GetLayerFor(m_Left));\n                }\n                else\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.MustDisarm);\n                }\n            }\n            else\n            {\n                Unequip(DressList.GetLayerFor(item));\n                m_Left = item;\n            }\n        }\n\n        public static bool Equip(Item item, Layer layer)\n        {\n            if (layer == Layer.Invalid || layer > Layer.LastUserValid || item == null || item.Layer == Layer.Invalid ||\n                item.Layer > Layer.LastUserValid)\n                return false;\n\n            if (item != null && World.Player != null && item.IsChildOf(World.Player.Backpack))\n            {\n                DragDropManager.DragDrop(item, World.Player, layer);\n                return true;\n            }\n\n            return false;\n        }\n\n        public static bool Unequip(Layer layer)\n        {\n            if (layer == Layer.Invalid || layer > Layer.LastUserValid)\n                return false;\n\n            Item item = World.Player.GetItemOnLayer(layer);\n            if (item != null)\n            {\n                Item pack = DressList.FindUndressBag(item);\n                if (pack != null)\n                {\n                    DragDropManager.DragDrop(item, pack);\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/DressList.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Xml;\r\nusing System.Windows.Forms;\r\nusing Assistant.Scripts;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant\r\n{\r\n    public class DressList\r\n    {\r\n        private static readonly List<DressList> m_List = new List<DressList>();\r\n        private static ListBox _dressList;\r\n        private static ListBox _dressItems;\r\n\r\n        public static void SetControls(ListBox dressList, ListBox dressItems)\r\n        {\r\n            _dressList = dressList;\r\n            _dressItems = dressItems;\r\n        }\r\n\r\n        public static void Redraw()\r\n        {\r\n            _dressList.SafeAction(s => s.Items.Clear());\r\n            _dressItems.SafeAction(s => s.Items.Clear());\r\n\r\n            _dressList.SafeAction(s => s.Items.AddRange(m_List.ToArray()));\r\n        }\r\n\r\n        public static void ClearAll()\r\n        {\r\n            _dressList?.SafeAction(s => s.Items.Clear());\r\n            _dressItems?.SafeAction(s => s.Items.Clear());\r\n\r\n            while (m_List.Count > 0)\r\n                Remove(m_List[0]);\r\n        }\r\n\r\n        public static DressList Find(string name)\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                DressList list = m_List[i];\r\n                if (list.Name == name)\r\n                    return list;\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        public static Item FindUndressBag(Item item)\r\n        {\r\n            Item undressBag = World.Player.Backpack;\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                DressList list = m_List[i];\r\n                if (list != null && (list.Items.Contains(item.Serial) || list.Items.Contains(item.ItemID)))\r\n                {\r\n                    if (list.m_UndressBag.IsValid)\r\n                    {\r\n                        Item bag = World.FindItem(list.m_UndressBag);\r\n                        if (bag != null && (bag.RootContainer == World.Player ||\r\n                                            (bag.RootContainer == null && Utility.InRange(bag.GetWorldPosition(),\r\n                                                 World.Player.Position, 2))))\r\n                            undressBag = bag;\r\n                    }\r\n\r\n                    break;\r\n                }\r\n            }\r\n\r\n            return undressBag;\r\n        }\r\n\r\n        public static void Load(XmlElement xml)\r\n        {\r\n            ClearAll();\r\n\r\n            if (xml == null)\r\n                return;\r\n\r\n            foreach (XmlElement el in xml.GetElementsByTagName(\"list\"))\r\n            {\r\n                try\r\n                {\r\n                    string name = el.GetAttribute(\"name\");\r\n                    DressList list = new DressList(name);\r\n                    Add(list);\r\n\r\n                    try\r\n                    {\r\n                        list.m_UndressBag = Serial.Parse(el.GetAttribute(\"undressbag\"));\r\n                    }\r\n                    catch\r\n                    {\r\n                        list.m_UndressBag = Serial.Zero;\r\n                    }\r\n\r\n                    foreach (XmlElement el2 in el.GetElementsByTagName(\"item\"))\r\n                    {\r\n                        try\r\n                        {\r\n                            string ser = el2.GetAttribute(\"serial\");\r\n                            list.Items.Add((Serial) Convert.ToUInt32(ser));\r\n                        }\r\n                        catch\r\n                        {\r\n                            try\r\n                            {\r\n                                string iid = el2.GetAttribute(\"id\");\r\n                                list.Items.Add((ItemID) Convert.ToUInt16(iid));\r\n                            }\r\n                            catch\r\n                            {\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Save(XmlTextWriter xml)\r\n        {\r\n            foreach (DressList list in m_List)\r\n            {\r\n                xml.WriteStartElement(\"list\");\r\n                xml.WriteAttributeString(\"name\", list.Name);\r\n\r\n                if (list.m_UndressBag.IsItem)\r\n                    xml.WriteAttributeString(\"undressbag\", list.m_UndressBag.ToString());\r\n\r\n                foreach (object o in list.Items)\r\n                {\r\n                    xml.WriteStartElement(\"item\");\r\n                    if (o is Serial)\r\n                        xml.WriteAttributeString(\"serial\", ((Serial) o).Value.ToString());\r\n                    else if (o is ItemID)\r\n                        xml.WriteAttributeString(\"id\", ((ItemID) o).Value.ToString());\r\n                    xml.WriteEndElement();\r\n                }\r\n\r\n                xml.WriteEndElement();\r\n            }\r\n        }\r\n\r\n        public static void Add(DressList list)\r\n        {\r\n            if (Engine.MainWindow == null)\r\n            {\r\n                m_List.Add(list);\r\n                HotKey.Add(HKCategory.Dress, HKSubCat.None, $\"Dress: {list.Name}\",\r\n                    new HotKeyCallback(list.Dress));\r\n                HotKey.Add(HKCategory.Dress, HKSubCat.None, $\"Undress: {list.Name}\",\r\n                    new HotKeyCallback(list.Undress));\r\n                HotKey.Add(HKCategory.Dress, HKSubCat.None, $\"Toggle: {list.Name}\",\r\n                    new HotKeyCallback(list.Toggle));\r\n            }\r\n            else\r\n            {\r\n                Engine.MainWindow.SafeAction(s =>\r\n                {\r\n                    m_List.Add(list);\r\n                    HotKey.Add(HKCategory.Dress, HKSubCat.None, $\"Dress: {list.Name}\",\r\n                        new HotKeyCallback(list.Dress));\r\n                    HotKey.Add(HKCategory.Dress, HKSubCat.None, $\"Undress: {list.Name}\",\r\n                        new HotKeyCallback(list.Undress));\r\n                    HotKey.Add(HKCategory.Dress, HKSubCat.None, $\"Toggle: {list.Name}\",\r\n                        new HotKeyCallback(list.Toggle));\r\n                });\r\n            }\r\n        }\r\n\r\n        public static void Remove(DressList list)\r\n        {\r\n            if (Engine.MainWindow == null)\r\n            {\r\n                m_List.Remove(list);\r\n                HotKey.Remove($\"Dress: {list.Name}\");\r\n                HotKey.Remove($\"Undress: {list.Name}\");\r\n                HotKey.Remove($\"Toggle: {list.Name}\");\r\n            }\r\n            else\r\n            {\r\n                Engine.MainWindow.SafeAction(s =>\r\n                {\r\n                    m_List.Remove(list);\r\n                    HotKey.Remove($\"Dress: {list.Name}\");\r\n                    HotKey.Remove($\"Undress: {list.Name}\");\r\n                    HotKey.Remove($\"Toggle: {list.Name}\");\r\n                });\r\n            }\r\n        }\r\n\r\n        private Serial m_UndressBag;\r\n\r\n        public DressList(string name)\r\n        {\r\n            Name = name;\r\n            Items = new List<object>();\r\n            m_UndressBag = Serial.Zero;\r\n        }\r\n\r\n        public DressList(XmlElement xml)\r\n        {\r\n            Name = xml.GetAttribute(\"name\");\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Name;\r\n        }\r\n\r\n        public string Name { get; }\r\n        public List<object> Items { get; }\r\n\r\n        public void SetUndressBag(Serial serial)\r\n        {\r\n            if (serial == World.Player.Backpack.Serial || !serial.IsItem)\r\n                m_UndressBag = Serial.Zero;\r\n            else\r\n                m_UndressBag = serial;\r\n        }\r\n\r\n        public void Toggle()\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            int worn = 0;\r\n            int total = Items.Count;\r\n\r\n            for (int i = 0; i < Items.Count; i++)\r\n            {\r\n                Item item = null;\r\n                if (Items[i] is Serial)\r\n                    item = World.FindItem((Serial) Items[i]);\r\n                else if (Items[i] is ItemID)\r\n                    item = World.Player.FindItemByID((ItemID) Items[i]);\r\n\r\n                if (item == null)\r\n                    total--;\r\n                else if (item.Container == World.Player)\r\n                    worn++;\r\n            }\r\n\r\n            if (Items.Count == 1)\r\n            {\r\n                if (worn != 0)\r\n                    Undress();\r\n                else\r\n                    Dress();\r\n            }\r\n            else\r\n            {\r\n                if (worn > total / 2)\r\n                    Undress();\r\n                else\r\n                    Dress();\r\n            }\r\n        }\r\n\r\n        public void Undress()\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            int count = 0;\r\n            Item undressBag = World.Player.Backpack;\r\n            if (undressBag == null)\r\n            {\r\n                World.Player.SendMessage(LocString.NoBackpack);\r\n                return;\r\n            }\r\n\r\n            if (Macros.MacroManager.AcceptActions)\r\n                Macros.MacroManager.Action(new Macros.UnDressAction(Name));\r\n\r\n            if (ScriptManager.Recording)\r\n                ScriptManager.AddToScript($\"undress '{Name}'\");\r\n\r\n            if (m_UndressBag.IsValid)\r\n            {\r\n                Item bag = World.FindItem(m_UndressBag);\r\n                if (bag != null && (bag.RootContainer == World.Player ||\r\n                                    (bag.RootContainer == null && Utility.InRange(bag.GetWorldPosition(),\r\n                                         World.Player.Position, 2))))\r\n                    undressBag = bag;\r\n                else\r\n                    World.Player.SendMessage(LocString.UndressBagRange);\r\n            }\r\n\r\n            for (int i = 0; i < Items.Count; i++)\r\n            {\r\n                Item item = null;\r\n                if (Items[i] is Serial)\r\n                    item = World.FindItem((Serial) Items[i]);\r\n                else if (Items[i] is ItemID)\r\n                    item = World.Player.FindItemByID((ItemID) Items[i]);\r\n\r\n                if (item == null || DragDropManager.CancelDragFor(item.Serial) || item.Container != World.Player)\r\n                {\r\n                    continue;\r\n                }\r\n                else\r\n                {\r\n                    DragDropManager.DragDrop(item, undressBag);\r\n                    count++;\r\n                }\r\n            }\r\n\r\n            World.Player.SendMessage(LocString.UndressQueued, count);\r\n        }\r\n\r\n        public static Layer GetLayerFor(Item item)\r\n        {\r\n            Layer layer = item.Layer;\r\n            if (layer == Layer.Invalid || layer > Layer.LastUserValid)\r\n                layer = (Layer) item.ItemID.ItemData.Quality;\r\n\r\n            return layer;\r\n        }\r\n\r\n        public void Dress()\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            int skipped = 0, gone = 0, done = 0;\r\n            List<Item> list = new List<Item>();\r\n            bool remConflicts = Config.GetBool(\"UndressConflicts\");\r\n\r\n            if (World.Player.Backpack == null)\r\n            {\r\n                World.Player.SendMessage(LocString.NoBackpack);\r\n                return;\r\n            }\r\n\r\n            if (Macros.MacroManager.AcceptActions)\r\n                Macros.MacroManager.Action(new Macros.DressAction(Name));\r\n\r\n            ScriptManager.AddToScript($\"dress '{Name}'\");\r\n\r\n            for (int i = 0; i < Items.Count; i++)\r\n            {\r\n                Item item = null;\r\n                if (Items[i] is Serial)\r\n                {\r\n                    item = World.FindItem((Serial) Items[i]);\r\n                    if (item == null)\r\n                        gone++;\r\n                    else\r\n                        list.Add(item);\r\n                }\r\n                else if (Items[i] is ItemID)\r\n                {\r\n                    ItemID id = (ItemID) Items[i];\r\n\r\n                    // search to make sure they are not already wearing this...\r\n                    item = World.Player.FindItemByID(id);\r\n                    if (item != null)\r\n                    {\r\n                        skipped++;\r\n                    }\r\n                    else\r\n                    {\r\n                        item = World.Player.Backpack.FindItemById(id);\r\n                        if (item == null)\r\n                            gone++;\r\n                        else\r\n                            list.Add(item);\r\n                    }\r\n                }\r\n            }\r\n\r\n            foreach (Item item in list)\r\n            {\r\n                if (item.Container == World.Player)\r\n                {\r\n                    skipped++;\r\n                }\r\n                else if (item.IsChildOf(World.Player.Backpack) || item.RootContainer == null)\r\n                {\r\n                    Layer layer = GetLayerFor(item);\r\n                    if (layer == Layer.Invalid || layer > Layer.LastUserValid)\r\n                        continue;\r\n\r\n                    if (remConflicts)\r\n                    {\r\n                        Item conflict = World.Player.GetItemOnLayer(layer);\r\n                        if (conflict != null)\r\n                            DragDropManager.DragDrop(conflict, FindUndressBag(conflict));\r\n\r\n                        // try to also undress conflicting hand(s)\r\n                        if (layer == Layer.RightHand)\r\n                            conflict = World.Player.GetItemOnLayer(Layer.LeftHand);\r\n                        else if (layer == Layer.LeftHand)\r\n                            conflict = World.Player.GetItemOnLayer(Layer.RightHand);\r\n                        else\r\n                            conflict = null;\r\n\r\n                        if (conflict != null && (conflict.IsTwoHanded || item.IsTwoHanded))\r\n                            DragDropManager.DragDrop(conflict, FindUndressBag(conflict));\r\n                    }\r\n\r\n                    DragDropManager.DragDrop(item, World.Player, layer);\r\n                    done++;\r\n                }\r\n            }\r\n\r\n            if (done > 0)\r\n                World.Player.SendMessage(LocString.DressQueued, done);\r\n            if (skipped > 0)\r\n                World.Player.SendMessage(LocString.AlreadyDressed, skipped);\r\n            if (gone > 0)\r\n                World.Player.SendMessage(LocString.ItemsNotFound, gone);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/EncodedSpeech.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\nnamespace Assistant.Core\n{\n    public class EncodedSpeech\n    {\n        internal class SpeechEntry : IComparable<SpeechEntry>\n        {\n            internal short m_KeywordID;\n            internal string[] m_Keywords;\n\n            internal SpeechEntry(int idKeyword, string keyword)\n            {\n                m_KeywordID = (short) idKeyword;\n                m_Keywords = keyword.Split(new char[] {'*'});\n            }\n\n            public int CompareTo(SpeechEntry entry)\n            {\n                if (entry == null)\n                {\n                    return -1;\n                }\n\n                if (entry != this)\n                {\n                    if (m_KeywordID < entry.m_KeywordID)\n                    {\n                        return -1;\n                    }\n\n                    if (m_KeywordID > entry.m_KeywordID)\n                    {\n                        return 1;\n                    }\n                }\n\n                return 0;\n            }\n        }\n\n        private static List<SpeechEntry> m_Speech;\n        internal static unsafe void LoadSpeechTable()\n        {\n            string path = Ultima.Files.GetFilePath(\"Speech.mul\");\n\n            if (!File.Exists(path))\n            {\n                m_Speech = new List<SpeechEntry>();\n            }\n            else\n            {\n                m_Speech = new List<SpeechEntry>();\n                byte[] buffer = new byte[0x400];\n                fixed (byte* numRef = buffer)\n                {\n                    using(var file = new FileStream(path, FileMode.Open,FileAccess.Read))\n                        while (file.Position < file.Length)\n                        {\n                            int id = (ushort)((file.ReadByte() << 8) | file.ReadByte());\n                            int length = (ushort)((file.ReadByte() << 8) | file.ReadByte());\n                            if (length > 0 && file.Position + length <= file.Length)\n                            {\n                                file.Read(buffer, 0, length);\n                                m_Speech.Add(new SpeechEntry(id, new string((sbyte*) numRef,0, length)));\n                            }\n                        }\n                }\n\n            }\n            \n        }\n\n        internal static List<ushort> GetKeywords(string text)\n        {\n            List<ushort> keynumber = new List<ushort>();\n\n            if (m_Speech == null)\n            {\n                LoadSpeechTable();\n            }\n\n            text = text.ToLower();\n\n            List<SpeechEntry> keywords = new List<SpeechEntry>();\n            List<SpeechEntry> speech = m_Speech.ToList();\n            foreach (SpeechEntry entry in speech)\n            {\n                if (IsMatch(text, entry.m_Keywords))\n                {\n                    keywords.Add(entry);\n                }\n            }\n\n            keywords.Sort();\n\n            bool flag = false;\n\n            int numk = keywords.Count & 15;\n            int index = 0;\n            while (index < keywords.Count)\n            {\n                SpeechEntry entry = keywords[index];\n                int keywordID = entry.m_KeywordID;\n\n                if (flag)\n                {\n                    keynumber.Add((byte) (keywordID >> 4));\n                    numk = keywordID & 15;\n                }\n                else\n                {\n                    keynumber.Add((byte) ((numk << 4) | ((keywordID >> 8) & 15)));\n                    keynumber.Add((byte) keywordID);\n                }\n\n                index++;\n                flag = !flag;\n            }\n\n            if (!flag)\n            {\n                keynumber.Add((byte) (numk << 4));\n            }\n\n            return keynumber;\n        }\n\n        private static bool IsMatch(string input, string[] split)\n        {\n            int startIndex = 0;\n\n            for (int i = 0; i < split.Length; i++)\n            {\n                if (split[i].Length > 0)\n                {\n                    int index = input.IndexOf(split[i], startIndex);\n                    if ((index > 0) && (i == 0))\n                    {\n                        return false;\n                    }\n\n                    if (index < 0)\n                    {\n                        return false;\n                    }\n\n                    startIndex = index + split[i].Length;\n                }\n            }\n\n            return ((split[split.Length - 1].Length <= 0) || (startIndex == input.Length));\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/FriendsManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\n\nnamespace Assistant.Core\n{\n    public static class FriendsManager\n    {\n        private static ComboBox _friendGroups;\n        private static ListBox _friendList;\n\n        private static List<FriendGroup> FriendGroups = new List<FriendGroup>();\n\n        public static void SetControls(ComboBox friendsGroup, ListBox friendsList)\n        {\n            _friendGroups = friendsGroup;\n            _friendList = friendsList;\n        }\n\n        public static void OnTargetAddFriend(FriendGroup group)\n        {\n            World.Player.SendMessage(MsgLevel.Friend, LocString.TargFriendAdd);\n            Targeting.OneTimeTarget(group.OnAddFriendTarget);\n        }\n\n        public class Friend\n        {\n            public string Name { get; set; }\n            public Serial Serial { get; set; }\n\n            public override string ToString()\n            {\n                return $\"{Name} ({Serial})\";\n            }\n        }\n\n        public class FriendGroup\n        {\n            public string GroupName { get; set; }\n            public bool Enabled { get; set; }\n            public List<Friend> Friends { get; set; }\n\n            public string OverheadFormat { get; set; }\n            public int OverheadFormatHue { get; set; }\n            public bool OverheadFormatEnabled { get; set; }\n\n            public FriendGroup()\n            {\n                Friends = new List<Friend>();\n            }\n\n            public void AddHotKeys()\n            {\n                if (Engine.MainWindow == null)\n                {\n                    HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Add Target To: {GroupName}\", AddFriendToGroup);\n                    HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Toggle Group: {GroupName}\", ToggleFriendGroup);\n                    HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Add All Mobiles: {GroupName}\",\n                        AddAllMobileAsFriends);\n                    HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Add All Humanoids: {GroupName}\",\n                        AddAllHumanoidsAsFriends);\n                }\n                else\n                {\n                    Engine.MainWindow.SafeAction(s =>\n                    {\n                        HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Add Target To: {GroupName}\", AddFriendToGroup);\n                        HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Toggle Group: {GroupName}\", ToggleFriendGroup);\n                        HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Add All Mobiles: {GroupName}\",\n                            AddAllMobileAsFriends);\n                        HotKey.Add(HKCategory.Friends, HKSubCat.None, $\"Add All Humanoids: {GroupName}\",\n                            AddAllHumanoidsAsFriends);\n                    });\n                }\n            }\n\n            public void RemoveHotKeys()\n            {\n                if (Engine.MainWindow == null)\n                {\n                    HotKey.Remove($\"Add Target To: {GroupName}\");\n                    HotKey.Remove($\"Toggle Group: {GroupName}\");\n                    HotKey.Remove($\"Add All Mobiles: {GroupName}\");\n                    HotKey.Remove($\"Add All Humanoids: {GroupName}\");\n                }\n                else\n                {\n                    Engine.MainWindow.SafeAction(s =>\n                    {\n                        HotKey.Remove($\"Add Target To: {GroupName}\");\n                        HotKey.Remove($\"Toggle Group: {GroupName}\");\n                        HotKey.Remove($\"Add All Mobiles: {GroupName}\");\n                        HotKey.Remove($\"Add All Humanoids: {GroupName}\");\n                    });\n                }\n            }\n\n            public void AddFriendToGroup()\n            {\n                World.Player.SendMessage(MsgLevel.Friend, $\"Target friend to add to group '{GroupName}'\");\n                Targeting.OneTimeTarget(OnAddFriendTarget);\n            }\n\n            private void ToggleFriendGroup()\n            {\n                if (Enabled)\n                {\n                    World.Player.SendMessage(MsgLevel.Warning,\n                        $\"Friend group '{GroupName}' ({Friends.Count} friends) has been 'Disabled'\");\n                    Enabled = false;\n                }\n                else\n                {\n                    World.Player.SendMessage(MsgLevel.Info,\n                        $\"Friend group '{GroupName}' ({Friends.Count} friends) has been 'Enabled'\");\n                    Enabled = true;\n                }\n            }\n\n            public override string ToString()\n            {\n                return $\"{GroupName}\";\n            }\n\n            public void OnAddFriendTarget(bool location, Serial serial, Point3D loc, ushort gfx)\n            {\n                Engine.MainWindow.SafeAction(s => s.ShowMe());\n\n                if (!location && serial.IsMobile && serial != World.Player.Serial)\n                {\n                    Mobile m = World.FindMobile(serial);\n\n                    if (m == null)\n                        return;\n\n                    if (AddFriend(m.Name, serial))\n                    {\n                        m.ObjPropList.Add(Language.GetString(LocString.RazorFriend));\n                        m.OPLChanged();\n                    }\n                    else\n                    {\n                        World.Player.SendMessage(MsgLevel.Warning, $\"'{m.Name}' is already in '{GroupName}'\");\n                    }\n                }\n            }\n\n            public bool AddFriend(string friendName, Serial friendSerial)\n            {\n                if (Friends.Any(f => f.Serial == friendSerial) == false)\n                {\n                    Friend newFriend = new Friend\n                    {\n                        Name = friendName,\n                        Serial = friendSerial\n                    };\n\n                    Friends.Add(newFriend);\n\n                    if (_friendGroups.SelectedItem == this)\n                    {\n                        RedrawList(this);\n                    }\n\n                    World.Player?.SendMessage(MsgLevel.Friend, $\"Added '{friendName}' to '{GroupName}'\");\n\n                    return true;\n                }\n\n                return false;\n            }\n\n            public void AddAllMobileAsFriends()\n            {\n                List<Mobile> mobiles = World.MobilesInRange(12);\n\n                foreach (Mobile mobile in mobiles)\n                {\n                    if (!IsFriend(mobile.Serial) && mobile.Serial.IsMobile && mobile.Serial != World.Player.Serial)\n                    {\n                        if (AddFriend(mobile.Name, mobile.Serial))\n                        {\n                            mobile.ObjPropList.Add(Language.GetString(LocString.RazorFriend));\n                            mobile.OPLChanged();\n                        }\n                    }\n                }\n            }\n\n            public void AddAllHumanoidsAsFriends()\n            {\n                List<Mobile> mobiles = World.MobilesInRange(12);\n\n                foreach (Mobile mobile in mobiles)\n                {\n                    if (!IsFriend(mobile.Serial) && mobile.Serial.IsMobile && mobile.Serial != World.Player.Serial &&\n                        mobile.IsHuman)\n                    {\n                        if (AddFriend(mobile.Name, mobile.Serial))\n                        {\n                            mobile.ObjPropList.Add(Language.GetString(LocString.RazorFriend));\n                            mobile.OPLChanged();\n                        }\n                    }\n                }\n            }\n        }\n\n        public static bool IsFriendOverhead(Serial serial, ref FriendGroup group)\n        {\n            // Check if they have treat party as friends enabled and check the party if so\n            if (Config.GetBool(\"AutoFriend\") && PacketHandlers.Party.Contains(serial))\n                return true;\n            \n            // Loop through each friends group that is enabled\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup.Enabled && friendGroup.Friends.Any(f => f.Serial == serial))\n                {\n                    group = friendGroup;\n\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static bool IsFriend(Serial serial)\n        {\n            // Check if they have treat party as friends enabled and check the party if so\n            if (Config.GetBool(\"AutoFriend\") && PacketHandlers.Party.Contains(serial))\n                return true;\n\n            // Loop through each friends group that is enabled\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup.Enabled && friendGroup.Friends.Any(f => f.Serial == serial))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static void EnableFriendsGroup(FriendGroup group, bool enabled)\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup == group)\n                {\n                    friendGroup.Enabled = enabled;\n                    return;\n                }\n            }\n        }\n\n        public static bool FriendsGroupExists(string group)\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup.GroupName.ToLower().Equals(group.ToLower()))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static bool IsFriendsGroupEnabled(FriendGroup group)\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup == group)\n                {\n                    return friendGroup.Enabled;\n                }\n            }\n\n            return false;\n        }\n\n        public static bool RemoveFriend(FriendGroup group, int index)\n        {\n            foreach (var friendGroup in FriendGroups)\n            {\n                if (friendGroup == group)\n                {\n                    friendGroup.Friends.RemoveAt(index);\n\n                    RedrawList(group);\n\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static void ClearFriendGroup(string group)\n        {\n            foreach (var friendGroup in FriendGroups)\n            {\n                if (friendGroup.GroupName.Equals(group))\n                {\n                    friendGroup.Friends.Clear();\n                    return;\n                }\n            }\n        }\n\n        public static bool DeleteFriendGroup(FriendGroup group)\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup == group)\n                {\n                    friendGroup.RemoveHotKeys();\n                }\n            }\n\n            return FriendGroups.Remove(group);\n        }\n\n        public static void AddFriendGroup(string group)\n        {\n            FriendGroup friendGroup = new FriendGroup\n            {\n                Enabled = true,\n                GroupName = group,\n                Friends = new List<Friend>(),\n                OverheadFormatHue = 63,\n                OverheadFormat = \"[Friend]\",\n                OverheadFormatEnabled = true\n            };\n\n            friendGroup.AddHotKeys();\n\n            FriendGroups.Add(friendGroup);\n\n            RedrawGroup();\n        }\n\n        public static void SetOverheadFormat(FriendGroup group, string format)\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup == group)\n                {\n                    friendGroup.OverheadFormat = format;\n                    return;\n                }\n            }\n        }\n\n        public static void SetOverheadHue(FriendGroup group, int hue)\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup == group)\n                {\n                    friendGroup.OverheadFormatHue = hue;\n                    return;\n                }\n            }\n        }\n\n        public static void SetOverheadFormatEnabled(FriendGroup group, bool enabled)\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                if (friendGroup == group)\n                {\n                    friendGroup.OverheadFormatEnabled = enabled;\n                    return;\n                }\n            }\n        }\n\n        public static void ShowOverhead(Mobile mobile)\n        {\n            FriendGroup group = null;\n\n            if (IsFriendOverhead(mobile.Serial, ref group))\n            {\n                if (group == null && Config.GetBool(\"ShowPartyFriendOverhead\")) // If they are a friend with no group, must be a party member\n                {\n                    mobile.OverheadMessage(63, \"[Party-Friend]\");\n                }\n                else if (group != null && group.OverheadFormatEnabled)\n                {\n                    mobile.OverheadMessage(group.OverheadFormatHue, group.OverheadFormat);\n                }\n            }\n        }\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (var friendGroup in FriendGroups)\n            {\n                xml.WriteStartElement(\"group\");\n                xml.WriteAttributeString(\"name\", friendGroup.GroupName);\n                xml.WriteAttributeString(\"enabled\", friendGroup.Enabled.ToString());\n                xml.WriteAttributeString(\"overheadformat\", friendGroup.OverheadFormat);\n                xml.WriteAttributeString(\"overheadhue\", friendGroup.OverheadFormatHue.ToString());\n                xml.WriteAttributeString(\"overheadenabled\", friendGroup.OverheadFormatEnabled.ToString());\n\n                foreach (var friend in friendGroup.Friends)\n                {\n                    xml.WriteStartElement(\"friend\");\n                    xml.WriteAttributeString(\"name\", friend.Name);\n                    xml.WriteAttributeString(\"serial\", friend.Serial.ToString());\n                    xml.WriteEndElement();\n                }\n\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"group\"))\n                {\n                    FriendGroup friendGroup = new FriendGroup\n                    {\n                        GroupName = el.GetAttribute(\"name\"),\n                        Enabled = Convert.ToBoolean(el.GetAttribute(\"enabled\"))\n                    };\n\n                    // Newer versions didn't have these, so it will cause an error when loading for the first time\n                    // If any fail, just set defaults\n                    try\n                    {\n                        friendGroup.OverheadFormat = el.GetAttribute(\"overheadformat\");\n                        friendGroup.OverheadFormatHue = Convert.ToInt32(el.GetAttribute(\"overheadhue\"));\n                        friendGroup.OverheadFormatEnabled = Convert.ToBoolean(el.GetAttribute(\"overheadenabled\"));\n                    }\n                    catch\n                    {\n                        friendGroup.OverheadFormat = \"[Friend]\";\n                        friendGroup.OverheadFormatHue = 63;\n                        friendGroup.OverheadFormatEnabled = true;\n                    }\n\n                    friendGroup.AddHotKeys();\n\n                    foreach (XmlElement friendEl in el.GetElementsByTagName(\"friend\"))\n                    {\n                        try\n                        {\n                            Friend friend = new Friend\n                            {\n                                Name = friendEl.GetAttribute(\"name\"),\n                                Serial = Serial.Parse(friendEl.GetAttribute(\"serial\"))\n                            };\n\n                            friendGroup.Friends.Add(friend);\n                        }\n                        catch\n                        {\n                            // ignore this bad record, most likely a bad serial\n                        }\n                    }\n\n                    FriendGroups.Add(friendGroup);\n                }\n\n                RedrawAll();\n            }\n            catch (Exception ex)\n            {\n                Debug.WriteLine(ex);\n            }\n        }\n\n        public static void ClearAll()\n        {\n            foreach (FriendGroup friendGroup in FriendGroups)\n            {\n                friendGroup.RemoveHotKeys();\n            }\n\n            FriendGroups.Clear();\n        }\n\n        private static void RedrawAll()\n        {\n            RedrawGroup();\n\n            if (_friendGroups?.Items.Count > 0)\n            {\n                RedrawList((FriendGroup) _friendGroups.Items[0]);\n            }\n            else\n            {\n                RedrawList(null); // we just want to clear the list\n            }\n        }\n\n        public static void RedrawGroup()\n        {\n            _friendGroups?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                foreach (FriendGroup friendGroup in FriendGroups)\n                {\n                    s.Items.Add(friendGroup);\n                }\n\n                s.EndUpdate();\n\n                if (s.Items.Count > 0)\n                {\n                    s.SelectedIndex = 0;\n                }\n            });\n        }\n\n        public static void RedrawList(FriendGroup group)\n        {\n            _friendList?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                if (group != null)\n                {\n                    foreach (Friend friend in group.Friends)\n                    {\n                        s.Items.Add(friend);\n                    }\n                }\n\n                s.EndUpdate();\n            });\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/GateTimer.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Linq;\nusing Assistant.Core;\n\nnamespace Assistant\n{\n    public class GateTimer\n    {\n        private static int m_Count;\n        private static Timer m_Timer;\n\n        private static readonly int[] m_ClilocsStop = {502632};\n\n        private static readonly int[] m_ClilocsRestart = {501024};\n\n        static GateTimer()\n        {\n            m_Timer = new InternalTimer();\n            \n            MessageManager.OnSystemMessage += OnSystemMessage;\n        }\n\n        public static int Count\n        {\n            get { return m_Count; }\n        }\n        \n        private static void OnSystemMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\n            MessageType type, ushort hue, ushort font, string lang, string sourceName,\n            string msg)\n        {\n            if (Running)\n            {\n                if (m_ClilocsStop.Any(t => Language.GetCliloc(t) == msg))\n                {\n                    Stop();\n                }\n\n                if (m_ClilocsRestart.Any(t => Language.GetCliloc(t) == msg))\n                {\n                    Start();\n                }\n            }\n        }\n\n        public static bool Running\n        {\n            get { return m_Timer.Running; }\n        }\n\n        public static void Start()\n        {\n            m_Count = 0;\n\n            if (m_Timer.Running)\n            {\n                m_Timer.Stop();\n            }\n\n            m_Timer.Start();\n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        public static void Stop()\n        {\n            m_Timer.Stop();\n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        private class InternalTimer : Timer\n        {\n            public InternalTimer() : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                m_Count++;\n                if (m_Count > 30)\n                {\n                    Stop();\n                }\n\n                Client.Instance.RequestTitlebarUpdate();\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/Geometry.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\n\r\nnamespace Assistant\r\n{\r\n    public interface IPoint2D\r\n    {\r\n        int X { get; }\r\n        int Y { get; }\r\n    }\r\n\r\n    public interface IPoint3D : IPoint2D\r\n    {\r\n        int Z { get; }\r\n    }\r\n\r\n    public struct Point2D : IPoint2D\r\n    {\r\n        internal int m_X;\r\n        internal int m_Y;\r\n\r\n        public static readonly Point2D Zero = new Point2D(0, 0);\r\n        public static readonly Point2D MinusOne = new Point2D(-1, -1);\r\n\r\n        public Point2D(int x, int y)\r\n        {\r\n            m_X = x;\r\n            m_Y = y;\r\n        }\r\n\r\n        public Point2D(IPoint2D p) : this(p.X, p.Y)\r\n        {\r\n        }\r\n\r\n        public int X\r\n        {\r\n            get { return m_X; }\r\n            set { m_X = value; }\r\n        }\r\n\r\n        public int Y\r\n        {\r\n            get { return m_Y; }\r\n            set { m_Y = value; }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"({m_X}, {m_Y})\";\r\n        }\r\n\r\n        public override bool Equals(object o)\r\n        {\r\n            if (o == null || !(o is IPoint2D)) return false;\r\n\r\n            IPoint2D p = (IPoint2D) o;\r\n\r\n            return m_X == p.X && m_Y == p.Y;\r\n        }\r\n\r\n        public override int GetHashCode()\r\n        {\r\n            return m_X ^ m_Y;\r\n        }\r\n\r\n        public static bool operator ==(Point2D l, Point2D r)\r\n        {\r\n            return l.m_X == r.m_X && l.m_Y == r.m_Y;\r\n        }\r\n\r\n        public static bool operator !=(Point2D l, Point2D r)\r\n        {\r\n            return l.m_X != r.m_X || l.m_Y != r.m_Y;\r\n        }\r\n\r\n        public static bool operator ==(Point2D l, IPoint2D r)\r\n        {\r\n            return l.m_X == r.X && l.m_Y == r.Y;\r\n        }\r\n\r\n        public static bool operator !=(Point2D l, IPoint2D r)\r\n        {\r\n            return l.m_X != r.X || l.m_Y != r.Y;\r\n        }\r\n\r\n        public static bool operator >(Point2D l, Point2D r)\r\n        {\r\n            return l.m_X > r.m_X && l.m_Y > r.m_Y;\r\n        }\r\n\r\n        public static bool operator >(Point2D l, Point3D r)\r\n        {\r\n            return l.m_X > r.m_X && l.m_Y > r.m_Y;\r\n        }\r\n\r\n        public static bool operator >(Point2D l, IPoint2D r)\r\n        {\r\n            return l.m_X > r.X && l.m_Y > r.Y;\r\n        }\r\n\r\n        public static bool operator <(Point2D l, Point2D r)\r\n        {\r\n            return l.m_X < r.m_X && l.m_Y < r.m_Y;\r\n        }\r\n\r\n        public static bool operator <(Point2D l, Point3D r)\r\n        {\r\n            return l.m_X < r.m_X && l.m_Y < r.m_Y;\r\n        }\r\n\r\n        public static bool operator <(Point2D l, IPoint2D r)\r\n        {\r\n            return l.m_X < r.X && l.m_Y < r.Y;\r\n        }\r\n\r\n        public static bool operator >=(Point2D l, Point2D r)\r\n        {\r\n            return l.m_X >= r.m_X && l.m_Y >= r.m_Y;\r\n        }\r\n\r\n        public static bool operator >=(Point2D l, Point3D r)\r\n        {\r\n            return l.m_X >= r.m_X && l.m_Y >= r.m_Y;\r\n        }\r\n\r\n        public static bool operator >=(Point2D l, IPoint2D r)\r\n        {\r\n            return l.m_X >= r.X && l.m_Y >= r.Y;\r\n        }\r\n\r\n        public static bool operator <=(Point2D l, Point2D r)\r\n        {\r\n            return l.m_X <= r.m_X && l.m_Y <= r.m_Y;\r\n        }\r\n\r\n        public static bool operator <=(Point2D l, Point3D r)\r\n        {\r\n            return l.m_X <= r.m_X && l.m_Y <= r.m_Y;\r\n        }\r\n\r\n        public static bool operator <=(Point2D l, IPoint2D r)\r\n        {\r\n            return l.m_X <= r.X && l.m_Y <= r.Y;\r\n        }\r\n    }\r\n\r\n    public struct Point3D : IPoint3D\r\n    {\r\n        internal int m_X;\r\n        internal int m_Y;\r\n        internal int m_Z;\r\n\r\n        public static readonly Point3D Zero = new Point3D(0, 0, 0);\r\n        public static readonly Point3D MinusOne = new Point3D(-1, -1, 0);\r\n\r\n        public Point3D(int x, int y, int z)\r\n        {\r\n            m_X = x;\r\n            m_Y = y;\r\n            m_Z = z;\r\n        }\r\n\r\n        public Point3D(IPoint3D p) : this(p.X, p.Y, p.Z)\r\n        {\r\n        }\r\n\r\n        public Point3D(IPoint2D p, int z) : this(p.X, p.Y, z)\r\n        {\r\n        }\r\n\r\n        public int X\r\n        {\r\n            get { return m_X; }\r\n            set { m_X = value; }\r\n        }\r\n\r\n        public int Y\r\n        {\r\n            get { return m_Y; }\r\n            set { m_Y = value; }\r\n        }\r\n\r\n        public int Z\r\n        {\r\n            get { return m_Z; }\r\n            set { m_Z = value; }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"({m_X}, {m_Y}, {m_Z})\";\r\n        }\r\n\r\n        public override bool Equals(object o)\r\n        {\r\n            if (o == null || !(o is IPoint3D)) return false;\r\n\r\n            IPoint3D p = (IPoint3D) o;\r\n\r\n            return m_X == p.X && m_Y == p.Y && m_Z == p.Z;\r\n        }\r\n\r\n        public override int GetHashCode()\r\n        {\r\n            return m_X ^ m_Y ^ m_Z;\r\n        }\r\n\r\n        public static Point3D Parse(string value)\r\n        {\r\n            int start = value.IndexOf('(');\r\n            int end = value.IndexOf(',', start + 1);\r\n\r\n            string param1 = value.Substring(start + 1, end - (start + 1)).Trim();\r\n\r\n            start = end;\r\n            end = value.IndexOf(',', start + 1);\r\n\r\n            string param2 = value.Substring(start + 1, end - (start + 1)).Trim();\r\n\r\n            start = end;\r\n            end = value.IndexOf(')', start + 1);\r\n\r\n            string param3 = value.Substring(start + 1, end - (start + 1)).Trim();\r\n\r\n            return new Point3D(Convert.ToInt32(param1), Convert.ToInt32(param2), Convert.ToInt16(param3));\r\n        }\r\n\r\n        public static bool operator ==(Point3D l, Point3D r)\r\n        {\r\n            return l.m_X == r.m_X && l.m_Y == r.m_Y && l.m_Z == r.m_Z;\r\n        }\r\n\r\n        public static bool operator !=(Point3D l, Point3D r)\r\n        {\r\n            return l.m_X != r.m_X || l.m_Y != r.m_Y || l.m_Z != r.m_Z;\r\n        }\r\n\r\n        public static bool operator ==(Point3D l, IPoint3D r)\r\n        {\r\n            return l.m_X == r.X && l.m_Y == r.Y && l.m_Z == r.Z;\r\n        }\r\n\r\n        public static bool operator !=(Point3D l, IPoint3D r)\r\n        {\r\n            return l.m_X != r.X || l.m_Y != r.Y || l.m_Z != r.Z;\r\n        }\r\n\r\n        public static Point3D operator +(Point3D l, Point3D r)\r\n        {\r\n            return new Point3D(l.m_X + r.m_X, l.m_Y + r.m_Y, l.m_Z + r.m_Z);\r\n        }\r\n\r\n        public static Point3D operator -(Point3D l, Point3D r)\r\n        {\r\n            return new Point3D(l.m_X - r.m_X, l.m_Y - r.m_Y, l.m_Z - r.m_Z);\r\n        }\r\n    }\r\n\r\n    public struct Line2D\r\n    {\r\n        private Point2D m_Start, m_End;\r\n\r\n        public Line2D(IPoint2D start, IPoint2D end)\r\n        {\r\n            m_Start = new Point2D(start);\r\n            m_End = new Point2D(end);\r\n            Fix();\r\n        }\r\n\r\n        public void Fix()\r\n        {\r\n            if (m_Start > m_End)\r\n            {\r\n                Point2D temp = m_Start;\r\n                m_Start = m_End;\r\n                m_End = temp;\r\n            }\r\n        }\r\n\r\n        public Point2D Start\r\n        {\r\n            get { return m_Start; }\r\n            set\r\n            {\r\n                m_Start = value;\r\n                Fix();\r\n            }\r\n        }\r\n\r\n        public Point2D End\r\n        {\r\n            get { return m_End; }\r\n            set\r\n            {\r\n                m_End = value;\r\n                Fix();\r\n            }\r\n        }\r\n\r\n        public double Length\r\n        {\r\n            get\r\n            {\r\n                int run = m_End.X - m_Start.X;\r\n                int rise = m_End.Y - m_Start.Y;\r\n\r\n                return Math.Sqrt(run * run + rise * rise);\r\n            }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"--{m_Start}->{m_End}--\";\r\n        }\r\n\r\n        public override bool Equals(object o)\r\n        {\r\n            if (o == null || !(o is Line2D)) return false;\r\n\r\n            Line2D ln = (Line2D) o;\r\n\r\n            return m_Start == ln.m_Start && m_End == ln.m_End;\r\n        }\r\n\r\n        public override int GetHashCode()\r\n        {\r\n            return m_Start.GetHashCode() ^ (~m_End.GetHashCode());\r\n        }\r\n\r\n        public static bool operator ==(Line2D l, Line2D r)\r\n        {\r\n            return l.m_Start == r.m_Start && l.m_End == r.m_End;\r\n        }\r\n\r\n        public static bool operator !=(Line2D l, Line2D r)\r\n        {\r\n            return l.m_Start != r.m_Start || l.m_End != r.m_End;\r\n        }\r\n\r\n        public static bool operator >(Line2D l, Line2D r)\r\n        {\r\n            return l.m_Start > r.m_Start && l.m_End > r.m_End;\r\n        }\r\n\r\n        public static bool operator <(Line2D l, Line2D r)\r\n        {\r\n            return l.m_Start < r.m_Start && l.m_End < r.m_End;\r\n        }\r\n\r\n        public static bool operator >=(Line2D l, Line2D r)\r\n        {\r\n            return l.m_Start >= r.m_Start && l.m_End >= r.m_End;\r\n        }\r\n\r\n        public static bool operator <=(Line2D l, Line2D r)\r\n        {\r\n            return l.m_Start <= r.m_Start && l.m_End <= r.m_End;\r\n        }\r\n    }\r\n\r\n    public struct Rectangle2D\r\n    {\r\n        private Point2D m_Start;\r\n        private Point2D m_End;\r\n\r\n        public Rectangle2D(IPoint2D start, IPoint2D end)\r\n        {\r\n            m_Start = new Point2D(start);\r\n            m_End = new Point2D(end);\r\n        }\r\n\r\n        public Rectangle2D(int x, int y, int width, int height)\r\n        {\r\n            m_Start = new Point2D(x, y);\r\n            m_End = new Point2D(x + width, y + height);\r\n        }\r\n\r\n        public void Set(int x, int y, int width, int height)\r\n        {\r\n            m_Start = new Point2D(x, y);\r\n            m_End = new Point2D(x + width, y + height);\r\n        }\r\n\r\n        public static Rectangle2D Parse(string value)\r\n        {\r\n            int start = value.IndexOf('(');\r\n            int end = value.IndexOf(',', start + 1);\r\n\r\n            string param1 = value.Substring(start + 1, end - (start + 1)).Trim();\r\n\r\n            start = end;\r\n            end = value.IndexOf(',', start + 1);\r\n\r\n            string param2 = value.Substring(start + 1, end - (start + 1)).Trim();\r\n\r\n            start = end;\r\n            end = value.IndexOf(',', start + 1);\r\n\r\n            string param3 = value.Substring(start + 1, end - (start + 1)).Trim();\r\n\r\n            start = end;\r\n            end = value.IndexOf(')', start + 1);\r\n\r\n            string param4 = value.Substring(start + 1, end - (start + 1)).Trim();\r\n\r\n            return new Rectangle2D(Convert.ToInt32(param1), Convert.ToInt32(param2), Convert.ToInt32(param3),\r\n                Convert.ToInt32(param4));\r\n        }\r\n\r\n        public Point2D Start\r\n        {\r\n            get { return m_Start; }\r\n            set { m_Start = value; }\r\n        }\r\n\r\n        public Point2D End\r\n        {\r\n            get { return m_End; }\r\n            set { m_End = value; }\r\n        }\r\n\r\n        public int X\r\n        {\r\n            get { return m_Start.m_X; }\r\n            set { m_Start.m_X = value; }\r\n        }\r\n\r\n        public int Y\r\n        {\r\n            get { return m_Start.m_Y; }\r\n            set { m_Start.m_Y = value; }\r\n        }\r\n\r\n        public int Width\r\n        {\r\n            get { return m_End.m_X - m_Start.m_X; }\r\n            set { m_End.m_X = m_Start.m_X + value; }\r\n        }\r\n\r\n        public int Height\r\n        {\r\n            get { return m_End.m_Y - m_Start.m_Y; }\r\n            set { m_End.m_Y = m_Start.m_Y + value; }\r\n        }\r\n\r\n        public void MakeHold(Rectangle2D r)\r\n        {\r\n            if (r.m_Start.m_X < m_Start.m_X)\r\n                m_Start.m_X = r.m_Start.m_X;\r\n\r\n            if (r.m_Start.m_Y < m_Start.m_Y)\r\n                m_Start.m_Y = r.m_Start.m_Y;\r\n\r\n            if (r.m_End.m_X > m_End.m_X)\r\n                m_End.m_X = r.m_End.m_X;\r\n\r\n            if (r.m_End.m_Y > m_End.m_Y)\r\n                m_End.m_Y = r.m_End.m_Y;\r\n        }\r\n\r\n        // \"test\" must be smaller than this rectangle!\r\n        public bool Insersects(Rectangle2D test)\r\n        {\r\n            Point2D e1 = new Point2D(test.Start.X + test.Width, test.Start.Y);\r\n            Point2D e2 = new Point2D(test.Start.X, test.Start.Y + test.Width);\r\n\r\n            return Contains(test.Start) || Contains(test.End) || Contains(e1) || Contains(e2);\r\n        }\r\n\r\n        public bool Contains(Rectangle2D test)\r\n        {\r\n            Point2D e1 = new Point2D(test.Start.X + test.Width, test.Start.Y);\r\n            Point2D e2 = new Point2D(test.Start.X, test.Start.Y + test.Width);\r\n\r\n            return Contains(test.Start) && Contains(test.End) && Contains(e1) && Contains(e2);\r\n        }\r\n\r\n        public bool Contains(Point3D p)\r\n        {\r\n            return (m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y);\r\n            //return ( m_Start <= p && m_End > p );\r\n        }\r\n\r\n        public bool Contains(Point2D p)\r\n        {\r\n            return (m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y);\r\n            //return ( m_Start <= p && m_End > p );\r\n        }\r\n\r\n        public bool Contains(IPoint2D p)\r\n        {\r\n            return (m_Start <= p && m_End > p);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"({X}, {Y})+({Width}, {Height})\";\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/GoldPerHourTimer.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\n\nnamespace Assistant\n{\n    public class GoldPerHourTimer\n    {\n        private static Timer m_Timer;\n        private static DateTime m_StartTime;\n        private static int m_PrevGoldAmount;\n\n        private static bool m_PickedUpGold;\n\n        public static int GoldSinceStart { get; set; }\n        public static double GoldPerSecond { get; set; }\n        public static double GoldPerMinute { get; set; }\n        public static double GoldPerHour { get; set; }\n\n        static GoldPerHourTimer()\n        {\n            m_Timer = new InternalTimer();\n            m_StartTime = DateTime.UtcNow;\n        }\n\n        public static bool Running\n        {\n            get { return m_Timer.Running; }\n        }\n\n        public static double TotalMinutes { get; set; }\n\n        public static void Start()\n        {\n            GoldSinceStart = 0;\n            m_PrevGoldAmount = (int) World.Player.Gold;\n            m_StartTime = DateTime.UtcNow;\n\n            m_PickedUpGold = false;\n\n            if (m_Timer.Running)\n            {\n                m_Timer.Stop();\n            }\n\n            m_Timer.Start();\n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        public static void Stop()\n        {\n            m_Timer.Stop();\n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        private class InternalTimer : Timer\n        {\n            public InternalTimer() : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                if (World.Player == null)\n                {\n                    GoldPerHourTimer.Stop();\n                    return;\n                }\n\n                if (m_PrevGoldAmount != World.Player.Gold)\n                {\n                    if (GoldSinceStart + ((int) World.Player.Gold - m_PrevGoldAmount) > m_PrevGoldAmount)\n                    {\n                        GoldSinceStart = GoldSinceStart + ((int) World.Player.Gold - m_PrevGoldAmount);\n\n                        m_PickedUpGold = true;\n                    }\n                }\n\n                // Let's not start calculating until we've picked up gold\n                if (m_PickedUpGold == false)\n                {\n                    m_StartTime = DateTime.UtcNow;\n                    return;\n                }\n\n                TimeSpan span = DateTime.UtcNow.Subtract(m_StartTime);\n\n                GoldPerSecond = span.Seconds > 0 ? (double) GoldSinceStart / span.TotalSeconds : 0;\n                GoldPerMinute = span.Seconds > 0 ? (double) GoldSinceStart / (span.TotalSeconds / 60.0) : 0;\n                GoldPerHour = span.Seconds > 0 ? (double) GoldSinceStart / (span.TotalSeconds / 3600.0) : 0;\n\n                TotalMinutes = span.TotalMinutes;\n\n                Client.Instance.RequestTitlebarUpdate();\n\n                m_PrevGoldAmount = (int) World.Player.Gold;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/Item.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Collections.Generic;\r\nusing Assistant.Agents;\r\nusing Assistant.Core;\r\n\r\nnamespace Assistant\r\n{\r\n    public enum Layer : byte\r\n    {\r\n        Invalid = 0x00,\r\n\r\n        FirstValid = 0x01,\r\n\r\n        RightHand = 0x01,\r\n        LeftHand = 0x02,\r\n        Shoes = 0x03,\r\n        Pants = 0x04,\r\n        Shirt = 0x05,\r\n        Head = 0x06,\r\n        Gloves = 0x07,\r\n        Ring = 0x08,\r\n        Talisman = 0x09,\r\n        Neck = 0x0A,\r\n        Hair = 0x0B,\r\n        Waist = 0x0C,\r\n        InnerTorso = 0x0D,\r\n        Bracelet = 0x0E,\r\n        Face = 0x0F,\r\n        FacialHair = 0x10,\r\n        MiddleTorso = 0x11,\r\n        Earrings = 0x12,\r\n        Arms = 0x13,\r\n        Cloak = 0x14,\r\n        Backpack = 0x15,\r\n        OuterTorso = 0x16,\r\n        OuterLegs = 0x17,\r\n        InnerLegs = 0x18,\r\n\r\n        LastUserValid = 0x18,\r\n\r\n        Mount = 0x19,\r\n        ShopBuy = 0x1A,\r\n        ShopResale = 0x1B,\r\n        ShopSell = 0x1C,\r\n        Bank = 0x1D,\r\n\r\n        LastValid = 0x1D\r\n    }\r\n\r\n    public class Item : UOEntity\r\n    {\r\n        private ItemID _itemId;\r\n        private ushort _amount;\r\n        private byte _direction;\r\n\r\n        private bool _visible;\r\n        private bool _movable;\r\n\r\n        private Layer _layer;\r\n        private string _name;\r\n        private object _parent;\r\n        private int _price;\r\n        private string _buyDesc;\r\n        private List<Item> _items;\r\n\r\n        private bool _isNew;\r\n        private bool _autoStack;\r\n\r\n        private byte[] _housePacket;\r\n        private int _houseRev;\r\n\r\n        private byte _gridNum;\r\n        \r\n        public override void AfterLoad()\r\n        {\r\n            _items = new List<Item>();\r\n\r\n            for (int i = 0; i < Serial.Serials.Count; i++)\r\n            {\r\n                Serial s = Serial.Serials[i];\r\n                if (s.IsItem)\r\n                {\r\n                    Item item = World.FindItem(s);\r\n\r\n                    if (item != null)\r\n                    {\r\n                        _items[i] = item;\r\n                    }\r\n\r\n                    Serial.Serials.RemoveAt(i);\r\n                    i--;\r\n                }\r\n            }\r\n\r\n            UpdateContainer();\r\n        }\r\n\r\n        public Item(Serial serial) : base(serial)\r\n        {\r\n            _items = new List<Item>();\r\n\r\n            _visible = true;\r\n            _movable = true;\r\n\r\n            Agent.InvokeItemCreated(this);\r\n        }\r\n\r\n        public ItemID ItemID\r\n        {\r\n            get { return _itemId; }\r\n            set { _itemId = value; }\r\n        }\r\n\r\n        public ushort Amount\r\n        {\r\n            get { return _amount; }\r\n            set { _amount = value; }\r\n        }\r\n\r\n        public byte Direction\r\n        {\r\n            get { return _direction; }\r\n            set { _direction = value; }\r\n        }\r\n\r\n        public bool Visible\r\n        {\r\n            get { return _visible; }\r\n            set { _visible = value; }\r\n        }\r\n\r\n        public bool Movable\r\n        {\r\n            get { return _movable; }\r\n            set { _movable = value; }\r\n        }\r\n\r\n        public string Name\r\n        {\r\n            get\r\n            {\r\n                if (!string.IsNullOrEmpty(_name))\r\n                {\r\n                    return _name;\r\n                }\r\n                else\r\n                {\r\n                    return _itemId.ToString();\r\n                }\r\n            }\r\n            set\r\n            {\r\n                if (value != null)\r\n                    _name = value.Trim();\r\n                else\r\n                    _name = null;\r\n            }\r\n        }\r\n\r\n        public string DisplayName => _itemId.Value < Ultima.TileData.ItemTable.Length ? Ultima.TileData.ItemTable[_itemId.Value].Name : string.Empty;\r\n\r\n        public Layer Layer\r\n        {\r\n            get\r\n            {\r\n                if ((_layer < Layer.FirstValid || _layer > Layer.LastValid) &&\r\n                    ((this.ItemID.ItemData.Flags & Ultima.TileFlag.Wearable) != 0 ||\r\n                     (this.ItemID.ItemData.Flags & Ultima.TileFlag.Armor) != 0 ||\r\n                     (this.ItemID.ItemData.Flags & Ultima.TileFlag.Weapon) != 0\r\n                    ))\r\n                {\r\n                    _layer = (Layer) this.ItemID.ItemData.Quality;\r\n                }\r\n\r\n                return _layer;\r\n            }\r\n            set { _layer = value; }\r\n        }\r\n\r\n        public Item FindItemById(ItemID id)\r\n        {\r\n            return FindItemById(id, true);\r\n        }\r\n\r\n        public List<Item> FindItemsById(ItemID id)\r\n        {\r\n            return FindItemsById(id, true);\r\n        }\r\n\r\n        public Item FindItemById(ItemID id, bool recurse)\r\n        {\r\n            for (int i = 0; i < _items.Count; i++)\r\n            {\r\n                Item item = (Item) _items[i];\r\n                if (item.ItemID == id)\r\n                {\r\n                    return item;\r\n                }\r\n\r\n                if (recurse)\r\n                {\r\n                    item = item.FindItemById(id, true);\r\n                    if (item != null)\r\n                        return item;\r\n                }\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        public List<Item> FindItemsById(ItemID id, bool recurse)\r\n        {\r\n            List<Item> items = new List<Item>();\r\n\r\n            for (int i = 0; i < _items.Count; i++)\r\n            {\r\n                Item item = _items[i];\r\n                if (item.ItemID == id)\r\n                {\r\n                    items.Add(item);\r\n                }\r\n                \r\n                if (recurse)\r\n                {\r\n                    List<Item> recurseItems = item.FindItemsById(id, true);\r\n\r\n                    if (recurseItems.Count > 0)\r\n                    {\r\n                        items.AddRange(recurseItems);\r\n                    }\r\n                }\r\n            }\r\n\r\n            return items;\r\n        }\r\n\r\n        public Item FindItemByName(string name, bool recurse)\r\n        {\r\n            foreach (var i in _items)\r\n            {\r\n                Item item = i;\r\n                \r\n                if (item.ItemID.ItemData.Name.Equals(name, StringComparison.OrdinalIgnoreCase))\r\n                {\r\n                    return item;\r\n                }\r\n\r\n                if (recurse)\r\n                {\r\n                    item = item.FindItemByName(name, true);\r\n                    if (item != null)\r\n                        return item;\r\n                }\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        public List<Item> FindItemsByName(string name, bool recurse)\r\n        {\r\n            List<Item> items = new List<Item>();\r\n\r\n            foreach (Item i in _items)\r\n            {\r\n                if (i.ItemID.ItemData.Name.Equals(name, StringComparison.OrdinalIgnoreCase))\r\n                {\r\n                    items.Add(i);\r\n                }\r\n                \r\n                if (recurse)\r\n                {\r\n                    List<Item> recurseItems = i.FindItemsByName(name, true);\r\n                    if (recurseItems.Count > 0)\r\n                    {\r\n                        items.AddRange(recurseItems);\r\n                    }\r\n                }\r\n            }\r\n\r\n            return items;\r\n        }\r\n\r\n        public int GetCount(ushort iid)\r\n        {\r\n            int count = 0;\r\n            for (int i = 0; i < _items.Count; i++)\r\n            {\r\n                Item item = (Item) _items[i];\r\n                if (item.ItemID == iid)\r\n                    count += item.Amount;\r\n                // fucking osi blank scrolls\r\n                else if ((item.ItemID == 0x0E34 && iid == 0x0EF3) || (item.ItemID == 0x0EF3 && iid == 0x0E34))\r\n                    count += item.Amount;\r\n                count += item.GetCount(iid);\r\n            }\r\n\r\n            return count;\r\n        }\r\n        \r\n        public int GetTotalCount()\r\n        {\r\n            int count = 0;\r\n            \r\n            foreach (Item item in _items)\r\n            {\r\n                count++;\r\n\r\n                if (item.IsContainer)\r\n                {\r\n                    count += item.GetTotalCount();\r\n                }\r\n            }\r\n\r\n            return count;\r\n        }\r\n\r\n        public object Container\r\n        {\r\n            get\r\n            {\r\n                if (_parent is Serial && UpdateContainer())\r\n                    m_NeedContUpdate.Remove(this);\r\n                return _parent;\r\n            }\r\n            set\r\n            {\r\n                if ((_parent != null && _parent.Equals(value))\r\n                    || (value is Serial && _parent is UOEntity && ((UOEntity) _parent).Serial == (Serial) value)\r\n                    || (_parent is Serial && value is UOEntity && ((UOEntity) value).Serial == (Serial) _parent))\r\n                {\r\n                    return;\r\n                }\r\n\r\n                if (_parent is Mobile)\r\n                    ((Mobile) _parent).RemoveItem(this);\r\n                else if (_parent is Item)\r\n                    ((Item) _parent).RemoveItem(this);\r\n\r\n                if (World.Player != null && (IsChildOf(World.Player.Backpack) || IsChildOf(World.Player.Quiver)))\r\n                    Counter.Uncount(this);\r\n\r\n                if (value is Mobile)\r\n                    _parent = ((Mobile) value).Serial;\r\n                else if (value is Item)\r\n                    _parent = ((Item) value).Serial;\r\n                else\r\n                    _parent = value;\r\n\r\n                if (!UpdateContainer() && m_NeedContUpdate != null)\r\n                    m_NeedContUpdate.Add(this);\r\n            }\r\n        }\r\n\r\n        public bool UpdateContainer()\r\n        {\r\n            if (!(_parent is Serial) || Deleted)\r\n                return true;\r\n\r\n            object o = null;\r\n            Serial contSer = (Serial) _parent;\r\n            if (contSer.IsItem)\r\n                o = World.FindItem(contSer);\r\n            else if (contSer.IsMobile)\r\n                o = World.FindMobile(contSer);\r\n\r\n            if (o == null)\r\n                return false;\r\n\r\n            _parent = o;\r\n\r\n            if (_parent is Item)\r\n                ((Item) _parent).AddItem(this);\r\n            else if (_parent is Mobile)\r\n                ((Mobile) _parent).AddItem(this);\r\n\r\n            if (World.Player != null && (IsChildOf(World.Player.Backpack) || IsChildOf(World.Player.Quiver)))\r\n            {\r\n                bool exempt = SearchExemptionAgent.IsExempt(this);\r\n                if (!exempt)\r\n                    Counter.Count(this);\r\n\r\n                if (_isNew)\r\n                {\r\n                    if (_autoStack)\r\n                        AutoStackResource();\r\n\r\n                    if (IsContainer && !exempt && (!IsPouch || !Config.GetBool(\"NoSearchPouches\")) &&\r\n                        Config.GetBool(\"AutoSearch\"))\r\n                    {\r\n                        PacketHandlers.IgnoreGumps.Add(this);\r\n                        PlayerData.DoubleClick(this);\r\n\r\n                        for (int c = 0; c < Contains.Count; c++)\r\n                        {\r\n                            Item icheck = (Item) Contains[c];\r\n                            if (icheck.IsContainer && !SearchExemptionAgent.IsExempt(icheck) &&\r\n                                (!icheck.IsPouch || !Config.GetBool(\"NoSearchPouches\")))\r\n                            {\r\n                                PacketHandlers.IgnoreGumps.Add(icheck);\r\n                                PlayerData.DoubleClick(icheck);\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            _autoStack = _isNew = false;\r\n\r\n            return true;\r\n        }\r\n\r\n        private static List<Item> m_NeedContUpdate = new List<Item>();\r\n\r\n        public static void UpdateContainers()\r\n        {\r\n            int i = 0;\r\n            while (i < m_NeedContUpdate.Count)\r\n            {\r\n                if (((Item) m_NeedContUpdate[i]).UpdateContainer())\r\n                    m_NeedContUpdate.RemoveAt(i);\r\n                else\r\n                    i++;\r\n            }\r\n        }\r\n\r\n        private static List<Serial> m_AutoStackCache = new List<Serial>();\r\n\r\n        public void AutoStackResource()\r\n        {\r\n            if (!IsResource || !Config.GetBool(\"AutoStack\") || m_AutoStackCache.Contains(Serial))\r\n                return;\r\n\r\n            foreach (Item check in World.Items.Values)\r\n            {\r\n                if (check.Container == null && check.ItemID == ItemID && check.Hue == Hue &&\r\n                    Utility.InRange(World.Player.Position, check.Position, 2))\r\n                {\r\n                    DragDropManager.DragDrop(this, check);\r\n                    m_AutoStackCache.Add(Serial);\r\n                    return;\r\n                }\r\n            }\r\n\r\n            DragDropManager.DragDrop(this, World.Player.Position);\r\n            m_AutoStackCache.Add(Serial);\r\n        }\r\n\r\n        public object RootContainer\r\n        {\r\n            get\r\n            {\r\n                int die = 100;\r\n                object cont = this.Container;\r\n                while (cont != null && cont is Item && die-- > 0)\r\n                    cont = ((Item) cont).Container;\r\n\r\n                return cont;\r\n            }\r\n        }\r\n\r\n        public bool IsChildOf(object parent)\r\n        {\r\n            Serial parentSerial = 0;\r\n            if (parent is Mobile)\r\n                return parent == RootContainer;\r\n            else if (parent is Item)\r\n                parentSerial = ((Item) parent).Serial;\r\n            else\r\n                return false;\r\n\r\n            object check = this;\r\n            int die = 100;\r\n            while (check != null && check is Item && die-- > 0)\r\n            {\r\n                if (((Item) check).Serial == parentSerial)\r\n                    return true;\r\n                else\r\n                    check = ((Item) check).Container;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public Point3D GetWorldPosition()\r\n        {\r\n            int die = 100;\r\n            object root = this.Container;\r\n            while (root != null && root is Item && ((Item) root).Container != null && die-- > 0)\r\n                root = ((Item) root).Container;\r\n\r\n            if (root is Item)\r\n                return ((Item) root).Position;\r\n            else if (root is Mobile)\r\n                return ((Mobile) root).Position;\r\n            else\r\n                return this.Position;\r\n        }\r\n\r\n        private void AddItem(Item item)\r\n        {\r\n            for (int i = 0; i < _items.Count; i++)\r\n            {\r\n                if (_items[i] == item)\r\n                    return;\r\n            }\r\n\r\n            _items.Add(item);\r\n        }\r\n\r\n        private void RemoveItem(Item item)\r\n        {\r\n            _items.Remove(item);\r\n        }\r\n\r\n        public byte GetPacketFlags()\r\n        {\r\n            byte flags = 0;\r\n\r\n            if (!_visible)\r\n            {\r\n                flags |= 0x80;\r\n            }\r\n\r\n            if (_movable)\r\n            {\r\n                flags |= 0x20;\r\n            }\r\n\r\n            return flags;\r\n        }\r\n\r\n        public int DistanceTo(Mobile m)\r\n        {\r\n            int x = Math.Abs(this.Position.X - m.Position.X);\r\n            int y = Math.Abs(this.Position.Y - m.Position.Y);\r\n\r\n            return x > y ? x : y;\r\n        }\r\n\r\n        public void ProcessPacketFlags(byte flags)\r\n        {\r\n            _visible = ((flags & 0x80) == 0);\r\n            _movable = ((flags & 0x20) != 0);\r\n        }\r\n\r\n        private Timer m_RemoveTimer = null;\r\n\r\n        public void RemoveRequest()\r\n        {\r\n            if (m_RemoveTimer == null)\r\n                m_RemoveTimer = Timer.DelayedCallback(TimeSpan.FromSeconds(0.25), new TimerCallback(Remove));\r\n            else if (m_RemoveTimer.Running)\r\n                m_RemoveTimer.Stop();\r\n\r\n            m_RemoveTimer.Start();\r\n        }\r\n\r\n        public bool CancelRemove()\r\n        {\r\n            if (m_RemoveTimer != null && m_RemoveTimer.Running)\r\n            {\r\n                m_RemoveTimer.Stop();\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public override void Remove()\r\n        {\r\n            /*if ( IsMulti )\r\n                 UOAssist.PostRemoveMulti( this );*/\r\n\r\n            List<Item> rem = new List<Item>(_items);\r\n            _items.Clear();\r\n            for (int i = 0; i < rem.Count; i++)\r\n                (rem[i]).Remove();\r\n\r\n            Counter.Uncount(this);\r\n\r\n            if (_parent is Mobile)\r\n                ((Mobile) _parent).RemoveItem(this);\r\n            else if (_parent is Item)\r\n                ((Item) _parent).RemoveItem(this);\r\n\r\n            World.RemoveItem(this);\r\n            base.Remove();\r\n        }\r\n\r\n        public List<Item> Contains\r\n        {\r\n            get { return _items; }\r\n        }\r\n\r\n        // possibly 4 bit x/y - 16x16?\r\n        public byte GridNum\r\n        {\r\n            get { return _gridNum; }\r\n            set { _gridNum = value; }\r\n        }\r\n\r\n        public bool OnGround\r\n        {\r\n            get { return Container == null; }\r\n        }\r\n\r\n        public bool IsContainer\r\n        {\r\n            get\r\n            {\r\n                ushort iid = _itemId.Value;\r\n                return (_items.Count > 0 && !IsCorpse) || (iid >= 0x9A8 && iid <= 0x9AC) ||\r\n                       (iid >= 0x9B0 && iid <= 0x9B2) ||\r\n                       (iid >= 0xA2C && iid <= 0xA53) || (iid >= 0xA97 && iid <= 0xA9E) ||\r\n                       (iid >= 0xE3C && iid <= 0xE43) ||\r\n                       (iid >= 0xE75 && iid <= 0xE80 && iid != 0xE7B) || iid == 0x1E80 || iid == 0x1E81 ||\r\n                       iid == 0x232A || iid == 0x232B ||\r\n                       iid == 0x2B02 || iid == 0x2B03 || iid == 0x2FB7 || iid == 0x3171;\r\n            }\r\n        }\r\n\r\n        public bool IsBagOfSending\r\n        {\r\n            get { return Hue >= 0x0400 && _itemId.Value == 0xE76; }\r\n        }\r\n\r\n        public bool IsInBank\r\n        {\r\n            get\r\n            {\r\n                if (_parent is Item)\r\n                    return ((Item) _parent).IsInBank;\r\n                else if (_parent is Mobile)\r\n                    return this.Layer == Layer.Bank;\r\n                else\r\n                    return false;\r\n            }\r\n        }\r\n\r\n        public bool IsNew\r\n        {\r\n            get { return _isNew; }\r\n            set { _isNew = value; }\r\n        }\r\n\r\n        public bool AutoStack\r\n        {\r\n            get { return _autoStack; }\r\n            set { _autoStack = value; }\r\n        }\r\n\r\n        public bool IsMulti\r\n        {\r\n            get { return _itemId.Value >= 0x4000; }\r\n        }\r\n\r\n        public bool IsPouch\r\n        {\r\n            get { return _itemId.Value == 0x0E79; }\r\n        }\r\n\r\n        public bool IsCorpse\r\n        {\r\n            get { return _itemId.Value == 0x2006 || (_itemId.Value >= 0x0ECA && _itemId.Value <= 0x0ED2); }\r\n        }\r\n\r\n        public bool IsDoor\r\n        {\r\n            get\r\n            {\r\n                ushort iid = _itemId.Value;\r\n                return (iid >= 0x0675 && iid <= 0x06F6) || (iid >= 0x0821 && iid <= 0x0875) ||\r\n                       (iid >= 0x1FED && iid <= 0x1FFC) ||\r\n                       (iid >= 0x241F && iid <= 0x2424) || (iid >= 0x2A05 && iid <= 0x2A1C);\r\n            }\r\n        }\r\n\r\n        public bool IsResource\r\n        {\r\n            get\r\n            {\r\n                ushort iid = _itemId.Value;\r\n                return (iid >= 0x19B7 && iid <= 0x19BA) || // ore\r\n                       (iid >= 0x09CC && iid <= 0x09CF) || // fishes\r\n                       (iid >= 0x1BDD && iid <= 0x1BE2) || // logs\r\n                       iid == 0x1779 || // granite / stone\r\n                       iid == 0x11EA || iid == 0x11EB // sand\r\n                    ;\r\n            }\r\n        }\r\n\r\n        public bool IsPotion\r\n        {\r\n            get\r\n            {\r\n                return (_itemId.Value >= 0x0F06 && _itemId.Value <= 0x0F0D) ||\r\n                       _itemId.Value == 0x2790 || _itemId.Value == 0x27DB; // Ninja belt (works like a potion)\r\n            }\r\n        }\r\n\r\n        public bool IsVirtueShield\r\n        {\r\n            get\r\n            {\r\n                ushort iid = _itemId.Value;\r\n                return (iid >= 0x1bc3 && iid <= 0x1bc5); // virtue shields\r\n            }\r\n        }\r\n\r\n        public bool IsTwoHanded\r\n        {\r\n            get\r\n            {\r\n                ushort iid = _itemId.Value;\r\n\r\n                if (Overrides.TwoHanded.TryGetValue(iid, out bool value))\r\n                {\r\n                    return value;\r\n                }\r\n\r\n                return (\r\n                           // everything in layer 2 except shields is 2handed\r\n                           Layer == Layer.LeftHand &&\r\n                           !((iid >= 0x1b72 && iid <= 0x1b7b) || IsVirtueShield) // shields\r\n                       ) ||\r\n\r\n                       // and all of these layer 1 weapons:\r\n                       (iid == 0x13fc || iid == 0x13fd) || // hxbow\r\n                       (iid == 0x13AF || iid == 0x13b2) || // war axe & bow\r\n                       (iid >= 0x0F43 && iid <= 0x0F50) || // axes & xbow\r\n                       (iid == 0x1438 || iid == 0x1439) || // war hammer\r\n                       (iid == 0x1442 || iid == 0x1443) || // 2handed axe\r\n                       (iid == 0x1402 || iid == 0x1403) || // short spear\r\n                       (iid == 0x26c1 || iid == 0x26cb) || // aos blade\r\n                       (iid == 0x26c2 || iid == 0x26cc) || // aos bow\r\n                       (iid == 0x26c3 || iid == 0x26cd) // aos xbow\r\n                    ;\r\n            }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"{this.Name} ({this.Serial})\";\r\n        }\r\n\r\n        public int Price\r\n        {\r\n            get { return _price; }\r\n            set { _price = value; }\r\n        }\r\n\r\n        public string BuyDesc\r\n        {\r\n            get { return _buyDesc; }\r\n            set { _buyDesc = value; }\r\n        }\r\n\r\n        public int HouseRevision\r\n        {\r\n            get { return _houseRev; }\r\n            set { _houseRev = value; }\r\n        }\r\n\r\n        public byte[] HousePacket\r\n        {\r\n            get { return _housePacket; }\r\n            set { _housePacket = value; }\r\n        }\r\n\r\n        public void MakeHousePacket()\r\n        {\r\n            _housePacket = null;\r\n\r\n            try\r\n            {\r\n                // 3 locations... which is right? all of them? wtf?\r\n                //\"Desktop/{0}/{1}/{2}/Multicache.dat\", World.AccountName, World.ShardName, World.OrigPlayerName\r\n                //\"Desktop/{0}/{1}/{2}/Multicache.dat\", World.AccountName, World.ShardName, World.Player.Name );\r\n                //\"Desktop/{0}/Multicache.dat\", World.AccountName );\r\n                string path = Ultima.Files.GetFilePath(\r\n                    $\"Desktop/{World.AccountName}/{World.ShardName}/{World.OrigPlayerName}/Multicache.dat\");\r\n                if (string.IsNullOrEmpty(path) || !File.Exists(path))\r\n                    return;\r\n\r\n                using (StreamReader reader =\r\n                    new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))\r\n                {\r\n                    string line;\r\n                    reader.ReadLine(); // ver\r\n                    int skip = 0;\r\n                    int count = 0;\r\n                    while ((line = reader.ReadLine()) != null)\r\n                    {\r\n                        if (count++ < skip || line == \"\" || line[0] == ';')\r\n                            continue;\r\n\r\n                        string[] split = line.Split(' ', '\\t');\r\n                        if (split.Length <= 0)\r\n                            return;\r\n\r\n                        skip = 0;\r\n                        Serial ser = (uint) Utility.ToInt32(split[0], 0);\r\n                        int rev = Utility.ToInt32(split[1], 0);\r\n                        int lines = Utility.ToInt32(split[2], 0);\r\n\r\n                        if (ser == this.Serial)\r\n                        {\r\n                            _houseRev = rev;\r\n                            MultiTileEntry[] tiles = new MultiTileEntry[lines];\r\n                            count = 0;\r\n\r\n                            Ultima.MultiComponentList mcl = Ultima.Multis.GetComponents(_itemId);\r\n\r\n                            while ((line = reader.ReadLine()) != null && count < lines)\r\n                            {\r\n                                split = line.Split(' ', '\\t');\r\n\r\n                                tiles[count] = new MultiTileEntry();\r\n                                tiles[count].m_ItemID = (ushort) Utility.ToInt32(split[0], 0);\r\n                                tiles[count].m_OffsetX = (short) (Utility.ToInt32(split[1], 0) + mcl.Center.X);\r\n                                tiles[count].m_OffsetX = (short) (Utility.ToInt32(split[2], 0) + mcl.Center.Y);\r\n                                tiles[count].m_OffsetX = (short) Utility.ToInt32(split[3], 0);\r\n\r\n                                count++;\r\n                            }\r\n\r\n                            _housePacket = new DesignStateDetailed(Serial, _houseRev, mcl.Min.X, mcl.Min.Y, mcl.Max.X,\r\n                                mcl.Max.Y, tiles).Compile();\r\n                            break;\r\n                        }\r\n                        else\r\n                        {\r\n                            skip = lines;\r\n                        }\r\n\r\n                        count = 0;\r\n                    }\r\n                }\r\n            }\r\n            catch // ( Exception e )\r\n            {\r\n                //Engine.LogCrash( e );\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/ItemID.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\n\r\nnamespace Assistant\r\n{\r\n    public struct ItemID\r\n    {\r\n        private ushort m_ID;\r\n\r\n        public ItemID(ushort id)\r\n        {\r\n            m_ID = id;\r\n        }\r\n\r\n        public ushort Value\r\n        {\r\n            get { return m_ID; }\r\n        }\r\n\r\n        public static implicit operator ushort(ItemID a)\r\n        {\r\n            return a.m_ID;\r\n        }\r\n\r\n        public static implicit operator ItemID(ushort a)\r\n        {\r\n            return new ItemID(a);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            try\r\n            {\r\n                return $\"{Ultima.TileData.ItemTable[m_ID].Name} ({m_ID:X4})\";\r\n            }\r\n            catch\r\n            {\r\n                return $\" ({m_ID:X4})\";\r\n            }\r\n        }\r\n\r\n        public Ultima.ItemData ItemData\r\n        {\r\n            get\r\n            {\r\n                try\r\n                {\r\n                    return Ultima.TileData.ItemTable[m_ID];\r\n                }\r\n                catch\r\n                {\r\n                    return new Ultima.ItemData(\"\", Ultima.TileFlag.None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\r\n                }\r\n            }\r\n        }\r\n\r\n        public override int GetHashCode()\r\n        {\r\n            return m_ID;\r\n        }\r\n\r\n        public override bool Equals(object o)\r\n        {\r\n            if (o == null || !(o is ItemID)) return false;\r\n\r\n            return ((ItemID) o).m_ID == m_ID;\r\n        }\r\n\r\n        public static bool operator ==(ItemID l, ItemID r)\r\n        {\r\n            return l.m_ID == r.m_ID;\r\n        }\r\n\r\n        public static bool operator !=(ItemID l, ItemID r)\r\n        {\r\n            return l.m_ID != r.m_ID;\r\n        }\r\n\r\n        public static bool operator >(ItemID l, ItemID r)\r\n        {\r\n            return l.m_ID > r.m_ID;\r\n        }\r\n\r\n        public static bool operator >=(ItemID l, ItemID r)\r\n        {\r\n            return l.m_ID >= r.m_ID;\r\n        }\r\n\r\n        public static bool operator <(ItemID l, ItemID r)\r\n        {\r\n            return l.m_ID < r.m_ID;\r\n        }\r\n\r\n        public static bool operator <=(ItemID l, ItemID r)\r\n        {\r\n            return l.m_ID <= r.m_ID;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/Main.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Reflection;\r\nusing System.Threading;\r\nusing System.Windows.Forms;\r\nusing System.Diagnostics;\r\nusing System.Globalization;\r\nusing System.IO;\r\nusing System.Net;\r\nusing System.Security.Principal;\r\nusing Assistant.Core;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant\r\n{\r\n    public partial class Engine\r\n    {\r\n        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)\r\n        {\r\n            if (e.IsTerminating)\r\n            {\r\n                Client.Instance.Close();\r\n                m_Running = false;\r\n\r\n                new MessageDialog(\"Unhandled Exception\", !e.IsTerminating, e.ExceptionObject.ToString()).ShowDialog(\r\n                    Engine.ActiveWindow);\r\n            }\r\n\r\n            LogCrash(e.ExceptionObject as Exception);\r\n        }\r\n\r\n        public static void LogCrash(object exception)\r\n        {\r\n            if (exception == null || (exception is ThreadAbortException))\r\n                return;\r\n\r\n            using (StreamWriter txt = new StreamWriter(\"Crash.log\", true))\r\n            {\r\n                txt.AutoFlush = true;\r\n                txt.WriteLine(\"Exception @ {0}\", Engine.MistedDateTime.ToString(\"MM-dd-yy HH:mm:ss.ffff\"));\r\n                txt.WriteLine(exception.ToString());\r\n                txt.WriteLine(\"\");\r\n                txt.WriteLine(\"\");\r\n            }\r\n        }\r\n\r\n        private static Version m_ClientVersion = null;\r\n\r\n        public static Version ClientVersion\r\n        {\r\n            get\r\n            {\r\n                if (m_ClientVersion == null || m_ClientVersion.Major < 2)\r\n                {\r\n                    string[] split = Client.Instance.GetClientVersion().Split('.');\r\n\r\n                    if (split.Length < 3)\r\n                        return new Version(4, 0, 0, 0);\r\n\r\n                    int rev = 0;\r\n\r\n                    if (split.Length > 3)\r\n                        rev = Utility.ToInt32(split[3], 0);\r\n\r\n                    m_ClientVersion = new Version(\r\n                        Utility.ToInt32(split[0], 0),\r\n                        Utility.ToInt32(split[1], 0),\r\n                        Utility.ToInt32(split[2], 0),\r\n                        rev);\r\n\r\n                    if (m_ClientVersion.Major == 0) // sanity check if the client returns 0.0.0.0\r\n                        m_ClientVersion = new Version(4, 0, 0, 0);\r\n                }\r\n\r\n                return m_ClientVersion;\r\n            }\r\n        }\r\n\r\n        public static bool UseNewMobileIncoming\r\n        {\r\n            get\r\n            {\r\n                if (ClientVersion.Major > 7)\r\n                {\r\n                    return true;\r\n                }\r\n                else if (ClientVersion.Major == 7)\r\n                {\r\n                    if (ClientVersion.Minor > 0 || ClientVersion.Build >= 33)\r\n                    {\r\n                        return true;\r\n                    }\r\n                }\r\n\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static bool UsePostHSChanges\r\n        {\r\n            get\r\n            {\r\n                if (ClientVersion.Major > 7)\r\n                {\r\n                    return true;\r\n                }\r\n                else if (ClientVersion.Major == 7)\r\n                {\r\n                    if (ClientVersion.Minor > 0)\r\n                    {\r\n                        return true;\r\n                    }\r\n                    else if (ClientVersion.Build >= 9)\r\n                    {\r\n                        return true;\r\n                    }\r\n                }\r\n\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static bool UsePostSAChanges\r\n        {\r\n            get\r\n            {\r\n                if (ClientVersion.Major >= 7)\r\n                {\r\n                    return true;\r\n                }\r\n\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static bool UsePostKRPackets\r\n        {\r\n            get\r\n            {\r\n                if (ClientVersion.Major >= 7)\r\n                {\r\n                    return true;\r\n                }\r\n                else if (ClientVersion.Major >= 6)\r\n                {\r\n                    if (ClientVersion.Minor == 0)\r\n                    {\r\n                        if (ClientVersion.Build == 1)\r\n                        {\r\n                            if (ClientVersion.Revision >= 7)\r\n                                return true;\r\n                        }\r\n                        else if (ClientVersion.Build > 1)\r\n                        {\r\n                            return true;\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        return true;\r\n                    }\r\n                }\r\n\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static string ExePath\r\n        {\r\n            get { return Process.GetCurrentProcess().MainModule.FileName; }\r\n        }\r\n\r\n        public static MainForm MainWindow\r\n        {\r\n            get { return m_MainWnd; }\r\n        }\r\n\r\n        public static bool Running\r\n        {\r\n            get { return m_Running; }\r\n        }\r\n\r\n        public static Form ActiveWindow\r\n        {\r\n            get { return m_ActiveWnd; }\r\n            set { m_ActiveWnd = value; }\r\n        }\r\n\r\n        public static string Version\r\n        {\r\n            get\r\n            {\r\n                if (m_Version == null)\r\n                {\r\n                    Version v = Assembly.GetCallingAssembly().GetName().Version;\r\n                    m_Version = $\"{v.Major}.{v.Minor}.{v.Build}.{v.Revision}\"; //, v.Revision\r\n                }\r\n\r\n                return m_Version;\r\n            }\r\n        }\r\n\r\n        private static MainForm m_MainWnd;\r\n        \r\n        private static Form m_ActiveWnd;\r\n\r\n        //private static Thread m_TimerThread;\r\n        private static bool m_Running;\r\n        private static string m_Version;\r\n\r\n        private static int _previousHour = -1;\r\n        private static int _Differential;\r\n\r\n        public static int Differential //to use in all cases where you rectify normal clocks obtained with utctimer!\r\n        {\r\n            get\r\n            {\r\n                if (_previousHour != DateTime.UtcNow.Hour)\r\n                {\r\n                    _previousHour = DateTime.UtcNow.Hour;\r\n                    _Differential = DateTimeOffset.Now.Offset.Hours;\r\n                }\r\n\r\n                return _Differential;\r\n            }\r\n        }\r\n\r\n        public static DateTime MistedDateTime\r\n        {\r\n            get { return DateTime.UtcNow.AddHours(Differential); }\r\n        }\r\n\r\n        public static CultureInfo Culture;\r\n\r\n        public static void Load()\r\n        {\r\n            Culture = new CultureInfo(\"en-US\", false);\r\n            Culture.NumberFormat.NumberDecimalSeparator = \".\";\r\n            Culture.NumberFormat.NumberGroupSeparator = \",\";\r\n\r\n            /* Load localization files */\r\n            string defLang = Config.GetAppSetting<string>(\"DefaultLanguage\");\r\n            if (defLang == null)\r\n            {\r\n                defLang = \"ENU\";\r\n            }\r\n\r\n            if (Client.IsOSI)\r\n            {\r\n                Ultima.Files.ReLoadDirectory();\r\n                Ultima.Files.LoadMulPath();\r\n            }\r\n\r\n            if (!Language.Load(defLang))\r\n            {\r\n                MessageBox.Show(\r\n                    $\"WARNING: Razor was unable to load the file Language/Razor_lang.{defLang}\\n.\", \"Language Load Error\", MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            m_Running = true;\r\n\r\n            /* Load settings from configuration file */\r\n            Ultima.Files.SetMulPath(Config.GetAppSetting<string>(\"UODataDir\"));\r\n            Client.Instance.ClientEncrypted = Config.GetAppSetting<int>(\"ClientEncrypted\") == 1;\r\n            Client.Instance.ServerEncrypted = Config.GetAppSetting<int>(\"ServerEncrypted\") == 1;\r\n\r\n            Language.LoadCliLoc();\r\n\r\n            /* Initialize engine */\r\n            SplashScreen.Message = LocString.Initializing;\r\n            Initialize(typeof(Engine).Assembly);\r\n\r\n            /* Load Profile */\r\n            SplashScreen.Message = LocString.LoadingLastProfile;\r\n            Config.LoadCharList();\r\n            Overrides.Load();\r\n            if (!Config.LoadLastProfile())\r\n                MessageBox.Show(\r\n                    \"The selected profile could not be loaded, using default instead.\", \"Profile Load Error\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n\r\n            /* Start client */\r\n            SplashScreen.Message = LocString.LoadingClient;\r\n            string clientPath = Ultima.Files.GetFilePath(\"client.exe\");\r\n            if (clientPath == null || !File.Exists(clientPath))\r\n            {\r\n                MessageBox.Show(SplashScreen.Instance,\r\n                    $\"Unable to find the client specified.\\n\\\"{(clientPath != null ? clientPath : \"-null-\")}\\\"\", \"Could Not Find Client\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Stop);\r\n                SplashScreen.End();\r\n                return;\r\n            }\r\n\r\n            var result = Client.Instance.LaunchClient(clientPath);\r\n            if (result != Client.Loader_Error.SUCCESS)\r\n            {\r\n                MessageBox.Show(SplashScreen.Instance,\r\n                    String.Format(\"Unable to launch the client specified. (Error: {1})\\n \\\"{0}\\\"\",\r\n                        clientPath != null ? clientPath : \"-null-\", result),\r\n                    \"Could Not Start Client\", MessageBoxButtons.OK, MessageBoxIcon.Stop);\r\n                SplashScreen.End();\r\n                return;\r\n            }\r\n\r\n            string addr = Config.GetAppSetting<string>(\"LastServer\");\r\n            int port = Config.GetAppSetting<int>(\"LastPort\");\r\n\r\n            IPAddress ip = Resolve(addr);\r\n            if (ip == IPAddress.None || port == 0)\r\n            {\r\n                MessageBox.Show(SplashScreen.Instance, Language.GetString(LocString.BadServerAddr),\r\n                    \"Bad Server Address\", MessageBoxButtons.OK, MessageBoxIcon.Stop);\r\n                SplashScreen.End();\r\n                return;\r\n            }\r\n\r\n            Client.Instance.SetConnectionInfo(ip, port);\r\n\r\n            SplashScreen.Message = LocString.WaitingForClient;\r\n        }\r\n\r\n        public static void Close()\r\n        {\r\n            m_Running = false;\r\n\r\n            Client.Instance.Close();\r\n            Counter.Save();\r\n            Macros.MacroManager.Save();\r\n            Config.Save();\r\n        }\r\n\r\n        public static void RunUI()\r\n        {\r\n            Thread.CurrentThread.Name = \"Razor UI Thread\";\r\n\r\n            m_MainWnd = new MainForm();\r\n            m_MainWnd.Show();\r\n            Application.Run(m_MainWnd);\r\n        }\r\n\r\n        [STAThread]\r\n        public static void Main(string[] Args)\r\n        {\r\n            Application.EnableVisualStyles();\r\n            Application.SetCompatibleTextRenderingDefault(false);\r\n\r\n#if !DEBUG\r\n\t\t\tAppDomain.CurrentDomain.UnhandledException +=\r\n new UnhandledExceptionEventHandler( CurrentDomain_UnhandledException );\r\n\t\t\tDirectory.SetCurrentDirectory( Config.GetInstallDirectory() );\r\n#endif\r\n\r\n            /* Load localization files */\r\n            string defLang = Config.GetAppSetting<string>(\"DefaultLanguage\");\r\n            if (defLang == null)\r\n            {\r\n                defLang = \"ENU\";\r\n            }\r\n\r\n            Client.Init(true);\r\n\r\n            if (Client.IsOSI)\r\n            {\r\n                Ultima.Files.ReLoadDirectory();\r\n                Ultima.Files.LoadMulPath();\r\n            }\r\n\r\n            if (!Language.Load(defLang))\r\n            {\r\n                MessageBox.Show(\r\n                    $\"WARNING: Razor was unable to load the file Language/Razor_lang.{defLang}\\n.\", \"Language Load Error\", MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            /* Show welcome screen */\r\n            if (Config.GetAppSetting<int>(\"ShowWelcome\") != 0)\r\n            {\r\n                SplashScreen.End();\r\n\r\n                WelcomeForm welcome = new WelcomeForm();\r\n                m_ActiveWnd = welcome;\r\n                if (welcome.ShowDialog() == DialogResult.Cancel)\r\n                    return;\r\n\r\n                SplashScreen.Start();\r\n                m_ActiveWnd = SplashScreen.Instance;\r\n            }\r\n\r\n            Load();\r\n            RunUI();\r\n            Close();\r\n        }\r\n\r\n        private static string _rootPath = null;\r\n\r\n        public static string RootPath =>\r\n            _rootPath ?? (_rootPath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(Engine)).Location));\r\n\r\n        /*public static string GetDirectory( string relPath )\r\n        {\r\n            string path = Path.Combine(ExeDirectory, relPath);\r\n            EnsureDirectory( path );\r\n            return path;\r\n        }*/\r\n\r\n        public static void EnsureDirectory(string dir)\r\n        {\r\n            if (!Directory.Exists(dir))\r\n                Directory.CreateDirectory(dir);\r\n        }\r\n\r\n        private static void Initialize(Assembly a)\r\n        {\r\n            Type[] types = a.GetTypes();\r\n\r\n            for (int i = 0; i < types.Length; i++)\r\n            {\r\n                if (types[i].Namespace == \"Ultima\")\r\n                    continue;\r\n                MethodInfo init = types[i].GetMethod(\"Initialize\", BindingFlags.Static | BindingFlags.Public);\r\n\r\n                if (init != null)\r\n                    init.Invoke(null, null);\r\n            }\r\n        }\r\n\r\n        private static IPAddress Resolve(string addr)\r\n        {\r\n            IPAddress ipAddr = IPAddress.None;\r\n\r\n            if (string.IsNullOrEmpty(addr))\r\n                return ipAddr;\r\n\r\n            try\r\n            {\r\n                ipAddr = IPAddress.Parse(addr);\r\n            }\r\n            catch\r\n            {\r\n                try\r\n                {\r\n                    IPHostEntry iphe = Dns.GetHostEntry(addr);\r\n\r\n                    if (iphe.AddressList.Length > 0)\r\n                        ipAddr = iphe.AddressList[iphe.AddressList.Length - 1];\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n\r\n            return ipAddr;\r\n        }\r\n\r\n        public static bool IsElevated\r\n        {\r\n            get\r\n            {\r\n                return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/Map.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing Ultima;\r\n\r\nnamespace Assistant\r\n{\r\n    public class MultiTileEntry\r\n    {\r\n        public ushort m_ItemID;\r\n        public short m_OffsetX;\r\n        public short m_OffsetY;\r\n        public short m_OffsetZ;\r\n    }\r\n\r\n    public class Map\r\n    {\r\n        public static Ultima.Map GetMap(int mapNum)\r\n        {\r\n            switch (mapNum)\r\n            {\r\n                case 1: return Ultima.Map.Trammel;\r\n                case 2: return Ultima.Map.Ilshenar;\r\n                case 3: return Ultima.Map.Malas;\r\n                case 4: return Ultima.Map.Tokuno;\r\n                case 5: return Ultima.Map.TerMur;\r\n                case 0:\r\n                default: return Ultima.Map.Felucca;\r\n            }\r\n        }\r\n\r\n        public static int Parse(string name)\r\n        {\r\n            if (string.IsNullOrEmpty(name))\r\n                return 0;\r\n\r\n            name = name.ToLower();\r\n\r\n            if (name == \"felucca\")\r\n                return 0;\r\n            else if (name == \"trammel\")\r\n                return 1;\r\n            else if (name == \"ilshenar\")\r\n                return 2;\r\n            else if (name == \"malas\")\r\n                return 3;\r\n            else if (name == \"samurai\" || name == \"tokuno\")\r\n                return 4;\r\n            else\r\n                return 0;\r\n        }\r\n\r\n        public static HuedTile GetTileNear(int mapNum, int x, int y, int z)\r\n        {\r\n            try\r\n            {\r\n                Ultima.Map map = GetMap(mapNum);\r\n\r\n                HuedTile[] tiles = map.Tiles.GetStaticTiles(x, y);\r\n                if (tiles != null && tiles.Length > 0)\r\n                {\r\n                    for (int i = 0; i < tiles.Length; i++)\r\n                    {\r\n                        if (tiles[i].Z >= z - 5 && tiles[i].Z <= z + 5)\r\n                            return tiles[i];\r\n                    }\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            return new HuedTile(0, 0, (sbyte) z);\r\n        }\r\n\r\n        private static void GetAverageZ(Ultima.Map map, int x, int y, ref int z, ref int avg, ref int top)\r\n        {\r\n            try\r\n            {\r\n                int zTop = map.Tiles.GetLandTile(x, y).Z;\r\n                int zLeft = map.Tiles.GetLandTile(x, y + 1).Z;\r\n                int zRight = map.Tiles.GetLandTile(x + 1, y).Z;\r\n                int zBottom = map.Tiles.GetLandTile(x + 1, y + 1).Z;\r\n\r\n                z = zTop;\r\n                if (zLeft < z)\r\n                    z = zLeft;\r\n                if (zRight < z)\r\n                    z = zRight;\r\n                if (zBottom < z)\r\n                    z = zBottom;\r\n\r\n                top = zTop;\r\n                if (zLeft > top)\r\n                    top = zLeft;\r\n                if (zRight > top)\r\n                    top = zRight;\r\n                if (zBottom > top)\r\n                    top = zBottom;\r\n\r\n                if (Math.Abs(zTop - zBottom) > Math.Abs(zLeft - zRight))\r\n                    avg = (int) Math.Floor((zLeft + zRight) / 2.0);\r\n                else\r\n                    avg = (int) Math.Floor((zTop + zBottom) / 2.0);\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public static sbyte ZTop(int mapNum, int xCheck, int yCheck, int oldZ)\r\n        {\r\n            try\r\n            {\r\n                Ultima.Map map = GetMap(mapNum);\r\n\r\n                Tile landTile = map.Tiles.GetLandTile(xCheck, yCheck);\r\n                int landZ = 0, landCenter = 0, zTop = 0;\r\n\r\n                GetAverageZ(map, xCheck, yCheck, ref landZ, ref landCenter, ref zTop);\r\n\r\n                if (zTop > oldZ)\r\n                    oldZ = zTop;\r\n\r\n                bool isSet = false;\r\n                HuedTile[] staticTiles = map.Tiles.GetStaticTiles(xCheck, yCheck);\r\n                for (int i = 0; i < staticTiles.Length; ++i)\r\n                {\r\n                    HuedTile tile = staticTiles[i];\r\n                    ItemData id = TileData.ItemTable[tile.ID & 0x3FFF];\r\n\r\n                    int calcTop = (tile.Z + id.CalcHeight);\r\n\r\n                    if (calcTop <= oldZ + 5 && (!isSet || calcTop > zTop) &&\r\n                        ((id.Flags & TileFlag.Surface) != 0 || (id.Flags & TileFlag.Wet) != 0))\r\n                    {\r\n                        zTop = calcTop;\r\n                        isSet = true;\r\n                    }\r\n                }\r\n\r\n                return (sbyte) zTop;\r\n            }\r\n            catch\r\n            {\r\n                return (sbyte) oldZ;\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/MemHelper.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\n\r\nnamespace Assistant\r\n{\r\n    public class MemoryHelperThinggie : Timer\r\n    {\r\n        private static TimeSpan Frequency = TimeSpan.FromMinutes(2.5);\r\n\r\n        public static readonly MemoryHelperThinggie Instance = new MemoryHelperThinggie();\r\n\r\n        public static void Initialize()\r\n        {\r\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\r\n                Instance.Start();\r\n        }\r\n\r\n        private MemoryHelperThinggie() : base(TimeSpan.Zero, Frequency)\r\n        {\r\n        }\r\n\r\n        [System.Runtime.InteropServices.DllImport(\"Kernel32\")]\r\n        private static extern uint SetProcessWorkingSetSize(IntPtr hProc, int minSize, int maxSize);\r\n\r\n        protected override void OnTick()\r\n        {\r\n            SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/MessageInBottleCapture.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Linq;\n\nnamespace Assistant.Core\n{\n    public class MessageInBottleCapture\n    {\n        private static readonly string[] _mibGumpLayout =\n        {\n            \"{ page 0 }{ resizepic 0 40 2520 350 300 }{ xmfhtmlgump 30 80 285 160 1018326 1 1 }{ htmlgump 35 240 230 20 0 0 0 }{ button 35 265 4005 4007 1 0 0 }{ xmfhtmlgump 70 265 100 20 1011036 0 0 }\",\n            \"{ page 0 }{ htmlgump 200 140 230 20 0 0 0 }{ resizepic 0 40 2520 350 300 }{ xmfhtmlgump 30 80 285 160 1018326 1 1 }{ htmlgump 35 240 230 20 1 0 0 }{ button 35 265 4005 4007 1 0 0 }{ xmfhtmlgump 70 265 100 20 1011036 0 0 }\"\n        };\n\n        public static bool IsMibGump(string layout)\n        {\n            return _mibGumpLayout.Any(\n                gumpLayout => layout.IndexOf(gumpLayout, StringComparison.OrdinalIgnoreCase) != -1);\n        }\n\n        public static void CaptureMibCoordinates(string coords, bool hasXY)\n        {\n            string mibLog = Path.Combine(Config.GetInstallDirectory(), \"MIBCapture.csv\");\n\n            if (!File.Exists(mibLog))\n            {\n                File.Create(mibLog);\n            }\n\n            // 130°15'N,63°16'W\n\n            int xAxis = 0;\n            int yAxis = 0;\n\n            if (hasXY)\n            {\n                // 0   1 2\n                // MIB|x|y\n                string[] mibCoords = coords.Split('|');\n                xAxis = Convert.ToInt32(mibCoords[1]);\n                yAxis = Convert.ToInt32(mibCoords[2]);\n            }\n            else\n            {\n                ConvertCoords(coords, ref xAxis, ref yAxis);\n            }\n\n            using (StreamWriter sw = File.AppendText(mibLog))\n            {\n                sw.WriteLine($\"{xAxis},{yAxis},{World.Player.Map},mib,mib,red,3\");\n            }\n\n            World.Player.SendMessage(MsgLevel.Force, $\"MIB Captured: {xAxis},{yAxis}\");\n        }\n\n\n        private static void ConvertCoords(string coords, ref int xAxis, ref int yAxis)\n        {\n            string[] coordsSplit = coords.Split(',');\n\n            string yCoord = coordsSplit[0];\n            string xCoord = coordsSplit[1];\n\n            // Calc Y first\n            string[] ySplit = yCoord.Split('°');\n            double yDegree = Convert.ToDouble(ySplit[0]);\n            double yMinute = Convert.ToDouble(ySplit[1].Substring(0, ySplit[1].IndexOf(\"'\", StringComparison.Ordinal)));\n\n            if (yCoord.Substring(yCoord.Length - 1).Equals(\"N\"))\n            {\n                yAxis = (int) (1624 - (yMinute / 60) * (4096.0 / 360) - yDegree * (4096.0 / 360));\n            }\n            else\n            {\n                yAxis = (int) (1624 + (yMinute / 60) * (4096.0 / 360) + yDegree * (4096.0 / 360));\n            }\n\n            // Calc X next\n            string[] xSplit = xCoord.Split('°');\n            double xDegree = Convert.ToDouble(xSplit[0]);\n            double xMinute = Convert.ToDouble(xSplit[1].Substring(0, xSplit[1].IndexOf(\"'\", StringComparison.Ordinal)));\n\n            if (xCoord.Substring(xCoord.Length - 1).Equals(\"W\"))\n            {\n                xAxis = (int) (1323 - (xMinute / 60) * (5120.0 / 360) - xDegree * (5120.0 / 360));\n            }\n            else\n            {\n                xAxis = (int) (1323 + (xMinute / 60) * (5120.0 / 360) + xDegree * (5120.0 / 360));\n            }\n\n            // Normalize values outside of map range.\n            if (xAxis < 0)\n                xAxis += 5120;\n            else if (xAxis > 5120)\n                xAxis -= 5120;\n\n            if (yAxis < 0)\n                yAxis += 4096;\n            else if (yAxis > 4096)\n                yAxis -= 4096;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/MessageManager.cs",
    "content": "#region license\n\n// Razor: An Ultima Online Assistant\n// Copyright (C) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#endregion\n\nusing System;\nusing System.IO;\nusing Assistant.Agents;\n\nnamespace Assistant.Core\n{\n    public static class MessageManager\n    {\n        public static Action<Packet, PacketHandlerEventArgs, Serial, ushort, MessageType, ushort, ushort, string, string, string> OnSpellMessage { get; set; }\n        public static Action<Packet, PacketHandlerEventArgs, Serial, ushort, MessageType, ushort, ushort, string, string, string> OnLabelMessage { get; set; }\n        public static Action<Packet, PacketHandlerEventArgs, Serial, ushort, MessageType, ushort, ushort, string, string, string> OnSystemMessage { get; set; }\n        public static Action<Packet, PacketHandlerEventArgs, Serial, ushort, MessageType, ushort, ushort, string, string, string> OnMobileMessage { get; set; }\n\n        public static bool GetLabelCommand { get; set; } = false;\n\n        public static void Initialize()\n        {\n            OnMobileMessage += HandleMobileMessage;\n        }\n\n        public static void HandleMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\n                                         MessageType type, ushort hue, ushort font, string lang, string sourceName,\n                                         string text)\n        {\n            if (World.Player == null)\n            {\n                return;\n            }\n\n            switch (type)\n            {\n                case MessageType.Spell:\n                    OnSpellMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text);\n                    break;\n\n                case MessageType.Label:\n                    if (source.IsMobile)\n                    {\n                        Mobile m = World.FindMobile(source);\n                        if (m != null)\n                        {\n                            m.Name = sourceName;\n                        }\n                    }\n\n                    OnLabelMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text);\n                    break;\n\n                case MessageType.Emote:\n\n                    if (Config.GetBool(\"PlayEmoteSound\") && source.IsMobile)\n                    {\n                        Mobile m = World.FindMobile(source);\n\n                        if (m != null)\n                        {\n                            text = text.Trim('*');\n\n                            if (m.Female)\n                            {\n                                if (Enum.TryParse(text, true, out FemaleSounds sound))\n                                {\n                                    if (sound != 0)\n                                    {\n                                        Client.Instance.SendToClient(new PlaySound((int)sound));\n                                    }\n                                }\n                            }\n                            else\n                            {\n                                if (Enum.TryParse(text, true, out MaleSounds sound))\n                                {\n                                    if (sound != 0)\n                                    {\n                                        Client.Instance.SendToClient(new PlaySound((int) sound));\n                                    }\n                                }\n                            }\n                        }\n                    }\n\n                    break;\n            }\n\n            OnSystemMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text);\n\n            if (GetLabelCommand)\n            {\n                OnLabelMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text);\n            }\n            else\n            {\n                OnMobileMessage?.Invoke(p, args, source, graphic, type, hue, font, lang, sourceName, text);\n            }\n        }\n\n        public static void HandleMobileMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\n                                 MessageType type, ushort hue, ushort font, string lang, string sourceName,\n                                 string text)\n        {\n            if ((type == MessageType.Emote || type == MessageType.Regular || type == MessageType.Whisper ||\n                 type == MessageType.Yell) && source.IsMobile && source != World.Player.Serial)\n            {\n                if (Config.GetBool(\"ForceSpeechHue\"))\n                {\n                    p.Seek(10, SeekOrigin.Begin);\n                    p.Write((ushort)Config.GetInt(\"SpeechHue\"));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/Mobile.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Text;\nusing Assistant.Agents;\nusing Assistant.UI;\n\nnamespace Assistant\n{\n    [Flags]\n    public enum Direction : byte\n    {\n        North = 0x0,\n        Right = 0x1,\n        East = 0x2,\n        Down = 0x3,\n        South = 0x4,\n        Left = 0x5,\n        West = 0x6,\n        Up = 0x7,\n        Mask = 0x7,\n        Running = 0x80,\n        ValueMask = 0x87\n    }\n\n    //public enum BodyType : byte\n    //{\n    //    Empty,\n    //    Monster,\n    //    Sea_Monster,\n    //    Animal,\n    //    Human,\n    //    Equipment\n    //}\n\n    public class Mobile : UOEntity\n    {\n        private ushort m_Body;\n        private Direction m_Direction;\n        private string m_Name;\n\n        private byte m_Notoriety;\n\n        private bool m_Visible;\n        private bool m_Female;\n        private bool m_Poisoned;\n        private bool m_Blessed;\n        private bool m_Paralyze;\n        private bool m_Warmode;\n\n        //new\n        private bool m_Unknown;\n        private bool m_Unknown2;\n        private bool m_Unknown3;\n\n        private bool m_CanRename;\n        //end new\n\n        private ushort m_HitsMax, m_Hits;\n        protected ushort m_StamMax, m_Stam, m_ManaMax, m_Mana;\n\n        private List<Serial> m_LoadSerials;\n        private List<Item> m_Items = new List<Item>();\n\n        private byte m_Map;\n        \n        public override void AfterLoad()\n        {\n            int count = m_LoadSerials.Count;\n\n            for (int i = count - 1; i >= 0; --i)\n            {\n                Item it = World.FindItem(m_LoadSerials[i]);\n                if (it != null)\n                    m_Items.Add(it);\n            }\n\n            m_LoadSerials = null; //per il GC e per liberare RAM\n        }\n\n        public Mobile(Serial serial) : base(serial)\n        {\n            m_Map = World.Player == null ? (byte) 0 : World.Player.Map;\n            m_Visible = true;\n\n            Agent.InvokeMobileCreated(this);\n        }\n\n        public string Name\n        {\n            get\n            {\n                if (m_Name == null)\n                    return \"\";\n                else\n                    return m_Name;\n            }\n            set\n            {\n                if (!string.IsNullOrEmpty(value) && value != m_Name)\n                {\n                    string trim = ClilocConversion(value);\n                    if (trim.Length > 0)\n                    {\n                        m_Name = trim;\n                    }\n                }\n            }\n        }\n\n        private static StringBuilder _InternalSB = new StringBuilder(32);\n\n        private static string ClilocConversion(string old)\n        {\n            _InternalSB.Clear();\n            string[] arr = old.Split(' ');\n            for (int i = 0; i < arr.Length; i++)\n            {\n                string ss = arr[i];\n                if (ss.Length > 1 && ss.StartsWith(\"#\"))\n                {\n                    if (int.TryParse(ss.Substring(1), out int x))\n                    {\n                        ss = Language.GetCliloc(x);\n                        if (string.IsNullOrEmpty(ss))\n                        {\n                            ss = arr[i];\n                        }\n                    }\n                }\n\n                _InternalSB.Append(ss);\n                _InternalSB.Append(' ');\n            }\n\n            return _InternalSB.ToString().Trim();\n        }\n\n        public ushort Body\n        {\n            get { return m_Body; }\n            set { m_Body = value; }\n        }\n\n        public Direction Direction\n        {\n            get { return m_Direction; }\n            set\n            {\n                if (value != m_Direction)\n                {\n                    var oldDir = m_Direction;\n                    m_Direction = value;\n                    OnDirectionChanging(oldDir);\n                }\n            }\n        }\n\n        public bool Visible\n        {\n            get { return m_Visible; }\n            set { m_Visible = value; }\n        }\n\n        public bool Poisoned\n        {\n            get { return m_Poisoned; }\n            set { m_Poisoned = value; }\n        }\n\n        public bool Blessed\n        {\n            get { return m_Blessed; }\n            set { m_Blessed = value; }\n        }\n\n        public bool Paralyzed\n        {\n            get { return m_Paralyze; }\n            set { m_Paralyze = value; }\n        }\n\n        public bool IsGhost\n        {\n            get\n            {\n                return m_Body == 402\n                       || m_Body == 403\n                       || m_Body == 607\n                       || m_Body == 608\n                       || m_Body == 970;\n            }\n        }\n\n        public bool IsHuman\n        {\n            get\n            {\n                return m_Body >= 0\n                       && (m_Body == 400\n                           || m_Body == 401\n                           || m_Body == 402\n                           || m_Body == 403\n                           || m_Body == 605\n                           || m_Body == 606\n                           || m_Body == 607\n                           || m_Body == 608\n                           || m_Body == 970); //player ghost\n            }\n        }\n\n        public bool IsMonster\n        {\n            get { return !IsHuman; }\n        }\n\n        //new\n        public bool Unknown\n        {\n            get { return m_Unknown; }\n            set { m_Unknown = value; }\n        }\n\n        public bool Unknown2\n        {\n            get { return m_Unknown2; }\n            set { m_Unknown2 = value; }\n        }\n\n        public bool Unknown3\n        {\n            get { return m_Unknown3; }\n            set { m_Unknown3 = value; }\n        }\n\n        public bool CanRename //A pet! (where the health bar is open, we can add this to an arraylist of mobiles...\n        {\n            get { return m_CanRename; }\n            set { m_CanRename = value; }\n        }\n        //end new\n\n        public bool Warmode\n        {\n            get { return m_Warmode; }\n            set { m_Warmode = value; }\n        }\n\n        public bool Female\n        {\n            get { return m_Female; }\n            set { m_Female = value; }\n        }\n\n        public byte Notoriety\n        {\n            get { return m_Notoriety; }\n            set\n            {\n                if (value != Notoriety)\n                {\n                    OnNotoChange(m_Notoriety, value);\n                    m_Notoriety = value;\n                }\n            }\n        }\n\n        protected virtual void OnNotoChange(byte old, byte cur)\n        {\n        }\n\n        // grey, blue, green, 'canbeattacked'\n        private static uint[] m_NotoHues = new uint[8]\n        {\n            // hue color #30\n            0x000000, // black\t\tunused 0\n            0x30d0e0, // blue\t\t0x0059 1\n            0x60e000, // green\t\t0x003F 2\n            0x9090b2, // greyish\t0x03b2 3\n            0x909090, // grey\t\t   \"   4\n            0xd88038, // orange\t\t0x0090 5\n            0xb01000, // red\t\t0x0022 6\n            0xe0e000 // yellow\t\t0x0035 7\n        };\n\n        private static int[] m_NotoHuesInt = new int[8]\n        {\n            1, // black\t\tunused 0\n            0x059, // blue\t\t0x0059 1\n            0x03F, // green\t\t0x003F 2\n            0x3B2, // greyish\t0x03b2 3\n            0x3B2, // grey\t\t   \"   4\n            0x090, // orange\t\t0x0090 5\n            0x022, // red\t\t0x0022 6\n            0x035, // yellow\t\t0x0035 7\n        };\n\n        public uint GetNotorietyColor()\n        {\n            if (m_Notoriety < 0 || m_Notoriety >= m_NotoHues.Length)\n                return m_NotoHues[0];\n            else\n                return m_NotoHues[m_Notoriety];\n        }\n\n        public int GetNotorietyColorInt()\n        {\n            if (m_Notoriety < 0 || m_Notoriety >= m_NotoHues.Length)\n                return m_NotoHuesInt[0];\n            else\n                return m_NotoHuesInt[m_Notoriety];\n        }\n\n        public byte GetStatusCode()\n        {\n            if (m_Poisoned)\n                return 1;\n            else\n                return 0;\n        }\n\n        public ushort HitsMax\n        {\n            get { return m_HitsMax; }\n            set { m_HitsMax = value; }\n        }\n\n        public ushort Hits\n        {\n            get { return m_Hits; }\n            set { m_Hits = value; }\n        }\n\n        public ushort Stam\n        {\n            get { return m_Stam; }\n            set { m_Stam = value; }\n        }\n\n        public ushort StamMax\n        {\n            get { return m_StamMax; }\n            set { m_StamMax = value; }\n        }\n\n        public ushort Mana\n        {\n            get { return m_Mana; }\n            set { m_Mana = value; }\n        }\n\n        public ushort ManaMax\n        {\n            get { return m_ManaMax; }\n            set { m_ManaMax = value; }\n        }\n\n\n        public byte Map\n        {\n            get { return m_Map; }\n            set\n            {\n                if (m_Map != value)\n                {\n                    OnMapChange(m_Map, value);\n                    m_Map = value;\n                }\n            }\n        }\n\n        public virtual void OnMapChange(byte old, byte cur)\n        {\n        }\n\n        public void AddItem(Item item)\n        {\n            m_Items.Add(item);\n        }\n\n        public void RemoveItem(Item item)\n        {\n            m_Items.Remove(item);\n        }\n\n        public override void Remove()\n        {\n            List<Item> rem = new List<Item>(m_Items);\n            m_Items.Clear();\n\n            for (int i = 0; i < rem.Count; i++)\n                rem[i].Remove();\n\n            if (!InParty)\n            {\n                base.Remove();\n                World.RemoveMobile(this);\n            }\n            else\n            {\n                Visible = false;\n            }\n        }\n\n        public bool InParty\n        {\n            get { return PacketHandlers.Party.Contains(this.Serial); }\n        }\n\n        public Item GetItemOnLayer(Layer layer)\n        {\n            for (int i = 0; i < m_Items.Count; i++)\n            {\n                Item item = (Item) m_Items[i];\n                if (item.Layer == layer)\n                    return item;\n            }\n\n            return null;\n        }\n\n        public Item Backpack\n        {\n            get { return GetItemOnLayer(Layer.Backpack); }\n        }\n\n        public Item Quiver\n        {\n            get\n            {\n                Item item = GetItemOnLayer(Layer.Cloak);\n\n                if (item != null && item.IsContainer)\n                    return item;\n                else\n                    return null;\n            }\n        }\n\n        public Item FindItemByID(ItemID id)\n        {\n            for (int i = 0; i < Contains.Count; i++)\n            {\n                Item item = (Item) Contains[i];\n                if (item.ItemID == id)\n                    return item;\n            }\n\n            return null;\n        }\n\n        public override void OnPositionChanging(Point3D oldPos)\n        {\n            if (this != World.Player && Engine.MainWindow.MapWindow != null)\n                Engine.MainWindow.SafeAction(s => s.MapWindow.CheckLocalUpdate(this));\n\n            base.OnPositionChanging(oldPos);\n        }\n\n        public virtual void OnDirectionChanging(Direction oldDir)\n        {\n        }\n\n        public int GetPacketFlags()\n        {\n            int flags = 0x0;\n\n            if (m_Paralyze)\n                flags |= 0x01;\n\n            if (m_Female)\n                flags |= 0x02;\n\n            if (m_Poisoned)\n                flags |= 0x04;\n\n            if (m_Blessed)\n                flags |= 0x08;\n\n            if (m_Warmode)\n                flags |= 0x40;\n\n            if (!m_Visible)\n                flags |= 0x80;\n\n            if (m_Unknown)\n                flags |= 0x01;\n\n            if (m_Unknown2)\n                flags |= 0x10;\n\n            if (m_Unknown3)\n                flags |= 0x20;\n\n            return flags;\n        }\n\n        public void ProcessPacketFlags(byte flags)\n        {\n            if (!PacketHandlers.UseNewStatus)\n                m_Poisoned = (flags & 0x04) != 0;\n\n            m_Paralyze = (flags & 0x01) != 0;\n            m_Female = (flags & 0x02) != 0;\n            m_Blessed = (flags & 0x08) != 0;\n            m_Unknown2 = (flags & 0x10) != 0; //new\n            m_Unknown3 = (flags & 0x10) != 0; //new\n            m_Warmode = (flags & 0x40) != 0;\n            m_Visible = (flags & 0x80) == 0;\n        }\n\n        public List<Item> Contains\n        {\n            get { return m_Items; }\n        }\n\n        internal void OverheadMessageFrom(int hue, string from, string format, params object[] args)\n        {\n            OverheadMessageFrom(hue, from, String.Format(format, args));\n        }\n\n        internal void OverheadMessageFrom(int hue, string from, string text, bool ascii)\n        {\n            if (Config.GetBool(\"FilterOverheadMessages\"))\n            {\n                if (!MessageQueue.Enqueue(this, hue, \"O\", text))\n                {\n                    return;\n                }\n            }\n\n            if (ascii)\n            {\n                Client.Instance.SendToClient(new AsciiMessage(Serial, m_Body, MessageType.Regular, hue, 3, from, text));\n            }\n            else\n            {\n                Client.Instance.SendToClient(new UnicodeMessage(Serial, m_Body, MessageType.Regular, hue, 3,\n                    Language.CliLocName, from, text));\n            }\n        }\n\n        internal void OverheadMessageFrom(int hue, string from, string text)\n        {\n            bool ascii = Config.GetInt(\"OverheadStyle\") == 0;\n\n            OverheadMessageFrom(hue, from, text, ascii);\n        }\n\n        internal void OverheadMessage(string text)\n        {\n            OverheadMessage(Config.GetInt(\"SysColor\"), text);\n        }\n\n        internal void OverheadMessage(string format, params object[] args)\n        {\n            OverheadMessage(Config.GetInt(\"SysColor\"), String.Format(format, args));\n        }\n\n        internal void OverheadMessage(int hue, string format, params object[] args)\n        {\n            OverheadMessage(hue, String.Format(format, args));\n        }\n\n        internal void OverheadMessage(int hue, string text)\n        {\n            OverheadMessageFrom(hue, \"Razor\", text);\n        }\n\n        internal void OverheadMessage(LocString str)\n        {\n            OverheadMessage(Language.GetString(str));\n        }\n\n        internal void OverheadMessage(LocString str, params object[] args)\n        {\n            OverheadMessage(Language.Format(str, args));\n        }\n\n        private Point2D m_ButtonPoint = Point2D.Zero;\n\n        internal Point2D ButtonPoint\n        {\n            get { return m_ButtonPoint; }\n            set { m_ButtonPoint = value; }\n        }\n\n        private static List<Layer> _layers = new List<Layer>\n        {\n            Layer.Backpack,\n            Layer.Invalid,\n            Layer.FirstValid,\n            Layer.RightHand,\n            Layer.LeftHand,\n            Layer.Shoes,\n            Layer.Pants,\n            Layer.Shirt,\n            Layer.Head,\n            Layer.Neck,\n            Layer.Gloves,\n            Layer.InnerTorso,\n            Layer.MiddleTorso,\n            Layer.Arms,\n            Layer.Cloak,\n            Layer.OuterTorso,\n            Layer.OuterLegs,\n            Layer.InnerLegs,\n            Layer.LastUserValid,\n            Layer.Mount,\n            Layer.LastValid,\n            Layer.Hair\n        };\n\n        internal void ResetLayerHue()\n        {\n            if (IsGhost)\n                return;\n\n            foreach (Layer l in _layers)\n            {\n                Item i = GetItemOnLayer(l);\n\n                if (i == null)\n                    continue;\n\n                if (i.ItemID == 0x204E && i.Hue == 0x08FD) // death shroud\n                    i.ItemID = 0x1F03;\n\n                Client.Instance.SendToClient(new EquipmentItem(i, i.Hue, Serial));\n            }\n        }\n\n        internal void SetLayerHue(int hue)\n        {\n            if (IsGhost)\n                return;\n\n            foreach (Layer l in _layers)\n            {\n                Item i = GetItemOnLayer(l);\n                if (i == null)\n                    continue;\n\n                Client.Instance.SendToClient(new EquipmentItem(i, (ushort) hue, Serial));\n            }\n        }\n\n        internal Packet SetMobileHue(Packet p, int hue)\n        {\n            if (IsGhost)\n                return p;\n\n            p = WriteHueToPacket(p, (ushort) hue);\n\n            return p;\n        }\n\n        private static Packet WriteHueToPacket(Packet p, ushort color)\n        {\n            p.Seek(-3, SeekOrigin.Current);\n            p.Write((short) color);\n            p.Seek(+1, SeekOrigin.Current);\n            return p;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/MsgQueue.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Concurrent;\r\nusing System.Collections.Generic;\r\n\r\nnamespace Assistant\r\n{\r\n    public class MessageQueue\r\n    {\r\n        private class MsgInfo\r\n        {\r\n            public MsgInfo(Serial ser, Mobile m, ushort body, MessageType type, ushort hue, ushort font, string lang,\r\n                string name)\r\n            {\r\n                Serial = ser;\r\n                Body = body;\r\n                Type = type;\r\n                Hue = hue;\r\n                Font = font;\r\n                Lang = lang;\r\n                Name = name;\r\n                Mobile = m;\r\n            }\r\n\r\n            public TimeSpan Delay;\r\n            public DateTime NextSend;\r\n            public int Count;\r\n\r\n            public Mobile Mobile;\r\n\r\n            //ser, body, type, hue, font, lang, name\r\n            public Serial Serial;\r\n            public ushort Body, Hue, Font;\r\n            public MessageType Type;\r\n            public string Lang, Name;\r\n        }\r\n\r\n        private class MessageTimer : Timer\r\n        {\r\n            public MessageTimer() : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))\r\n            {\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                if (m_Table.Count <= 0)\r\n                    return;\r\n\r\n                List<string> toremove = new List<string>();\r\n                foreach (KeyValuePair<string, MsgInfo> de in m_Table)\r\n                {\r\n                    string txt = de.Key;\r\n                    MsgInfo msg = de.Value;\r\n\r\n                    if (msg.NextSend <= DateTime.UtcNow)\r\n                    {\r\n                        if (msg.Count > 0)\r\n                        {\r\n                            switch (msg.Lang)\r\n                            {\r\n                                case \"O\":\r\n                                    msg.Mobile.OverheadMessage(msg.Hue, msg.Count > 1 ? $\"{txt} [{msg.Count}]\" : txt);\r\n\r\n                                    break;\r\n                                case \"A\":\r\n                                    Client.Instance.SendToClient(new AsciiMessage(msg.Serial, msg.Body, msg.Type,\r\n                                        msg.Hue, msg.Font, msg.Name,\r\n                                        msg.Count > 1 ? $\"{txt} [{msg.Count}]\" : txt));\r\n                                    break;\r\n                                default:\r\n                                    Client.Instance.SendToClient(new UnicodeMessage(msg.Serial, msg.Body, msg.Type,\r\n                                        msg.Hue, msg.Font, msg.Lang, msg.Name,\r\n                                        msg.Count > 1 ? $\"{txt} [{msg.Count}]\" : txt));\r\n                                    break;\r\n                            }\r\n\r\n                            msg.Count = 0;\r\n                            msg.NextSend = DateTime.UtcNow + msg.Delay;\r\n                        }\r\n                        else\r\n                        {\r\n                            if (txt != null)\r\n                                toremove.Add(txt);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                for (int i = toremove.Count - 1; i >= 0; --i)\r\n                {\r\n                    m_Table.TryRemove(toremove[i], out var msg);\r\n                }\r\n            }\r\n        }\r\n\r\n        private static Timer m_Timer = new MessageTimer();\r\n        private static ConcurrentDictionary<string, MsgInfo> m_Table = new ConcurrentDictionary<string, MsgInfo>();\r\n\r\n        static MessageQueue()\r\n        {\r\n            m_Timer.Start();\r\n        }\r\n\r\n        public static bool Enqueue(Mobile m, int hue, string lang, string text)\r\n        {\r\n            return Enqueue(0xFFFFFFFF, m, 0, MessageType.Regular, (ushort) hue, 3, lang, \"System\", text);\r\n        }\r\n\r\n        public static bool Enqueue(Serial ser, Mobile mobile, ushort body, MessageType type, ushort hue, ushort font,\r\n            string lang,\r\n            string name, string text)\r\n        {\r\n            MsgInfo m;\r\n\r\n            if (!m_Table.TryGetValue(text, out m) || m == null)\r\n            {\r\n                m_Table[text] = m = new MsgInfo(ser, mobile, body, type, hue, font, lang, name);\r\n\r\n                m.Count = 0;\r\n\r\n                m.Delay = TimeSpan.FromSeconds((text.Length / 50 + 1) * Config.GetDouble(\"FilterDelay\"));\r\n\r\n                m.NextSend = DateTime.UtcNow + m.Delay;\r\n\r\n                return true;\r\n            }\r\n\r\n            m.Count++;\r\n\r\n            return false;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/ObjectPropertyList.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Text;\r\nusing System.Collections.Generic;\r\n\r\nnamespace Assistant\r\n{\r\n    public class ObjectPropertyList\r\n    {\r\n        private class OPLEntry\r\n        {\r\n            public int Number = 0;\r\n            public string Args = null;\r\n\r\n            public OPLEntry(int num) : this(num, null)\r\n            {\r\n            }\r\n\r\n            public OPLEntry(int num, string args)\r\n            {\r\n                Number = num;\r\n                Args = args;\r\n            }\r\n        }\r\n\r\n        private List<int> m_StringNums = new List<int>();\r\n\r\n        private int m_Hash = 0;\r\n        private List<OPLEntry> m_Content = new List<OPLEntry>();\r\n\r\n        private int m_CustomHash = 0;\r\n        private List<OPLEntry> m_CustomContent = new List<OPLEntry>();\r\n\r\n\r\n        private UOEntity m_Owner = null;\r\n\r\n        public int Hash\r\n        {\r\n            get { return m_Hash ^ m_CustomHash; }\r\n            set { m_Hash = value; }\r\n        }\r\n\r\n        public int ServerHash\r\n        {\r\n            get { return m_Hash; }\r\n        }\r\n\r\n        public bool Customized\r\n        {\r\n            get { return m_CustomHash != 0; }\r\n        }\r\n\r\n        public ObjectPropertyList(UOEntity owner)\r\n        {\r\n            m_Owner = owner;\r\n\r\n            m_StringNums.AddRange(m_DefaultStringNums);\r\n        }\r\n\r\n        public UOEntity Owner\r\n        {\r\n            get { return m_Owner; }\r\n        }\r\n\r\n        public void Read(PacketReader p)\r\n        {\r\n            m_Content.Clear();\r\n\r\n            p.Seek(5, System.IO.SeekOrigin.Begin); // seek to packet data\r\n\r\n            p.ReadUInt32(); // serial\r\n            p.ReadByte(); // 0\r\n            p.ReadByte(); // 0\r\n            m_Hash = p.ReadInt32();\r\n\r\n            m_StringNums.Clear();\r\n            m_StringNums.AddRange(m_DefaultStringNums);\r\n\r\n            while (p.Position < p.Length)\r\n            {\r\n                int num = p.ReadInt32();\r\n                if (num == 0)\r\n                    break;\r\n\r\n                m_StringNums.Remove(num);\r\n\r\n                short bytes = p.ReadInt16();\r\n                string args = null;\r\n                if (bytes > 0)\r\n                    args = p.ReadUnicodeStringBE(bytes >> 1);\r\n\r\n                m_Content.Add(new OPLEntry(num, args));\r\n            }\r\n\r\n            for (int i = 0; i < m_CustomContent.Count; i++)\r\n            {\r\n                OPLEntry ent = (OPLEntry) m_CustomContent[i];\r\n                if (m_StringNums.Contains(ent.Number))\r\n                {\r\n                    m_StringNums.Remove(ent.Number);\r\n                }\r\n                else\r\n                {\r\n                    for (int s = 0; s < m_DefaultStringNums.Length; s++)\r\n                    {\r\n                        if (ent.Number == m_DefaultStringNums[s])\r\n                        {\r\n                            ent.Number = GetStringNumber();\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        public void Add(int number)\r\n        {\r\n            if (number == 0)\r\n                return;\r\n\r\n            AddHash(number);\r\n\r\n            m_CustomContent.Add(new OPLEntry(number));\r\n        }\r\n\r\n        private static byte[] m_Buffer = new byte[0];\r\n\r\n        public void AddHash(int val)\r\n        {\r\n            m_CustomHash ^= (val & 0x3FFFFFF);\r\n            m_CustomHash ^= (val >> 26) & 0x3F;\r\n        }\r\n\r\n        public void Add(int number, string arguments)\r\n        {\r\n            if (number == 0)\r\n                return;\r\n\r\n            AddHash(number);\r\n            m_CustomContent.Add(new OPLEntry(number, arguments));\r\n        }\r\n\r\n        public void Add(int number, string format, object arg0)\r\n        {\r\n            Add(number, String.Format(format, arg0));\r\n        }\r\n\r\n        public void Add(int number, string format, object arg0, object arg1)\r\n        {\r\n            Add(number, String.Format(format, arg0, arg1));\r\n        }\r\n\r\n        public void Add(int number, string format, object arg0, object arg1, object arg2)\r\n        {\r\n            Add(number, String.Format(format, arg0, arg1, arg2));\r\n        }\r\n\r\n        public void Add(int number, string format, params object[] args)\r\n        {\r\n            Add(number, String.Format(format, args));\r\n        }\r\n\r\n        private static int[] m_DefaultStringNums = new int[]\r\n        {\r\n            1042971, // ~1_NOTHING~\r\n            1070722, // ~1_NOTHING~\r\n            1063483, // ~1_MATERIAL~ ~2_ITEMNAME~\r\n            1076228, // ~1_DUMMY~ ~2_DUMMY~\r\n            1060847, // ~1_val~ ~2_val~\r\n            1050039 // ~1_NUMBER~ ~2_ITEMNAME~\r\n            // these are ugly:\r\n            //1062613, // \"~1_NAME~\" (orange)\r\n            //1049644, // [~1_stuff~]\r\n        };\r\n\r\n        private int GetStringNumber()\r\n        {\r\n            if (m_StringNums.Count > 0)\r\n            {\r\n                int num = (int) m_StringNums[0];\r\n                m_StringNums.RemoveAt(0);\r\n                return num;\r\n            }\r\n            else\r\n            {\r\n                return 1049644;\r\n            }\r\n        }\r\n\r\n        private const string RazorHTMLFormat = \" <CENTER><BASEFONT COLOR=#FF0000>{0}</BASEFONT></CENTER> \";\r\n\r\n        public void Add(string text)\r\n        {\r\n            Add(GetStringNumber(), String.Format(RazorHTMLFormat, text));\r\n        }\r\n\r\n        public void Add(string format, string arg0)\r\n        {\r\n            Add(GetStringNumber(), String.Format(format, arg0));\r\n        }\r\n\r\n        public void Add(string format, string arg0, string arg1)\r\n        {\r\n            Add(GetStringNumber(), String.Format(format, arg0, arg1));\r\n        }\r\n\r\n        public void Add(string format, string arg0, string arg1, string arg2)\r\n        {\r\n            Add(GetStringNumber(), String.Format(format, arg0, arg1, arg2));\r\n        }\r\n\r\n        public void Add(string format, params object[] args)\r\n        {\r\n            Add(GetStringNumber(), String.Format(format, args));\r\n        }\r\n\r\n        public bool Remove(int number)\r\n        {\r\n            for (int i = 0; i < m_Content.Count; i++)\r\n            {\r\n                OPLEntry ent = (OPLEntry) m_Content[i];\r\n                if (ent == null)\r\n                    continue;\r\n\r\n                if (ent.Number == number)\r\n                {\r\n                    for (int s = 0; s < m_DefaultStringNums.Length; s++)\r\n                    {\r\n                        if (m_DefaultStringNums[s] == ent.Number)\r\n                        {\r\n                            m_StringNums.Insert(0, ent.Number);\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    m_Content.RemoveAt(i);\r\n                    AddHash(ent.Number);\r\n                    if (!string.IsNullOrEmpty(ent.Args))\r\n                        AddHash(ent.Args.GetHashCode());\r\n\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            for (int i = 0; i < m_CustomContent.Count; i++)\r\n            {\r\n                OPLEntry ent = (OPLEntry) m_CustomContent[i];\r\n                if (ent == null)\r\n                    continue;\r\n\r\n                if (ent.Number == number)\r\n                {\r\n                    for (int s = 0; s < m_DefaultStringNums.Length; s++)\r\n                    {\r\n                        if (m_DefaultStringNums[s] == ent.Number)\r\n                        {\r\n                            m_StringNums.Insert(0, ent.Number);\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    m_CustomContent.RemoveAt(i);\r\n                    AddHash(ent.Number);\r\n                    if (!string.IsNullOrEmpty(ent.Args))\r\n                        AddHash(ent.Args.GetHashCode());\r\n                    if (m_CustomContent.Count == 0)\r\n                        m_CustomHash = 0;\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public bool Remove(string str)\r\n        {\r\n            string htmlStr = String.Format(RazorHTMLFormat, str);\r\n\r\n            /*for ( int i = 0; i < m_Content.Count; i++ )\r\n            {\r\n                 OPLEntry ent = (OPLEntry)m_Content[i];\r\n                 if ( ent == null )\r\n                      continue;\r\n\r\n                 for (int s=0;s<m_DefaultStringNums.Length;s++)\r\n                 {\r\n                      if ( ent.Number == m_DefaultStringNums[s] && ( ent.Args == htmlStr || ent.Args == str ) )\r\n                      {\r\n                           m_StringNums.Insert( 0, ent.Number );\r\n\r\n                           m_Content.RemoveAt( i );\r\n\r\n                           AddHash( ent.Number );\r\n                           if ( ent.Args != null && ent.Args != \"\" )\r\n                                AddHash( ent.Args.GetHashCode() );\r\n                           return true;\r\n                      }\r\n                 }\r\n            }*/\r\n\r\n            for (int i = 0; i < m_CustomContent.Count; i++)\r\n            {\r\n                OPLEntry ent = (OPLEntry) m_CustomContent[i];\r\n                if (ent == null)\r\n                    continue;\r\n\r\n                for (int s = 0; s < m_DefaultStringNums.Length; s++)\r\n                {\r\n                    if (ent.Number == m_DefaultStringNums[s] && (ent.Args == htmlStr || ent.Args == str))\r\n                    {\r\n                        m_StringNums.Insert(0, ent.Number);\r\n\r\n                        m_CustomContent.RemoveAt(i);\r\n\r\n                        AddHash(ent.Number);\r\n                        if (!string.IsNullOrEmpty(ent.Args))\r\n                            AddHash(ent.Args.GetHashCode());\r\n                        return true;\r\n                    }\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public Packet BuildPacket()\r\n        {\r\n            Packet p = new Packet(0xD6);\r\n\r\n            p.EnsureCapacity(128);\r\n\r\n            p.Write((short) 0x01);\r\n            p.Write((uint) (m_Owner != null ? m_Owner.Serial : Serial.Zero));\r\n            p.Write((byte) 0);\r\n            p.Write((byte) 0);\r\n            p.Write((uint) (m_Hash ^ m_CustomHash));\r\n\r\n            foreach (OPLEntry ent in m_Content)\r\n            {\r\n                if (ent != null && ent.Number != 0)\r\n                {\r\n                    p.Write((int) ent.Number);\r\n                    if (!string.IsNullOrEmpty(ent.Args))\r\n                    {\r\n                        int byteCount = Encoding.Unicode.GetByteCount(ent.Args);\r\n\r\n                        if (byteCount > m_Buffer.Length)\r\n                            m_Buffer = new byte[byteCount];\r\n\r\n                        byteCount = Encoding.Unicode.GetBytes(ent.Args, 0, ent.Args.Length, m_Buffer, 0);\r\n\r\n                        p.Write((short) byteCount);\r\n                        p.Write(m_Buffer, 0, byteCount);\r\n                    }\r\n                    else\r\n                    {\r\n                        p.Write((short) 0);\r\n                    }\r\n                }\r\n            }\r\n\r\n            foreach (OPLEntry ent in m_CustomContent)\r\n            {\r\n                try\r\n                {\r\n                    if (ent != null && ent.Number != 0)\r\n                    {\r\n                        string arguments = ent.Args;\r\n\r\n                        p.Write((int) ent.Number);\r\n\r\n                        if (string.IsNullOrEmpty(arguments))\r\n                            arguments = \" \";\r\n                        arguments += \"\\t \";\r\n\r\n                        if (!string.IsNullOrEmpty(arguments))\r\n                        {\r\n                            int byteCount = Encoding.Unicode.GetByteCount(arguments);\r\n\r\n                            if (byteCount > m_Buffer.Length)\r\n                                m_Buffer = new byte[byteCount];\r\n\r\n                            byteCount = Encoding.Unicode.GetBytes(arguments, 0, arguments.Length, m_Buffer, 0);\r\n\r\n                            p.Write((short) byteCount);\r\n                            p.Write(m_Buffer, 0, byteCount);\r\n                        }\r\n                        else\r\n                        {\r\n                            p.Write((short) 0);\r\n                        }\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n\r\n            p.Write((int) 0);\r\n\r\n            return p;\r\n        }\r\n    }\r\n\r\n    public class OPLInfo : Packet\r\n    {\r\n        public OPLInfo(Serial ser, int hash) : base(0xDC, 9)\r\n        {\r\n            Write((uint) ser);\r\n            Write((int) hash);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/OverheadManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Filters;\nusing Assistant.UI;\nusing Ultima;\n\nnamespace Assistant.Core\n{\n    public class OverheadMessage\n    {\n        public string SearchMessage { get; set; }\n        public string MessageOverhead { get; set; }\n        public int Hue { get; set; }\n        public int Sound { get; set; }\n    }\n\n    public static class OverheadManager\n    {\n        private static ListView _listView;\n\n        public static List<OverheadMessage> OverheadMessages = new List<OverheadMessage>();\n\n        public static void SetControls(ListView listView)\n        {\n            _listView = listView;\n        }\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (var message in OverheadMessages)\n            {\n                xml.WriteStartElement(\"overheadmessage\");\n                xml.WriteAttributeString(\"searchtext\", message.SearchMessage);\n                xml.WriteAttributeString(\"message\", (message.MessageOverhead));\n                xml.WriteAttributeString(\"hue\", Convert.ToString(message.Hue));\n                xml.WriteAttributeString(\"sound\", Convert.ToString(message.Sound));\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"overheadmessage\"))\n                {\n                    OverheadMessage overheadMessage = new OverheadMessage\n                    {\n                        MessageOverhead = el.GetAttribute(\"message\"),\n                        SearchMessage = el.GetAttribute(\"searchtext\"),\n                        Hue = string.IsNullOrEmpty(el.GetAttribute(\"hue\"))\n                            ? 68\n                            : Convert.ToInt32(el.GetAttribute(\"hue\")),\n                        Sound = string.IsNullOrEmpty(el.GetAttribute(\"sound\"))\n                        ? -1\n                        : Convert.ToInt32(el.GetAttribute(\"sound\"))\n                    };\n\n                    OverheadMessages.Add(overheadMessage);\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        public static void ClearAll()\n        {\n            OverheadMessages.Clear();\n        }\n\n        public static void Remove(string text)\n        {\n            foreach (OverheadMessage message in OverheadMessages)\n            {\n                if (message.SearchMessage.Equals(text))\n                {\n                    OverheadMessages.Remove(message);\n                    break;\n                }\n            }\n        }\n\n        public static void RedrawList()\n        {\n            _listView.SafeAction(s => s.Items.Clear());\n\n            foreach (OverheadMessage message in OverheadMessages)\n            {\n                ListViewItem item = new ListViewItem($\"{message.SearchMessage}\");\n                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, message.MessageOverhead));\n                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, SoundMusicManager.GetSoundName((ushort) message.Sound)));\n\n                int hueIdx = message.Hue;\n\n                item.SubItems[1].BackColor = hueIdx > 0 && hueIdx < 3000\n                    ? Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX)\n                    : SystemColors.Control;\n\n                item.SubItems[1].ForeColor = (item.SubItems[1].BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\n\n                item.UseItemStyleForSubItems = false;\n\n                _listView.SafeAction(s => s.Items.Add(item));\n            }\n        }\n\n        public static void DisplayOverheadMessage(string text)\n        {\n            if (Config.GetBool(\"ShowOverheadMessages\") && OverheadMessages.Count > 0)\n            {\n                string overheadFormat = Config.GetString(\"OverheadFormat\");\n\n                foreach (OverheadMessage message in OverheadMessages)\n                {\n                    if (text.IndexOf(message.SearchMessage, StringComparison.OrdinalIgnoreCase) != -1)\n                    {\n                        string ohMessage = overheadFormat.Replace(\"{msg}\", message.MessageOverhead);\n                        string[] splitText = text.Split(' ');\n\n                        if (splitText.Length > 0)\n                        {\n                            for (int wordNum = 1; wordNum < splitText.Length + 1; wordNum++)\n                            {\n                                ohMessage = ohMessage.Replace($\"{{{wordNum}}}\", splitText[wordNum - 1]);\n                            }\n                        }\n\n                        World.Player.OverheadMessage(message.Hue, ohMessage);\n\n                        if (message.Sound > -1)\n                        {\n                            Client.Instance.SendToClient(new PlaySound(message.Sound));\n                        }\n\n                        break;\n                    }\n                }\n            }\n        }\n\n        public static void SetOverheadHue()\n        {\n            ListViewItem selectedItem = _listView.Items[_listView.SelectedIndices[0]];\n\n            HueEntry h = new HueEntry(GetHue(selectedItem.SubItems[1].Text));\n\n            if (h.ShowDialog(Engine.MainWindow) == DialogResult.OK)\n            {\n                int hueIdx = h.Hue;\n\n                if (hueIdx > 0 && hueIdx < 3000)\n                    selectedItem.SubItems[1].BackColor = Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n                else\n                    selectedItem.SubItems[1].BackColor = Color.White;\n\n                selectedItem.SubItems[1].ForeColor = (selectedItem.SubItems[1].BackColor.GetBrightness() < 0.35\n                    ? Color.White\n                    : Color.Black);\n\n                foreach (OverheadMessage list in OverheadManager.OverheadMessages)\n                {\n                    if (list.SearchMessage.Equals(selectedItem.Text))\n                    {\n                        list.Hue = hueIdx;\n                        break;\n                    }\n                }\n            }\n        }\n\n        public static int GetHue(string id)\n        {\n            int hue = 0;\n\n            foreach (OverheadMessage list in OverheadManager.OverheadMessages)\n            {\n                if (list.MessageOverhead.Equals(id))\n                {\n                    return list.Hue;\n                }\n            }\n\n            return hue;\n        }\n\n        public static void SetOverheadSound()\n        {\n            ListViewItem selectedItem = _listView.Items[_listView.SelectedIndices[0]];\n\n            int soundId = SoundMusicManager.GetSoundId(selectedItem.SubItems[2].Text);\n\n            SoundEntry soundDialog = new SoundEntry(soundId, selectedItem.SubItems[2].Text);\n\n            if (soundDialog.ShowDialog(Engine.MainWindow) == DialogResult.OK)\n            {\n                selectedItem.SubItems[2].Text = SoundMusicManager.GetSoundName((ushort) soundId);\n                \n                foreach (OverheadMessage list in OverheadMessages)\n                {\n                    if (list.SearchMessage.Equals(selectedItem.Text))\n                    {\n                        list.Sound = soundDialog.Sound;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/Overrides.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\n\n#region license\n\n// Razor: An Ultima Online Assistant\n// Copyright (C) 2021 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#endregion\n\nnamespace Assistant.Core\n{\n    public static class Overrides\n    {\n        public static Dictionary<ushort, bool> TwoHanded { get; private set; }\n\n        public static void Load()\n        {\n            if (TwoHanded == null)\n                TwoHanded = new Dictionary<ushort, bool>();\n            else\n                TwoHanded.Clear();\n\n            string file = Path.Combine(Config.GetInstallDirectory(), \"overrides.def\");\n\n            if (!File.Exists(file))\n            {\n                return;\n            }\n\n            string[] lines = File.ReadAllLines(file);\n\n            foreach (string line in lines)\n            {\n                if (string.IsNullOrEmpty(line) || line[0] == '#')\n                {\n                    continue;\n                }\n\n                string[] split = line.Trim().Split(' ');\n\n                switch (split[0])\n                {\n                    case \"twohanded\":\n                        TwoHanded.Add(Convert.ToUInt16(split[1], 16), Convert.ToBoolean(split[2]));\n                        break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Core/PasswordMemory.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Xml;\r\nusing System.Text;\r\nusing System.Collections;\r\nusing System.Net;\r\n\r\nnamespace Assistant\r\n{\r\n    public class PasswordMemory\r\n    {\r\n        private class Entry\r\n        {\r\n            public Entry()\r\n            {\r\n            }\r\n\r\n            public Entry(string u, string p, IPAddress a)\r\n            {\r\n                User = u;\r\n                Pass = p;\r\n                Address = a;\r\n            }\r\n\r\n            public string User;\r\n            public string Pass;\r\n            public IPAddress Address;\r\n        }\r\n\r\n        private static ArrayList m_List = new ArrayList();\r\n\r\n        public static string Encrypt(string source)\r\n        {\r\n            byte[] buff = ASCIIEncoding.ASCII.GetBytes(source);\r\n            int kidx = 0;\r\n            string key = Platform.GetWindowsUserName();\r\n            if (key == String.Empty)\r\n                return String.Empty;\r\n            StringBuilder sb = new StringBuilder(source.Length * 2 + 2);\r\n            sb.Append(\"1+\");\r\n            for (int i = 0; i < buff.Length; i++)\r\n            {\r\n                sb.AppendFormat(\"{0:X2}\", (byte) (buff[i] ^ ((byte) key[kidx++])));\r\n                if (kidx >= key.Length)\r\n                    kidx = 0;\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public static string Decrypt(string source)\r\n        {\r\n            byte[] buff = null;\r\n\r\n            if (source.Length > 2 && source[0] == '1' && source[1] == '+')\r\n            {\r\n                buff = new byte[(source.Length - 2) / 2];\r\n                string key = Platform.GetWindowsUserName();\r\n                if (key == String.Empty)\r\n                    return String.Empty;\r\n                int kidx = 0;\r\n                for (int i = 2; i < source.Length; i += 2)\r\n                {\r\n                    byte c;\r\n                    try\r\n                    {\r\n                        c = Convert.ToByte(source.Substring(i, 2), 16);\r\n                    }\r\n                    catch\r\n                    {\r\n                        continue;\r\n                    }\r\n\r\n                    buff[(i - 2) / 2] = (byte) (c ^ ((byte) key[kidx++]));\r\n                    if (kidx >= key.Length)\r\n                        kidx = 0;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                byte key = (byte) (source.Length / 2);\r\n                buff = new byte[key];\r\n\r\n                for (int i = 0; i < source.Length; i += 2)\r\n                {\r\n                    byte c;\r\n                    try\r\n                    {\r\n                        c = Convert.ToByte(source.Substring(i, 2), 16);\r\n                    }\r\n                    catch\r\n                    {\r\n                        continue;\r\n                    }\r\n\r\n                    buff[i / 2] = (byte) (c ^ key++);\r\n                }\r\n            }\r\n\r\n            return ASCIIEncoding.ASCII.GetString(buff);\r\n        }\r\n\r\n        public static void Load(XmlElement xml)\r\n        {\r\n            ClearAll();\r\n\r\n            if (xml == null)\r\n                return;\r\n\r\n            foreach (XmlElement el in xml.GetElementsByTagName(\"password\"))\r\n            {\r\n                try\r\n                {\r\n                    string user = el.GetAttribute(\"user\");\r\n                    string addr = el.GetAttribute(\"ip\");\r\n\r\n                    if (el.InnerText == null)\r\n                        continue;\r\n\r\n                    m_List.Add(new Entry(user, el.InnerText, IPAddress.Parse(addr)));\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Save(XmlTextWriter xml)\r\n        {\r\n            if (m_List == null)\r\n                return;\r\n\r\n            foreach (Entry e in m_List)\r\n            {\r\n                if (e.Pass != String.Empty)\r\n                {\r\n                    xml.WriteStartElement(\"password\");\r\n                    try\r\n                    {\r\n                        xml.WriteAttributeString(\"user\", e.User);\r\n                        xml.WriteAttributeString(\"ip\", e.Address.ToString());\r\n                        xml.WriteString(e.Pass);\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n\r\n                    xml.WriteEndElement();\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void ClearAll()\r\n        {\r\n            m_List.Clear();\r\n        }\r\n\r\n        public static void Add(string user, string pass, IPAddress addr)\r\n        {\r\n            if (pass == \"\")\r\n                return;\r\n\r\n            user = user.ToLower();\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                Entry e = (Entry) m_List[i];\r\n                if (e.User == user && e.Address.Equals(addr))\r\n                {\r\n                    e.Pass = Encrypt(pass);\r\n                    return;\r\n                }\r\n            }\r\n\r\n            m_List.Add(new Entry(user, Encrypt(pass), addr));\r\n        }\r\n\r\n        public static string Find(string user, IPAddress addr)\r\n        {\r\n            user = user.ToLower();\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                Entry e = (Entry) m_List[i];\r\n                if (e.User == user && e.Address.Equals(addr))\r\n                    return Decrypt(e.Pass);\r\n            }\r\n\r\n            return String.Empty;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/Ping.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\n\r\nnamespace Assistant\r\n{\r\n    public class Ping\r\n    {\r\n        private static DateTime m_Start;\r\n        private static byte m_Seq;\r\n        private static double m_Time, m_Min, m_Max;\r\n        private static int m_Total;\r\n        private static int m_Count;\r\n\r\n        public static bool Response(byte seq)\r\n        {\r\n            if (seq == m_Seq && m_Start != DateTime.MinValue)\r\n            {\r\n                double ms = (DateTime.UtcNow - m_Start).TotalMilliseconds;\r\n\r\n                if (ms < m_Min)\r\n                    m_Min = ms;\r\n                if (ms > m_Max)\r\n                    m_Max = ms;\r\n\r\n                if (m_Count-- > 0)\r\n                {\r\n                    m_Time += ms;\r\n                    World.Player.SendMessage(MsgLevel.Force, $\"Response: {ms:F1}ms\");\r\n                    DoPing();\r\n                }\r\n                else\r\n                {\r\n                    m_Start = DateTime.MinValue;\r\n                    World.Player.SendMessage(MsgLevel.Force, \"Ping Result:\");\r\n                    World.Player.SendMessage(MsgLevel.Force, \"Min: {0:F1}ms  Max: {1:F1}ms  Avg: {2:F1}ms\", m_Min,\r\n                        m_Max, m_Time / ((double) m_Total));\r\n                }\r\n\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static void StartPing(int count)\r\n        {\r\n            if (count <= 0 || count > 20)\r\n                m_Count = 5;\r\n            else\r\n                m_Count = count;\r\n\r\n            m_Total = m_Count;\r\n            m_Time = 0;\r\n            m_Min = double.MaxValue;\r\n            m_Max = 0;\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, \"Pinging server with {0} packets ({1} bytes)...\", m_Count,\r\n                m_Count * 2);\r\n            DoPing();\r\n        }\r\n\r\n        private static void DoPing()\r\n        {\r\n            m_Seq = (byte) Utility.Random(256);\r\n            m_Start = DateTime.UtcNow;\r\n            Client.Instance.SendToServer(new PingPacket(m_Seq));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/Player.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Assistant.Agents;\nusing Assistant.Core;\nusing Assistant.Gumps;\nusing Assistant.Macros;\nusing Assistant.UI;\n\nnamespace Assistant\n{\n    public enum LockType : byte\n    {\n        Up = 0,\n        Down = 1,\n        Locked = 2\n    }\n\n    public enum MsgLevel\n    {\n        Debug = 0,\n        Info = 0,\n        Warning = 1,\n        Error = 2,\n        Force = 3,\n        Friend = 4\n    }\n\n    public class Skill\n    {\n        private LockType _lock;\n        private ushort _value;\n        private ushort _base;\n        private ushort _cap;\n        private short _delta;\n        private int _index;\n\n        public Skill(int idx)\n        {\n            _index = idx;\n        }\n\n        public int Index\n        {\n            get { return _index; }\n        }\n\n        public LockType Lock\n        {\n            get { return _lock; }\n            set { _lock = value; }\n        }\n\n        public ushort FixedValue\n        {\n            get { return _value; }\n            set { _value = value; }\n        }\n\n        public ushort FixedBase\n        {\n            get { return _base; }\n            set\n            {\n                _delta += (short) (value - _base);\n                _base = value;\n            }\n        }\n\n        public ushort FixedCap\n        {\n            get { return _cap; }\n            set { _cap = value; }\n        }\n\n        public double Value\n        {\n            get { return _value / 10.0; }\n            set { _value = (ushort) (value * 10.0); }\n        }\n\n        public double Base\n        {\n            get { return _base / 10.0; }\n            set { _base = (ushort) (value * 10.0); }\n        }\n\n        public double Cap\n        {\n            get { return _cap / 10.0; }\n            set { _cap = (ushort) (value * 10.0); }\n        }\n\n        public double Delta\n        {\n            get { return _delta / 10.0; }\n            set { _delta = (short) (value * 10); }\n        }\n    }\n\n    public enum MaleSounds\n    {\n        Ah = 0x419,\n        Ahha = 0x41A,\n        Applaud = 0x41B,\n        Blownose = 0x41C,\n        Burp = 0x41D,\n        Cheer = 0x41E,\n        Clear_Throat = 0x41F,\n        Cough = 0x420,\n        Coughbs = 0x421,\n        Cry = 0x422,\n        Death_01 = 0x423,\n        Death_02 = 0x424,\n        Death_03 = 0x425,\n        Death_04 = 0x426,\n        Death_05 = 0x427,\n        Fart = 0x428,\n        Gasp = 0x429,\n        Giggle = 0x42A,\n        Groan = 0x42B,\n        Growl = 0x42C,\n        Hey = 0x42D,\n        Hiccup = 0x42E,\n        Huh = 0x42F,\n        Kiss = 0x430,\n        Laugh = 0x431,\n        No = 0x432,\n        Oh = 0x433,\n        Oomph_01 = 0x434,\n        Oomph_02 = 0x435,\n        Oomph_03 = 0x436,\n        Oomph_04 = 0x437,\n        Oomph_05 = 0x438,\n        Oomph_06 = 0x439,\n        Oomph_07 = 0x43A,\n        Oomph_08 = 0x43B,\n        Oomph_09 = 0x43C,\n        Oooh = 0x43D,\n        Oops = 0x43E,\n        Puke = 0x43F,\n        Scream = 0x440,\n        Shush = 0x441,\n        Sigh = 0x442,\n        Sneeze = 0x443,\n        Sniff = 0x444,\n        Snore = 0x445,\n        Spit = 0x446,\n        Whistle = 0x447,\n        Yawn = 0x448,\n        Yea = 0x449,\n        Yell = 0x44A\n    }\n\n    public enum FemaleSounds\n    {\n        Ah = 0x30A,\n        Ahha = 0x30B,\n        Applaud = 0x30C,\n        Blownose = 0x30D,\n        Burp = 0x30E,\n        Cheer = 0x30F,\n        Clear_Throat = 0x310,\n        Cough = 0x311,\n        Coughbs = 0x312,\n        Cry = 0x313,\n        Death_01 = 0x314,\n        Death_02 = 0x315,\n        Death_03 = 0x316,\n        Death_04 = 0x317,\n        Fart = 0x318,\n        Gasp = 0x319,\n        Giggle = 0x31A,\n        Groan = 0x31B,\n        Growl = 0x31C,\n        Hey = 0x31D,\n        Hiccup = 0x31E,\n        Huh = 0x31F,\n        Kiss = 0x320,\n        Laugh = 0x321,\n        No = 0x322,\n        Oh = 0x323,\n        Oomph_01 = 0x324,\n        Oomph_02 = 0x325,\n        Oomph_03 = 0x326,\n        Oomph_04 = 0x327,\n        Oomph_05 = 0x328,\n        Oomph_06 = 0x329,\n        Oomph_07 = 0x32A,\n        Oooh = 0x32B,\n        Oops = 0x32C,\n        Puke = 0x32D,\n        Scream = 0x32E,\n        Shush = 0x32F,\n        Sigh = 0x330,\n        Sneeze = 0x331,\n        Sniff = 0x332,\n        Snore = 0x333,\n        Spit = 0x334,\n        Whistle = 0x335,\n        Yawn = 0x336,\n        Yea = 0x337,\n        Yell = 0x338\n    }\n\n    public class PlayerData : Mobile\n    {\n        public int VisRange = 18;\n\n        public int MultiVisRange\n        {\n            get { return VisRange + 5; }\n        }\n\n        private int _maxWeight = -1;\n\n        private short _fireResist, _coldResist, _poisonResist, _energyResist, _luck;\n        private ushort _damageMin, _damageMax;\n\n        private ushort _str, _dex, _int;\n        private LockType _strLock, _dexLock, _intLock;\n        private uint _gold;\n        private ushort _weight;\n        private Skill[] _skills;\n        private ushort _ar;\n        private ushort _statCap;\n        private byte _followers;\n        private byte _followersMax;\n        private int _tithe;\n        private sbyte _localLight;\n        private byte _globalLight;\n        private uint _features;\n        private byte _season;\n        private byte _defaultSeason;\n        private int[] _papPatches = new int[10];\n\n\n        private bool _skillsSent;\n        private Timer _criminalTime;\n        private DateTime _criminalStart = DateTime.MinValue;\n\n        private List<BuffDebuff> _buffsDebuffs = new List<BuffDebuff>();\n\n        internal List<BuffDebuff> BuffsDebuffs\n        {\n            get { return _buffsDebuffs; }\n        }\n\n        private List<uint> _openedCorpses = new List<uint>();\n\n        public List<uint> OpenedCorpses\n        {\n            get { return _openedCorpses; }\n        }\n\n        public PlayerData(Serial serial) : base(serial)\n        {\n            _skills = new Skill[Ultima.Skills.TotalSkills()];\n            for (int i = 0; i < _skills.Length; i++)\n                _skills[i] = new Skill(i);\n        }\n\n        public ushort Str\n        {\n            get { return _str; }\n            set { _str = value; }\n        }\n\n        public ushort Dex\n        {\n            get { return _dex; }\n            set { _dex = value; }\n        }\n\n        public ushort Int\n        {\n            get { return _int; }\n            set { _int = value; }\n        }\n\n        public uint Gold\n        {\n            get { return _gold; }\n            set { _gold = value; }\n        }\n\n        public ushort Weight\n        {\n            get { return _weight; }\n            set { _weight = value; }\n        }\n\n        public ushort MaxWeight\n        {\n            get\n            {\n                if (_maxWeight == -1)\n                    return (ushort) ((_str * 3.5) + 40);\n                else\n                    return (ushort) _maxWeight;\n            }\n            set { _maxWeight = value; }\n        }\n\n        public short FireResistance\n        {\n            get { return _fireResist; }\n            set { _fireResist = value; }\n        }\n\n        public short ColdResistance\n        {\n            get { return _coldResist; }\n            set { _coldResist = value; }\n        }\n\n        public short PoisonResistance\n        {\n            get { return _poisonResist; }\n            set { _poisonResist = value; }\n        }\n\n        public short EnergyResistance\n        {\n            get { return _energyResist; }\n            set { _energyResist = value; }\n        }\n\n        public short Luck\n        {\n            get { return _luck; }\n            set { _luck = value; }\n        }\n\n        public ushort DamageMin\n        {\n            get { return _damageMin; }\n            set { _damageMin = value; }\n        }\n\n        public ushort DamageMax\n        {\n            get { return _damageMax; }\n            set { _damageMax = value; }\n        }\n\n        public LockType StrLock\n        {\n            get { return _strLock; }\n            set { _strLock = value; }\n        }\n\n        public LockType DexLock\n        {\n            get { return _dexLock; }\n            set { _dexLock = value; }\n        }\n\n        public LockType IntLock\n        {\n            get { return _intLock; }\n            set { _intLock = value; }\n        }\n\n        public ushort StatCap\n        {\n            get { return _statCap; }\n            set { _statCap = value; }\n        }\n\n        public ushort AR\n        {\n            get { return _ar; }\n            set { _ar = value; }\n        }\n\n        public byte Followers\n        {\n            get { return _followers; }\n            set { _followers = value; }\n        }\n\n        public byte FollowersMax\n        {\n            get { return _followersMax; }\n            set { _followersMax = value; }\n        }\n\n        public int Tithe\n        {\n            get { return _tithe; }\n            set { _tithe = value; }\n        }\n\n        public Skill[] Skills\n        {\n            get { return _skills; }\n        }\n\n        public bool SkillsSent\n        {\n            get { return _skillsSent; }\n            set { _skillsSent = value; }\n        }\n\n        public int CriminalTime\n        {\n            get\n            {\n                if (_criminalStart != DateTime.MinValue)\n                {\n                    int sec = (int) (DateTime.UtcNow - _criminalStart).TotalSeconds;\n                    if (sec > 300)\n                    {\n                        if (_criminalTime != null)\n                            _criminalTime.Stop();\n                        _criminalStart = DateTime.MinValue;\n                        return 0;\n                    }\n                    else\n                    {\n                        return sec;\n                    }\n                }\n                else\n                {\n                    return 0;\n                }\n            }\n        }\n\n        private class DoorOpenTimer : Timer\n        {\n            // Fire off once in 5ms\n            public DoorOpenTimer() : base(TimeSpan.FromMilliseconds(5), 1)\n            {\n            }\n\n            protected override void OnTick()\n            {\n                Client.Instance.SendToServer(new OpenDoorMacro());\n            }\n        }\n\n        private readonly DoorOpenTimer _doorTimer = new DoorOpenTimer();\n\n        private void AutoOpenDoors(bool onDirChange)\n        {\n            if (!Visible && !Config.GetBool(\"AutoOpenDoorWhenHidden\"))\n                return;\n\n            if (Body != 0x03DB && !IsGhost && ((int) (Direction & Direction.Mask)) % 2 == 0 &&\n                Config.GetBool(\"AutoOpenDoors\") &&\n                Client.Instance.AllowBit(FeatureBit.AutoOpenDoors))\n            {\n                int x = Position.X, y = Position.Y, z = Position.Z;\n\n                /* Check if one more tile in the direction we just moved is a door */\n                Utility.Offset(Direction, ref x, ref y);\n\n                if (World.Items.Values.Any(s =>\n                    s.IsDoor && s.Position.X == x && s.Position.Y == y && s.Position.Z - 15 <= z &&\n                    s.Position.Z + 15 >= z))\n                {\n                    if (Client.IsOSI)\n                    {\n                        Client.Instance.SendToServer(new OpenDoorMacro());\n                    }\n                    else\n                    {\n                        // ClassicUO requires a slight pause before attempting to\n                        // open a door after a direction change\n                        if (onDirChange)\n                        {\n                            _doorTimer.Start();\n                        }\n                        else\n                        {\n                            Client.Instance.SendToServer(new OpenDoorMacro());\n                        }\n                    }\n                }\n            }\n        }\n\n        public override void OnPositionChanging(Point3D oldPos)\n        {\n            if (!IsGhost)\n                StealthSteps.OnMove();\n\n            AutoOpenDoors(false);\n\n            List<Mobile> mlist = new List<Mobile>(World.Mobiles.Values);\n            for (int i = 0; i < mlist.Count; i++)\n            {\n                Mobile m = mlist[i];\n                if (m != this)\n                {\n                    if (!Utility.InRange(m.Position, Position, VisRange))\n                        m.Remove();\n                    else\n                        Targeting.CheckLastTargetRange(m);\n                }\n            }\n\n            mlist = null;\n\n\n            List<Item> ilist = new List<Item>(World.Items.Values);\n            ScavengerAgent s = ScavengerAgent.Instance;\n            for (int i = 0; i < ilist.Count; i++)\n            {\n                Item item = ilist[i];\n                if (item.Deleted || item.Container != null)\n                    continue;\n\n                int dist = Utility.Distance(item.GetWorldPosition(), Position);\n                if (item != DragDropManager.Holding && (dist > MultiVisRange || (!item.IsMulti && dist > VisRange)))\n                    item.Remove();\n                else if (!IsGhost && Visible && dist <= 2 && s.Enabled && item.Movable)\n                    s.Scavenge(item);\n            }\n\n            ilist = null;\n\n            if (Engine.MainWindow != null && Engine.MainWindow.MapWindow != null)\n                Engine.MainWindow.SafeAction(f => f.MapWindow.PlayerMoved());\n\n            base.OnPositionChanging(oldPos);\n        }\n\n        public override void OnDirectionChanging(Direction oldDir)\n        {\n            AutoOpenDoors(true);\n        }\n\n        public override void OnMapChange(byte old, byte cur)\n        {\n            List<Mobile> list = new List<Mobile>(World.Mobiles.Values);\n            for (int i = 0; i < list.Count; i++)\n            {\n                Mobile m = list[i];\n                if (m != this && m.Map != cur)\n                    m.Remove();\n            }\n\n            list = null;\n\n            World.Items.Clear();\n            Counter.Reset();\n            for (int i = 0; i < Contains.Count; i++)\n            {\n                Item item = (Item) Contains[i];\n                World.AddItem(item);\n                item.Contains.Clear();\n            }\n\n            if (Config.GetBool(\"AutoSearch\") && Backpack != null)\n                PlayerData.DoubleClick(Backpack);\n\n            UOAssist.PostMapChange(cur);\n\n            if (Engine.MainWindow != null && Engine.MainWindow.MapWindow != null)\n                Engine.MainWindow.SafeAction(s => s.MapWindow.PlayerMoved());\n        }\n\n        /*public override void OnMapChange( byte old, byte cur )\n        {\n             World.Mobiles.Clear();\n             World.Items.Clear();\n             Counter.Reset();\n\n             Contains.Clear();\n\n             World.AddMobile( this );\n\n             UOAssist.PostMapChange( cur );\n        }*/\n\n        protected override void OnNotoChange(byte old, byte cur)\n        {\n            if ((old == 3 || old == 4) && (cur != 3 && cur != 4))\n            {\n                // grey is turning off\n                // SendMessage( \"You are no longer a criminal.\" );\n                if (_criminalTime != null)\n                    _criminalTime.Stop();\n                _criminalStart = DateTime.MinValue;\n                Client.Instance.RequestTitlebarUpdate();\n            }\n            else if ((cur == 3 || cur == 4) && (old != 3 && old != 4 && old != 0))\n            {\n                // grey is turning on\n                ResetCriminalTimer();\n            }\n        }\n\n        public void ResetCriminalTimer()\n        {\n            if (_criminalStart == DateTime.MinValue || DateTime.UtcNow - _criminalStart >= TimeSpan.FromSeconds(1))\n            {\n                _criminalStart = DateTime.UtcNow;\n                if (_criminalTime == null)\n                    _criminalTime = new CriminalTimer(this);\n                _criminalTime.Start();\n                Client.Instance.RequestTitlebarUpdate();\n            }\n        }\n\n        private class CriminalTimer : Timer\n        {\n            private PlayerData _player;\n\n            public CriminalTimer(PlayerData player) : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n                _player = player;\n            }\n\n            protected override void OnTick()\n            {\n                Client.Instance.RequestTitlebarUpdate();\n            }\n        }\n\n        internal void SendMessage(MsgLevel lvl, LocString loc, params object[] args)\n        {\n            SendMessage(lvl, Language.Format(loc, args));\n        }\n\n        internal void SendMessage(MsgLevel lvl, LocString loc)\n        {\n            SendMessage(lvl, Language.GetString(loc));\n        }\n\n        internal void SendMessage(LocString loc, params object[] args)\n        {\n            SendMessage(MsgLevel.Info, Language.Format(loc, args));\n        }\n\n        internal void SendMessage(LocString loc)\n        {\n            SendMessage(MsgLevel.Info, Language.GetString(loc));\n        }\n\n        internal void SendMessage(int hue, string text)\n        {\n            Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, hue, 3,\n                Language.CliLocName, \"System\", text));\n        }\n\n        internal void SendMessage(MsgLevel lvl, string format, params object[] args)\n        {\n            SendMessage(lvl, String.Format(format, args));\n        }\n\n        internal void SendMessage(string format, params object[] args)\n        {\n            SendMessage(MsgLevel.Info, String.Format(format, args));\n        }\n\n        internal void SendMessage(string text)\n        {\n            SendMessage(MsgLevel.Info, text);\n        }\n\n        internal void SendMessage(MsgLevel lvl, string text)\n        {\n            if (lvl >= (MsgLevel) Config.GetInt(\"MessageLevel\") && text.Length > 0)\n            {\n                int hue;\n                switch (lvl)\n                {\n                    case MsgLevel.Error:\n                    case MsgLevel.Warning:\n                        hue = Config.GetInt(\"WarningColor\");\n                        break;\n                    case MsgLevel.Friend:\n                        hue = 63;\n                        break;\n                    default:\n                        hue = Config.GetInt(\"SysColor\");\n                        break;\n                }\n\n                SystemMessages.Add(text);\n\n                if (Config.GetBool(\"FilterRazorMessages\"))\n                {\n                    if (!MessageQueue.Enqueue(0xFFFFFFFF, null, 0, MessageType.Regular, (ushort) hue, 3,\n                        Language.CliLocName, \"System\", text))\n                    {\n                        return;\n                    }\n                }\n\n                Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, hue, 3,\n                    Language.CliLocName, \"System\", text));\n            }\n        }\n\n        internal void Say(int hue, string msg)\n        {\n            List<ushort> keywords = EncodedSpeech.GetKeywords(msg);\n\n            if (keywords.Count == 1 && (int) keywords[0] == 0)\n            {\n                Client.Instance.SendToServer(new ClientUniEncodedCommandMessage(MessageType.Regular, hue, 3,\n                    Language.CliLocName, keywords, msg));\n            }\n            else\n            {\n                Client.Instance.SendToServer(new ClientUniEncodedCommandMessage(MessageType.Encoded, hue, 3,\n                    Language.CliLocName, keywords, msg));\n            }\n        }\n\n        internal void Say(string msg)\n        {\n            Say(Config.GetInt(\"SpeechHue\"), msg);\n        }\n\n        internal void Whisper(string msg, int hue)\n        {\n            Client.Instance.SendToServer(new ClientUniMessage(MessageType.Whisper, hue, 3,\n                Language.CliLocName, new ArrayList(), msg));\n        }\n\n        internal void Yell(string msg, int hue)\n        {\n            Client.Instance.SendToServer(new ClientUniMessage(MessageType.Yell, hue, 3,\n                Language.CliLocName, new ArrayList(), msg));\n        }\n\n        internal void Emote(string msg, int hue)\n        {\n            msg = $\"*{msg}*\";\n\n            Client.Instance.SendToServer(new ClientUniMessage(MessageType.Emote, hue, 3,\n                Language.CliLocName, new ArrayList(), msg));\n        }\n\n        internal void Guild(string msg, int hue)\n        {\n            Client.Instance.SendToServer(new ClientUniMessage(MessageType.Guild, hue, 3,\n                Language.CliLocName, new ArrayList(), msg));\n        }\n\n        internal void Alliance(string msg, int hue)\n        {\n            Client.Instance.SendToServer(new ClientUniMessage(MessageType.Alliance, hue, 3,\n                Language.CliLocName, new ArrayList(), msg));\n        }\n\n        public uint CurrentGumpS, CurrentGumpI;\n        public GumpResponseAction LastGumpResponseAction;\n        public bool HasGump;\n        public bool HasCompressedGump;\n        public List<string> CurrentGumpStrings = new List<string>(); \n        public string CurrentGumpRawData;\n        public uint CurrentMenuS;\n        public ushort CurrentMenuI;\n        public bool HasMenu;\n\n        public bool HasPrompt;\n        public uint PromptSenderSerial;\n        public uint PromptID;\n        public uint PromptType;\n        public string PromptInputText;\n\n        public Dictionary<uint, GumpInfo> GumpList { get; set; } = new Dictionary<uint, GumpInfo>();\n\n        public class GumpInfo\n        {\n            private uint _serial;\n            private uint _gumpId;\n            List<string> _gumpContext;\n\n            public uint GumpSerial\n            {\n                set => _serial = value;\n                get => _serial;\n            }\n\n            public uint GumpId\n            {\n                set => _gumpId = value;\n                get => _gumpId;\n            }\n\n            public List<string> GumpContext\n            {\n                set => _gumpContext = value;\n                get => _gumpContext;\n            }\n\n            public GumpInfo(uint serial, uint gumpId, List<string> gumpContext)\n            {\n                _serial = serial;\n                _gumpId = gumpId;\n                _gumpContext = gumpContext;\n            }\n\n            public GumpInfo(uint serial, uint gumpId)\n            {\n                _serial = serial;\n                _gumpId = gumpId;\n            }\n        }\n\n        public GumpCollection InternalGumps { get; set; } = new GumpCollection();\n\n        public void CancelPrompt()\n        {\n            Client.Instance.SendToServer(new PromptResponse(World.Player.PromptSenderSerial, World.Player.PromptID, 0,\n                Language.CliLocName, string.Empty));\n            World.Player.HasPrompt = false;\n        }\n\n        public void ResponsePrompt(string text)\n        {\n            Client.Instance.SendToServer(new PromptResponse(World.Player.PromptSenderSerial, World.Player.PromptID, 1,\n                Language.CliLocName, text));\n\n            PromptInputText = text;\n            World.Player.HasPrompt = false;\n        }\n\n        private ushort _speechHue;\n\n        public ushort SpeechHue\n        {\n            get { return _speechHue; }\n            set { _speechHue = value; }\n        }\n\n        public sbyte LocalLightLevel\n        {\n            get { return _localLight; }\n            set { _localLight = value; }\n        }\n\n        public byte GlobalLightLevel\n        {\n            get { return _globalLight; }\n            set { _globalLight = value; }\n        }\n\n        public enum SeasonFlag\n        {\n            Spring,\n            Summer,\n            Fall,\n            Winter,\n            Desolation\n        }\n\n        public byte Season\n        {\n            get { return _season; }\n            set { _season = value; }\n        }\n\n        public byte DefaultSeason\n        {\n            get { return _defaultSeason; }\n            set { _defaultSeason = value; }\n        }\n\n        /// <summary>\n        /// Sets the player's season, set a default to revert back if required\n        /// </summary>\n        /// <param name=\"defaultSeason\"></param>\n        public void SetSeason(byte defaultSeason = 0)\n        {\n            if (Config.GetInt(\"Season\") < 5)\n            {\n                byte season = (byte) Config.GetInt(\"Season\");\n\n                World.Player.Season = season;\n                World.Player.DefaultSeason = defaultSeason;\n\n                if (!_seasonTimer.Running)\n                    _seasonTimer.Start();\n            }\n            else\n            {\n                World.Player.Season = defaultSeason;\n                World.Player.DefaultSeason = defaultSeason;\n            }\n        }\n\n        public static Timer _seasonTimer = new SeasonTimer();\n\n        private class SeasonTimer : Timer\n        {\n            public SeasonTimer() : base(TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                if (World.Player != null && Client.Instance != null)\n                {\n                    Client.Instance.ForceSendToClient(new SeasonChange(World.Player.Season, true));\n                    _seasonTimer.Stop();\n                }\n            }\n        }\n\n        public uint Features\n        {\n            get { return _features; }\n            set { _features = value; }\n        }\n\n        public int[] MapPatches\n        {\n            get { return _papPatches; }\n            set { _papPatches = value; }\n        }\n\n        private int _lstSkill = -1;\n\n        public int LastSkill\n        {\n            get { return _lstSkill; }\n            set { _lstSkill = value; }\n        }\n\n        private Serial _lastObj = Serial.Zero;\n\n        public Serial LastObject\n        {\n            get { return _lastObj; }\n            set { _lastObj = value; }\n        }\n\n        private int _lastSpell = -1;\n\n        public int LastSpell\n        {\n            get { return _lastSpell; }\n            set { _lastSpell = value; }\n        }\n\n        public bool UseItem(Item cont, ushort find)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.PotionHotkeys))\n                return false;\n\n            for (int i = 0; i < cont.Contains.Count; i++)\n            {\n                Item item = (Item)cont.Contains[i];\n\n                if (item.ItemID == find)\n                {\n                    DoubleClick(item);\n                    return true;\n                }\n\n                if (item.Contains != null && item.Contains.Count > 0)\n                {\n                    if (UseItem(item, find))\n                        return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static bool DoubleClick(object clicked)\n        {\n            return DoubleClick(clicked, true);\n        }\n\n        public static bool DoubleClick(object clicked, bool silent)\n        {\n            Serial s;\n            if (clicked is Mobile)\n                s = ((Mobile) clicked).Serial.Value;\n            else if (clicked is Item)\n                s = ((Item) clicked).Serial.Value;\n            else if (clicked is Serial)\n                s = ((Serial) clicked).Value;\n            else\n                s = Serial.Zero;\n\n            if (s != Serial.Zero)\n            {\n                Item free = null, pack = World.Player.Backpack;\n                if (s.IsItem && pack != null && Config.GetBool(\"PotionEquip\") &&\n                    Client.Instance.AllowBit(FeatureBit.AutoPotionEquip))\n                {\n                    Item i = World.FindItem(s);\n                    if (i != null && i.IsPotion && i.ItemID != 3853) // dont unequip for exploison potions\n                    {\n                        // dont worry about uneqipping RuneBooks or SpellBooks\n                        Item left = World.Player.GetItemOnLayer(Layer.LeftHand);\n                        Item right = World.Player.GetItemOnLayer(Layer.RightHand);\n\n                        if (left != null && (right != null || left.IsTwoHanded))\n                            free = left;\n                        else if (right != null && right.IsTwoHanded)\n                            free = right;\n\n                        if (free != null)\n                        {\n                            if (DragDropManager.HasDragFor(free.Serial))\n                                free = null;\n                            else\n                                DragDropManager.DragDrop(free, pack);\n                        }\n                    }\n                }\n\n                ActionQueue.DoubleClick(silent, s);\n\n                if (free != null && Config.GetBool(\"PotionReequip\"))\n                    DragDropManager.DragDrop(free, World.Player, free.Layer, true);\n\n                if (s.IsItem)\n                    World.Player._lastObj = s;\n            }\n\n            return false;\n        }\n\n        public enum InvokeVirtues\n        {\n            Honor = 0x01,\n            Sacrifice = 0x02,\n            Valor = 0x03\n        }\n\n        public static void InvokeVirtue(InvokeVirtues virtue)\n        {\n            Client.Instance.SendToServer(new VirtueRequest((byte) virtue));\n        }\n\n        public static void RenameMobile(Serial serial, string newName)\n        {\n            Client.Instance.SendToServer(new RenamePacket(serial.Value, newName));\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/ScreenCapture.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Windows.Forms;\r\nusing System.Drawing;\r\nusing System.Drawing.Imaging;\r\nusing System.Runtime.InteropServices;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant\r\n{\r\n    public class ScreenCapManager\r\n    {\r\n        [System.Runtime.InteropServices.DllImport(\"Gdi32.dll\")]\r\n        private static extern IntPtr DeleteObject(IntPtr hGdiObj);\r\n\r\n        private static TimerCallback m_DoCaptureCall = new TimerCallback(CaptureNow);\r\n\r\n        public static string LastMobileDeathName { get; set; }\r\n\r\n        public static void Initialize()\r\n        {\r\n            HotKey.Add(HKCategory.Misc, LocString.TakeSS, new HotKeyCallback(CaptureNow));\r\n        }\r\n\r\n        public static void DeathCapture(double delay)\r\n        {\r\n            Timer.DelayedCallback(TimeSpan.FromSeconds(delay), m_DoCaptureCall).Start();\r\n        }\r\n\r\n        public static void CaptureNow()\r\n        {\r\n            string filename;\r\n            string playerName = \"Unknown\";\r\n            string path = Config.GetString(\"CapPath\");\r\n            string type = Config.GetString(\"ImageFormat\").ToLower();\r\n\r\n            if (World.Player != null)\r\n                playerName = World.Player.Name;\r\n\r\n            if (playerName == null || playerName.Trim() == \"\" ||\r\n                playerName.IndexOfAny(Path.GetInvalidPathChars()) != -1)\r\n                playerName = \"Unknown\";\r\n\r\n            if (LastMobileDeathName == null || LastMobileDeathName.Trim() == \"\" ||\r\n                LastMobileDeathName.IndexOfAny(Path.GetInvalidPathChars()) != -1)\r\n                LastMobileDeathName = \"Unknown\";\r\n\r\n            string imageTimestampTag = Config.GetBool(\"CapTimeStamp\")\r\n                ? $\"{playerName} ({World.ShardName}) - {Engine.MistedDateTime:M/dd/yy - HH:mm:ss}\"\r\n                : \"\";\r\n\r\n            playerName = !string.IsNullOrEmpty(LastMobileDeathName)\r\n                ? $\"{playerName}_{LastMobileDeathName}_{Engine.MistedDateTime:M-d_HH.mm}\"\r\n                : $\"{playerName}_{Engine.MistedDateTime:M-d_HH.mm}\";\r\n\r\n            try\r\n            {\r\n                Engine.EnsureDirectory(path);\r\n            }\r\n            catch\r\n            {\r\n                try\r\n                {\r\n                    path = Config.GetUserDirectory(\"ScreenShots\");\r\n                    Config.SetProperty(\"CapPath\", path);\r\n                }\r\n                catch\r\n                {\r\n                    path = \"\";\r\n                }\r\n            }\r\n\r\n            int count = 0;\r\n            do\r\n            {\r\n                filename = Path.Combine(path,\r\n                    $\"{playerName}{(count != 0 ? count.ToString() : \"\")}.{type}\");\r\n                count--; // cause a - to be put in front of the number\r\n            } while (File.Exists(filename));\r\n\r\n            try\r\n            {\r\n                IntPtr hBmp = Platform.CaptureScreen(Client.Instance.GetWindowHandle(), Config.GetBool(\"CapFullScreen\"),\r\n                    imageTimestampTag);\r\n                using (Image img = Image.FromHbitmap(hBmp))\r\n                    img.Save(filename, GetFormat(type));\r\n                DeleteObject(hBmp);\r\n            }\r\n            catch\r\n            {\r\n                // ignored\r\n            }\r\n\r\n            LastMobileDeathName = string.Empty;\r\n\r\n            Engine.MainWindow.SafeAction(s => s.ReloadScreenShotsList());\r\n        }\r\n\r\n        private static ImageFormat GetFormat(string fmt)\r\n        {\r\n            //string fmt = Config.GetString( \"ImageFormat\" ).ToLower();\r\n            if (fmt == \"jpeg\" || fmt == \"jpg\")\r\n                return ImageFormat.Jpeg;\r\n            else if (fmt == \"png\")\r\n                return ImageFormat.Png;\r\n            else if (fmt == \"bmp\")\r\n                return ImageFormat.Bmp;\r\n            else if (fmt == \"gif\")\r\n                return ImageFormat.Gif;\r\n            else if (fmt == \"tiff\" || fmt == \"tif\")\r\n                return ImageFormat.Tiff;\r\n            else if (fmt == \"wmf\")\r\n                return ImageFormat.Wmf;\r\n            else if (fmt == \"exif\")\r\n                return ImageFormat.Exif;\r\n            else if (fmt == \"emf\")\r\n                return ImageFormat.Emf;\r\n            else\r\n                return ImageFormat.Jpeg;\r\n        }\r\n\r\n        public static void DisplayTo(ListBox list)\r\n        {\r\n            string path = Config.GetString(\"CapPath\");\r\n            Engine.EnsureDirectory(path);\r\n\r\n            //list.BeginUpdate();\r\n            list.Items.Clear();\r\n\r\n            AddFiles(list, path, \"jpeg\");\r\n            AddFiles(list, path, \"jpg\");\r\n            AddFiles(list, path, \"png\");\r\n            AddFiles(list, path, \"bmp\");\r\n            AddFiles(list, path, \"gif\");\r\n            AddFiles(list, path, \"tiff\");\r\n            AddFiles(list, path, \"tif\");\r\n            AddFiles(list, path, \"wmf\");\r\n            AddFiles(list, path, \"exif\");\r\n            AddFiles(list, path, \"emf\");\r\n            //list.EndUpdate();\r\n        }\r\n\r\n        public static void AddFiles(ListBox list, string path, string ext)\r\n        {\r\n            if (list.Items.Count >= 500)\r\n                return;\r\n\r\n            string[] files = Directory.GetFiles(path, $\"*.{ext}\");\r\n            for (int i = 0; i < files.Length && list.Items.Count < 500; i++)\r\n                list.Items.Add(Path.GetFileName(files[i]));\r\n        }\r\n\r\n\r\n        public static Image CaptureWindow(IntPtr handle)\r\n        {\r\n            // get te hDC of the target window\r\n            IntPtr hdcSrc = User32.GetWindowDC(handle);\r\n            // get the size\r\n            User32.RECT windowRect = new User32.RECT();\r\n            User32.GetWindowRect(handle, ref windowRect);\r\n            int width = windowRect.right - windowRect.left;\r\n            int height = windowRect.bottom - windowRect.top;\r\n            // create a device context we can copy to\r\n            IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);\r\n            // create a bitmap we can copy it to,\r\n            // using GetDeviceCaps to get the width/height\r\n            IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);\r\n            // select the bitmap object\r\n            IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);\r\n            // bitblt over\r\n            GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);\r\n            // restore selection\r\n            GDI32.SelectObject(hdcDest, hOld);\r\n            // clean up\r\n            GDI32.DeleteDC(hdcDest);\r\n            User32.ReleaseDC(handle, hdcSrc);\r\n            // get a .NET image object for it\r\n            Image img = Image.FromHbitmap(hBitmap);\r\n            // free up the Bitmap object\r\n            GDI32.DeleteObject(hBitmap);\r\n            return img;\r\n        }\r\n\r\n        /// <summary>\r\n        /// Captures a screen shot of a specific window, and saves it to a file\r\n        /// </summary>\r\n        /// <param name=\"handle\"></param>\r\n        /// <param name=\"filename\"></param>\r\n        /// <param name=\"format\"></param>\r\n        public static void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)\r\n        {\r\n            Image img = CaptureWindow(handle);\r\n            img.Save(filename, format);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Captures a screen shot of the entire desktop, and saves it to a file\r\n        /// </summary>\r\n        /// <param name=\"filename\"></param>\r\n        /// <param name=\"format\"></param>\r\n        public static void CaptureScreenToFile(string filename, ImageFormat format)\r\n        {\r\n            Image img = CaptureScreen();\r\n            img.Save(filename, format);\r\n        }\r\n\r\n        public static Image CaptureScreen()\r\n        {\r\n            return CaptureWindow(User32.GetDesktopWindow());\r\n        }\r\n\r\n        /// <summary>\r\n        /// Helper class containing Gdi32 API functions\r\n        /// </summary>\r\n        private class GDI32\r\n        {\r\n            public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter\r\n\r\n            [DllImport(\"gdi32.dll\")]\r\n            public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,\r\n                int nWidth, int nHeight, IntPtr hObjectSource,\r\n                int nXSrc, int nYSrc, int dwRop);\r\n\r\n            [DllImport(\"gdi32.dll\")]\r\n            public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,\r\n                int nHeight);\r\n\r\n            [DllImport(\"gdi32.dll\")]\r\n            public static extern IntPtr CreateCompatibleDC(IntPtr hDC);\r\n\r\n            [DllImport(\"gdi32.dll\")]\r\n            public static extern bool DeleteDC(IntPtr hDC);\r\n\r\n            [DllImport(\"gdi32.dll\")]\r\n            public static extern bool DeleteObject(IntPtr hObject);\r\n\r\n            [DllImport(\"gdi32.dll\")]\r\n            public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Helper class containing User32 API functions\r\n        /// </summary>\r\n        private class User32\r\n        {\r\n            [StructLayout(LayoutKind.Sequential)]\r\n            public struct RECT\r\n            {\r\n                public int left;\r\n                public int top;\r\n                public int right;\r\n                public int bottom;\r\n            }\r\n\r\n            [DllImport(\"user32.dll\")]\r\n            public static extern IntPtr GetDesktopWindow();\r\n\r\n            [DllImport(\"user32.dll\")]\r\n            public static extern IntPtr GetWindowDC(IntPtr hWnd);\r\n\r\n            [DllImport(\"user32.dll\")]\r\n            public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);\r\n\r\n            [DllImport(\"user32.dll\")]\r\n            public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/Serial.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\n\r\nnamespace Assistant\r\n{\r\n    public struct Serial : IComparable\r\n    {\r\n        private uint m_Serial;\r\n        public static List<Serial> Serials { get; set; }\r\n\r\n        public static readonly Serial MinusOne = new Serial(0xFFFFFFFF);\r\n        public static readonly Serial Zero = new Serial(0);\r\n\r\n        private Serial(uint serial)\r\n        {\r\n            m_Serial = serial;\r\n        }\r\n\r\n        public uint Value\r\n        {\r\n            get { return m_Serial; }\r\n        }\r\n\r\n        public bool IsMobile\r\n        {\r\n            get { return (m_Serial > 0 && m_Serial < 0x40000000); }\r\n        }\r\n\r\n        public bool IsItem\r\n        {\r\n            get { return (m_Serial >= 0x40000000 && m_Serial <= 0x7FFFFF00); }\r\n        }\r\n\r\n        public bool IsValid\r\n        {\r\n            get { return (m_Serial > 0 && m_Serial <= 0x7FFFFF00); }\r\n        }\r\n\r\n        public override int GetHashCode()\r\n        {\r\n            return (int) m_Serial;\r\n        }\r\n\r\n        public int CompareTo(object o)\r\n        {\r\n            if (o == null) return 1;\r\n            else if (!(o is Serial)) throw new ArgumentException();\r\n\r\n            uint ser = ((Serial) o).m_Serial;\r\n\r\n            if (m_Serial > ser) return 1;\r\n            else if (m_Serial < ser) return -1;\r\n            else return 0;\r\n        }\r\n\r\n        public override bool Equals(object o)\r\n        {\r\n            if (o == null || !(o is Serial)) return false;\r\n\r\n            return ((Serial) o).m_Serial == m_Serial;\r\n        }\r\n\r\n        public static bool operator ==(Serial l, Serial r)\r\n        {\r\n            return l.m_Serial == r.m_Serial;\r\n        }\r\n\r\n        public static bool operator !=(Serial l, Serial r)\r\n        {\r\n            return l.m_Serial != r.m_Serial;\r\n        }\r\n\r\n        public static bool operator >(Serial l, Serial r)\r\n        {\r\n            return l.m_Serial > r.m_Serial;\r\n        }\r\n\r\n        public static bool operator <(Serial l, Serial r)\r\n        {\r\n            return l.m_Serial < r.m_Serial;\r\n        }\r\n\r\n        public static bool operator >=(Serial l, Serial r)\r\n        {\r\n            return l.m_Serial >= r.m_Serial;\r\n        }\r\n\r\n        public static bool operator <=(Serial l, Serial r)\r\n        {\r\n            return l.m_Serial <= r.m_Serial;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"0x{m_Serial:X}\";\r\n        }\r\n\r\n        public static Serial Parse(string s)\r\n        {\r\n            if (s.StartsWith(\"0x\"))\r\n                return (Serial) Convert.ToUInt32(s.Substring(2), 16);\r\n            else\r\n                return (Serial) Convert.ToUInt32(s);\r\n        }\r\n\r\n        public static implicit operator uint(Serial a)\r\n        {\r\n            return a.m_Serial;\r\n        }\r\n\r\n        public static implicit operator int(Serial a)\r\n        {\r\n            return (int) a.m_Serial;\r\n        }\r\n\r\n        public static implicit operator Serial(uint a)\r\n        {\r\n            return new Serial(a);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/SkillTimer.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\n\nnamespace Assistant\n{\n    public class SkillTimer\n    {\n        private static int m_Count;\n        private static Timer m_Timer;\n\n        static SkillTimer()\n        {\n            m_Timer = new InternalTimer();\n        }\n\n        public static int Count\n        {\n            get { return m_Count; }\n        }\n\n        public static bool Running\n        {\n            get { return m_Timer.Running; }\n        }\n\n        public static void Start()\n        {\n            m_Count = 0;\n\n            if (m_Timer.Running)\n            {\n                m_Timer.Stop();\n            }\n\n            m_Timer.Start();\n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        public static void Stop()\n        {\n            m_Timer.Stop();\n            Client.Instance.RequestTitlebarUpdate();\n        }\n\n        private class InternalTimer : Timer\n        {\n            public InternalTimer() : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                m_Count++;\n                if (m_Count > 10)\n                {\n                    Stop();\n                }\n\n                Client.Instance.RequestTitlebarUpdate();\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/Spells.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.Windows.Forms;\r\nusing Assistant.Core;\r\n\r\nnamespace Assistant\r\n{\r\n    public class Spell\r\n    {\r\n        public enum SpellFlag\r\n        {\r\n            None = '?',\r\n            Beneficial = 'B',\r\n            Harmful = 'H',\r\n            Neutral = 'N'\r\n        }\r\n\r\n        public enum SpellKind\r\n        {\r\n            Magery,\r\n            Necromancy,\r\n            Chivalry,\r\n            Bushido,\r\n            Ninjutsu,\r\n            Spellweaving,\r\n            Mysticism,\r\n            Masteries,\r\n            Unknown\r\n        }\r\n\r\n        readonly public SpellFlag Flag;\r\n        readonly public int Circle;\r\n        readonly public int Number;\r\n        readonly public string WordsOfPower;\r\n        readonly public string[] Reagents;\r\n\r\n        private static Timer m_UnflagTimer;\r\n\r\n        public Spell(char flag, int n, int c, string power, string[] reags)\r\n        {\r\n            Flag = (SpellFlag) flag;\r\n            Number = n;\r\n            Circle = c;\r\n            WordsOfPower = power;\r\n            Reagents = reags;\r\n        }\r\n\r\n        public SpellKind Kind\r\n        {\r\n            get\r\n            {\r\n                switch(Circle)\r\n                {\r\n                    case int circle when circle <= 8:\r\n                        return SpellKind.Magery;\r\n                    case 10:\r\n                        return SpellKind.Necromancy;\r\n                    case 20:\r\n                        return SpellKind.Chivalry;\r\n                    case 40:\r\n                        return SpellKind.Bushido;\r\n                    case 50:\r\n                        return SpellKind.Ninjutsu;\r\n                    case 60:\r\n                        return SpellKind.Spellweaving;\r\n                    case 65:\r\n                        return SpellKind.Mysticism;\r\n                    case 70:\r\n                        return SpellKind.Masteries;\r\n                    default:\r\n                        return SpellKind.Unknown;\r\n                }\r\n            }\r\n        }\r\n\r\n        public bool NeedsChanneling\r\n        {\r\n            get\r\n            {\r\n                return (Kind == SpellKind.Magery || Kind == SpellKind.Mysticism);\r\n            }\r\n        }\r\n\r\n        public int Name\r\n        {\r\n            get\r\n            {\r\n                switch(Kind)\r\n                {\r\n                    case SpellKind.Magery:\r\n                        return 3002011 + ((Circle - 1) * 8) + (Number - 1);\r\n\r\n                    case SpellKind.Necromancy:\r\n                        return 1060509 + Number - 1;\r\n\r\n                    case SpellKind.Chivalry:\r\n                        return 1060585 + Number - 1;\r\n\r\n                    case SpellKind.Bushido:\r\n                        return 1060595 + Number - 1;\r\n\r\n                    case SpellKind.Ninjutsu:\r\n                        return 1060610 + Number - 1;\r\n\r\n                    case SpellKind.Spellweaving:\r\n                        return 1071026 + Number - 1;\r\n\r\n                    case SpellKind.Mysticism:\r\n                        return 1031678 + this.Number - 28;\r\n\r\n                    case SpellKind.Masteries:\r\n                    {\r\n                        if (Number <= 6)\r\n                            return 1115683 + Number - 1;\r\n\r\n                        return 1155896 + Number - 7;\r\n                    }\r\n\r\n                    default:\r\n                        return -1;\r\n\r\n                }\r\n            }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"{Language.GetString(this.Name)} (#{GetID()})\";\r\n        }\r\n\r\n        public string GetName()\r\n        {\r\n            return $\"{Language.GetString(Name)}\";\r\n        }\r\n\r\n        public int GetID()\r\n        {\r\n            return ToID(Circle, Number);\r\n        }\r\n\r\n        public int GetHue(int def)\r\n        {\r\n            if (Config.GetBool(\"ForceSpellHue\"))\r\n            {\r\n                switch (Flag)\r\n                {\r\n                    case SpellFlag.Beneficial:\r\n                        return Config.GetInt(\"BeneficialSpellHue\");\r\n                    case SpellFlag.Harmful:\r\n                        return Config.GetInt(\"HarmfulSpellHue\");\r\n                    case SpellFlag.Neutral:\r\n                        return Config.GetInt(\"NeutralSpellHue\");\r\n                    default:\r\n                        return def;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                return def;\r\n            }\r\n        }\r\n\r\n        public void OnCast(PacketReader p)\r\n        {\r\n            Cast();\r\n            Client.Instance.SendToServer(p);\r\n        }\r\n\r\n        public void OnCast(Packet p)\r\n        {\r\n            Cast();\r\n            Client.Instance.SendToServer(p);\r\n        }\r\n\r\n        private void Cast()\r\n        {\r\n            if (Config.GetBool(\"SpellUnequip\")\r\n                && Client.Instance.AllowBit(FeatureBit.UnequipBeforeCast)\r\n                && NeedsChanneling)\r\n            {\r\n                Item pack = World.Player.Backpack;\r\n                if (pack != null)\r\n                {\r\n                    // dont worry about uneqipping RuneBooks or SpellBooks\r\n                    Item item = World.Player.GetItemOnLayer(Layer.RightHand);\r\n#if DEBUG\r\n                    if (item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA &&\r\n                        !item.IsVirtueShield)\r\n#else\r\n\t\t\t\t\tif ( item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA )\r\n#endif\r\n                    {\r\n                        DragDropManager.Drag(item, item.Amount);\r\n                        DragDropManager.Drop(item, pack);\r\n                    }\r\n\r\n                    item = World.Player.GetItemOnLayer(Layer.LeftHand);\r\n#if DEBUG\r\n                    if (item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA &&\r\n                        !item.IsVirtueShield)\r\n#else\r\n\t\t\t\t\tif ( item != null && item.ItemID != 0x22C5 && item.ItemID != 0xE3B && item.ItemID != 0xEFA )\r\n#endif\r\n                    {\r\n                        DragDropManager.Drag(item, item.Amount);\r\n                        DragDropManager.Drop(item, pack);\r\n                    }\r\n                }\r\n            }\r\n\r\n            for (int i = 0; i < Counter.List.Count; i++)\r\n                ((Counter) Counter.List[i]).Flag = false;\r\n\r\n            if (Config.GetBool(\"HighlightReagents\"))\r\n            {\r\n                for (int r = 0; r < Reagents.Length; r++)\r\n                {\r\n                    for (int i = 0; i < Counter.List.Count; i++)\r\n                    {\r\n                        Counter c = (Counter) Counter.List[i];\r\n                        if (c.Enabled && c.Format.ToLower() == Reagents[r])\r\n                        {\r\n                            c.Flag = true;\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n\r\n                if (m_UnflagTimer != null)\r\n                    m_UnflagTimer.Stop();\r\n                else\r\n                    m_UnflagTimer = new UnflagTimer();\r\n                m_UnflagTimer.Start();\r\n            }\r\n\r\n            Client.Instance.RequestTitlebarUpdate();\r\n            UOAssist.PostSpellCast(this.Number);\r\n\r\n            if (World.Player != null)\r\n            {\r\n                World.Player.LastSpell = GetID();\r\n                LastCastTime = DateTime.UtcNow;\r\n                Targeting.SpellTargetID = 0;\r\n            }\r\n        }\r\n\r\n        public static DateTime LastCastTime = DateTime.MinValue;\r\n\r\n        private class UnflagTimer : Timer\r\n        {\r\n            public UnflagTimer() : base(TimeSpan.FromSeconds(30.0))\r\n            {\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                for (int i = 0; i < Counter.List.Count; i++)\r\n                    ((Counter) Counter.List[i]).Flag = false;\r\n                Client.Instance.RequestTitlebarUpdate();\r\n            }\r\n        }\r\n\r\n        private static Dictionary<string, Spell> m_SpellsByPower;\r\n        private static Dictionary<int, Spell> m_SpellsByID;\r\n        private static Dictionary<string, Spell> m_SpellsByName;\r\n        private static HotKeyCallbackState HotKeyCallback;\r\n\r\n        static Spell()\r\n        {\r\n            string filename = Path.Combine(Config.GetInstallDirectory(), \"spells.def\");\r\n            m_SpellsByPower = new Dictionary<string, Spell>(64 + 10 + 16);\r\n            m_SpellsByID = new Dictionary<int, Spell>(64 + 10 + 16);\r\n            m_SpellsByName = new Dictionary<string, Spell>(64 + 10 + 16);\r\n\r\n            if (!File.Exists(filename))\r\n            {\r\n                MessageBox.Show(Engine.ActiveWindow, Language.GetString(LocString.NoSpells), \"Spells.def\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            using (StreamReader reader = new StreamReader(filename))\r\n            {\r\n                string line;\r\n                while ((line = reader.ReadLine()) != null)\r\n                {\r\n                    line = line.Trim();\r\n                    if (line.Length <= 0 || line[0] == '#')\r\n                        continue;\r\n                    string[] split = line.Split('|');\r\n\r\n                    try\r\n                    {\r\n                        if (split.Length >= 5)\r\n                        {\r\n                            string[] reags = new string[split.Length - 5];\r\n                            for (int i = 5; i < split.Length; i++)\r\n                                reags[i - 5] = split[i].ToLower().Trim();\r\n                            Spell s = new Spell(split[0].Trim()[0], Convert.ToInt32(split[1].Trim()),\r\n                                Convert.ToInt32(split[2].Trim()), /*split[3].Trim(),*/ split[4].Trim(), reags);\r\n\r\n                            m_SpellsByID[s.GetID()] = s;\r\n\r\n                            line = Language.GetString(s.Name);\r\n                            if (string.IsNullOrEmpty(line))\r\n                                line = split[3].Trim();\r\n                            if (!string.IsNullOrEmpty(line))\r\n                                m_SpellsByName[line.ToLower()] = s;\r\n\r\n                            if (s.WordsOfPower != null && s.WordsOfPower.Trim().Length > 0)\r\n                                m_SpellsByPower[s.WordsOfPower] = s;\r\n                        }\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n            }\r\n\r\n            HotKeyCallback = new HotKeyCallbackState(OnHotKey);\r\n            foreach (Spell s in m_SpellsByID.Values)\r\n                HotKey.Add(HKCategory.Spells, HKSubCat.SpellOffset + s.Circle, s.Name, HotKeyCallback,\r\n                    (ushort) s.GetID());\r\n            HotKey.Add(HKCategory.Spells, LocString.HealOrCureSelf, new HotKeyCallback(HealOrCureSelf));\r\n            HotKey.Add(HKCategory.Spells, LocString.MiniHealOrCureSelf, new HotKeyCallback(MiniHealOrCureSelf));\r\n            HotKey.Add(HKCategory.Spells, LocString.GHealOrCureSelf, new HotKeyCallback(GHealOrCureSelf));\r\n            HotKey.Add(HKCategory.Spells, LocString.Interrupt, new HotKeyCallback(Interrupt));\r\n            \r\n            MessageManager.OnSpellMessage += HandleSpellMessage;\r\n        }\r\n        \r\n        private static StringBuilder SpellPowerwordsBuilder { get; set; } = new StringBuilder(Config.GetString(\"SpellFormat\"));\r\n        \r\n        private static void ResetSpellPowerwordsBuilder()\r\n        {\r\n            SpellPowerwordsBuilder.Remove(0, SpellPowerwordsBuilder.Length);\r\n            SpellPowerwordsBuilder.Insert(0, Config.GetString(\"SpellFormat\"));\r\n        }\r\n        \r\n        private static void HandleSpellMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\r\n            MessageType type, ushort hue, ushort font, string lang, string sourceName,\r\n            string text)\r\n        {\r\n            Spell s = Get(text.Trim());\r\n\r\n            if (Config.GetBool(\"OverrideSpellFormat\") && s != null)\r\n            {\r\n                ResetSpellPowerwordsBuilder();\r\n\r\n                StringBuilder sb = SpellPowerwordsBuilder;\r\n                sb.Replace(@\"{power}\", s.WordsOfPower);\r\n                string spell = Language.GetString(s.Name);\r\n                sb.Replace(@\"{spell}\", spell);\r\n                sb.Replace(@\"{name}\", spell);\r\n                sb.Replace(@\"{circle}\", s.Circle.ToString());\r\n\r\n                string newText = sb.ToString();\r\n\r\n                if (newText != null && newText != \"\" && newText != text)\r\n                {\r\n                    Client.Instance.SendToClient(new AsciiMessage(source, graphic, MessageType.Spell, s.GetHue(hue), font,\r\n                        sourceName, newText));\r\n\r\n                    args.Block = true;\r\n                    return;\r\n                }\r\n            }\r\n\r\n            if (Config.GetBool(\"ForceSpellHue\"))\r\n            {\r\n                p.Seek(10, SeekOrigin.Begin);\r\n                if (s != null)\r\n                    p.Write((ushort)s.GetHue(hue));\r\n                else\r\n                    p.Write((ushort)Config.GetInt(\"NeutralSpellHue\"));\r\n            }\r\n        }\r\n\r\n        public static void HealOrCureSelf()\r\n        {\r\n            Spell s = null;\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n            {\r\n                if (World.Player.Hits + 30 < World.Player.HitsMax && World.Player.Mana >= 12)\r\n                    s = Get(4, 5); // greater heal\r\n                else\r\n                    s = Get(1, 4); // mini heal\r\n            }\r\n            else\r\n            {\r\n                if (World.Player.Poisoned && Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n                {\r\n                    s = Get(2, 3); // cure\r\n                }\r\n                else if (World.Player.Hits + 2 < World.Player.HitsMax)\r\n                {\r\n                    if (World.Player.Hits + 30 < World.Player.HitsMax && World.Player.Mana >= 12)\r\n                        s = Get(4, 5); // greater heal\r\n                    else\r\n                        s = Get(1, 4); // mini heal\r\n                }\r\n                else\r\n                {\r\n                    if (World.Player.Mana >= 12)\r\n                        s = Get(4, 5); // greater heal\r\n                    else\r\n                        s = Get(1, 4); // mini heal\r\n                }\r\n            }\r\n\r\n            if (s != null)\r\n            {\r\n                if (World.Player.Poisoned || World.Player.Hits < World.Player.HitsMax)\r\n                    Targeting.TargetSelf(true);\r\n                Client.Instance.SendToServer(new CastSpellFromMacro((ushort) s.GetID()));\r\n                s.Cast();\r\n            }\r\n        }\r\n\r\n        public static void MiniHealOrCureSelf()\r\n        {\r\n            Spell s = null;\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n            {\r\n                s = Get(1, 4); // mini heal\r\n            }\r\n            else\r\n            {\r\n                if (World.Player.Poisoned)\r\n                    s = Get(2, 3); // cure\r\n                else\r\n                    s = Get(1, 4); // mini heal\r\n            }\r\n\r\n            if (s != null)\r\n            {\r\n                if (World.Player.Poisoned || World.Player.Hits < World.Player.HitsMax)\r\n                    Targeting.TargetSelf(true);\r\n                Client.Instance.SendToServer(new CastSpellFromMacro((ushort) s.GetID()));\r\n                s.Cast();\r\n            }\r\n        }\r\n\r\n        public static void GHealOrCureSelf()\r\n        {\r\n            Spell s = null;\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n            {\r\n                s = Get(4, 5); // gheal\r\n            }\r\n            else\r\n            {\r\n                if (World.Player.Poisoned)\r\n                    s = Get(2, 3); // cure\r\n                else\r\n                    s = Get(4, 5); // gheal\r\n            }\r\n\r\n            if (s != null)\r\n            {\r\n                if (World.Player.Poisoned || World.Player.Hits < World.Player.HitsMax)\r\n                    Targeting.TargetSelf(true);\r\n                Client.Instance.SendToServer(new CastSpellFromMacro((ushort) s.GetID()));\r\n                s.Cast();\r\n            }\r\n        }\r\n        \r\n        public static void Interrupt(Layer layer)\r\n        {\r\n            Item item = World.Player.GetItemOnLayer(layer);\r\n\r\n            if (item != null)\r\n            {\r\n                Client.Instance.SendToServer(new LiftRequest(item, 1)); // unequip\r\n                Client.Instance.SendToServer(new EquipRequest(item.Serial, World.Player, item.Layer)); // Equip\r\n            }\r\n        }\r\n\r\n        public static void Interrupt()\r\n        {\r\n            Item item = FindUsedLayer();\r\n\r\n            if (item != null)\r\n            {\r\n                Client.Instance.SendToServer(new LiftRequest(item, 1)); // unequip\r\n                Client.Instance.SendToServer(new EquipRequest(item.Serial, World.Player, item.Layer)); // Equip\r\n            }\r\n        }\r\n\r\n        private static Item FindUsedLayer()\r\n        {\r\n            Item layeredItem = World.Player.GetItemOnLayer(Layer.Shirt);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Shoes);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Pants);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Head);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Gloves);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Ring);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Neck);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Waist);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.InnerTorso);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Bracelet);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.MiddleTorso);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Earrings);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Arms);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.Cloak);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.OuterTorso);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.OuterLegs);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.InnerLegs);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.RightHand);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            layeredItem = World.Player.GetItemOnLayer(Layer.LeftHand);\r\n            if (layeredItem != null)\r\n                return layeredItem;\r\n\r\n            return null;\r\n        }\r\n\r\n        public static void Initialize()\r\n        {\r\n            // no code, this is here to make sure out static ctor is init'd by the core\r\n        }\r\n\r\n        public static void OnHotKey(ref object state)\r\n        {\r\n            ushort id = (ushort) state;\r\n            Spell s = Spell.Get(id);\r\n            if (s != null)\r\n            {\r\n                s.OnCast(new CastSpellFromMacro(id));\r\n                //if ( Macros.MacroManager.AcceptActions )\r\n                //\tMacros.MacroManager.Action( new Macros.MacroCastSpellAction( s ) );\r\n            }\r\n        }\r\n\r\n        public static int ToID(int circle, int num)\r\n        {\r\n            if (circle < 10)\r\n                return ((circle - 1) * 8) + num;\r\n            else\r\n                return (circle * 10) + num;\r\n        }\r\n\r\n        public static Spell Get(string power)\r\n        {\r\n            Spell s;\r\n            m_SpellsByPower.TryGetValue(power, out s);\r\n            return s;\r\n        }\r\n\r\n        public static Spell Get(int num)\r\n        {\r\n            Spell s;\r\n            m_SpellsByID.TryGetValue(num, out s);\r\n            return s;\r\n        }\r\n\r\n        public static Spell GetByName(string name)\r\n        {\r\n            m_SpellsByName.TryGetValue(name.ToLower(), out Spell s);\r\n            return s;\r\n        }\r\n\r\n        public static string GetName(int num)\r\n        {\r\n            if (m_SpellsByID.TryGetValue(num, out Spell spell))\r\n            {\r\n                return spell.GetName();\r\n            }\r\n\r\n            return string.Empty;\r\n        }\r\n\r\n        public static Spell Get(int circle, int num)\r\n        {\r\n            return Get(Spell.ToID(circle, num));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/StaffToolsManager.cs",
    "content": "#region license\n\n// Razor: An Ultima Online Assistant\n// Copyright (C) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\nusing FastColoredTextBoxNS;\nusing Ultima;\n\nnamespace Assistant.Core\n{\n    public static class StaffToolsManager\n    {\n        public static void Initialize()\n        {\n           \n        }\n\n        public static void LoadItems(TreeView tree)\n        {\n            XmlDocument xDoc = new XmlDocument();\n            xDoc.Load(Path.Combine(Config.GetInstallDirectory(), \"items.xml\"));\n\n            tree.SafeAction(s =>\n            {\n                s.BeginUpdate();\n\n                s.Nodes.Clear();\n                s.Nodes.Add(new TreeNode(xDoc.DocumentElement.Name));\n\n                TreeNode tNode = s.Nodes[0];\n                AddItemTreeNode(xDoc.DocumentElement, tNode);\n\n                s.Nodes[0].Expand();\n\n                s.EndUpdate();\n            });\n        }\n        \n        public static void LoadDoors(TreeView tree)\n        {\n            XmlDocument xDoc = new XmlDocument();\n            xDoc.Load(Path.Combine(Config.GetInstallDirectory(), \"doors.xml\"));\n\n            tree.SafeAction(s =>\n            {\n                s.BeginUpdate();\n\n                s.Nodes.Clear();\n                s.Nodes.Add(new TreeNode(xDoc.DocumentElement.Name));\n\n                TreeNode tNode = s.Nodes[0];\n                AddDoorTreeNode(xDoc.DocumentElement, tNode);\n\n                s.Nodes[0].Expand();\n\n                s.EndUpdate();\n            });\n        }\n\n        private static void AddItemTreeNode(XmlNode xmlNode, TreeNode treeNode)\n        {\n            if (xmlNode.HasChildNodes)\n            {\n                XmlNodeList xNodeList = xmlNode.ChildNodes;\n\n                for (int x = 0; x <= xNodeList.Count - 1; x++)\n                {\n                    XmlNode xNode = xmlNode.ChildNodes[x];\n\n                    if (xNode.Attributes != null)\n                    {\n                        XmlAttribute name = xNode.Attributes[\"name\"];\n\n                        treeNode.Nodes.Add(name != null ? new TreeNode(name.Value) : new TreeNode(xNode.Name));\n                    }\n                    else\n                    {\n                        treeNode.Nodes.Add(new TreeNode(xNode.Name));\n                    }\n\n                    TreeNode tNode = treeNode.Nodes[x];\n                    AddItemTreeNode(xNode, tNode);\n                }\n            }\n            else\n            {\n                XmlAttribute id = xmlNode.Attributes?[\"ID\"];\n\n                if (id != null)\n                {\n                    int itemId = Utility.ToInt32(id.Value, 0x0);\n                    string itemName = TileData.ItemTable[itemId].Name;\n\n                    treeNode.Text = string.IsNullOrEmpty(itemName) ? $\"{id.Value}\" : $\"{itemName} ({id.Value})\";\n\n                    treeNode.Tag = itemId;\n\n                }\n                else\n                {\n                    xmlNode.OuterXml.Trim();\n                }\n            }\n        }\n\n\n        private static void AddDoorTreeNode(XmlNode xmlNode, TreeNode treeNode)\n        {\n            if (xmlNode.HasChildNodes)\n            {\n                XmlNodeList xNodeList = xmlNode.ChildNodes;\n\n                for (int x = 0; x <= xNodeList.Count - 1; x++)\n                {\n                    XmlNode xNode = xmlNode.ChildNodes[x];\n\n                    if (xNode.Attributes != null)\n                    {\n                        DoorInfo doorInfo = DoorInfo.FromXmlNode(xNode);\n\n                        treeNode.Nodes.Add(new TreeNode(doorInfo.Name));\n                    }\n                    else\n                    {\n                        treeNode.Nodes.Add(new TreeNode(xNode.Name));\n                    }\n\n                    TreeNode tNode = treeNode.Nodes[x];\n                    AddDoorTreeNode(xNode, tNode);\n                }\n            }\n            else\n            {\n                XmlAttribute id = xmlNode.Attributes?[\"base\"];\n\n                if (id != null)\n                {\n                    //<Door name=\"Stone 1\" base=\"232\" item=\"SecretStoneDoor1\"></Door>\n                    DoorInfo doorInfo = DoorInfo.FromXmlNode(xmlNode);\n                    treeNode.Tag = doorInfo;\n\n                }\n                else\n                {\n                    xmlNode.OuterXml.Trim();\n                }\n            }\n        }\n\n        public static void AddDoor(DoorInfo door, string facing)\n        {\n            string command = $\"[add {door.Item} {facing}\";\n\n            World.Player.SendMessage(MsgLevel.Info, $\"Command: {command}\");\n            World.Player.Say(command);\n        }\n\n        public static int GetDoorOffset(string facing)\n        {\n            var offset = 0;\n\n            if (facing.Contains(\"WestCW\"))\n            {\n                offset = 0;\n            }\n            else if (facing.Contains(\"EastCCW\"))\n            {\n                offset = 2;\n            }\n            else if (facing.Contains(\"WestCCW\"))\n            {\n                offset = 4;\n            }\n            else if (facing.Contains(\"EastCW\"))\n            {\n                offset = 6;\n            }\n            else if (facing.Contains(\"NorthCW\"))\n            {\n                offset = 14;\n            }\n            else if (facing.Contains(\"SouthCCW\"))\n            {\n                offset = 8;\n            }\n            else if (facing.Contains(\"NorthCCW\"))\n            {\n                offset = 10;\n            }\n            else if (facing.Contains(\"SouthCW\"))\n            {\n                offset = 12;\n            }\n\n            return offset;\n        }\n    }\n\n    public class DoorInfo\n    {\n        /// <summary>\n        ///     Gets or sets the door name\n        /// </summary>\n        public string Name { get; private set; }\n\n        /// <summary>\n        ///     Gets or sets the door's item name\n        /// </summary>\n        public string Item { get; private set; }\n\n        /// <summary>\n        ///     Gets or sets the door's base ID\n        /// </summary>\n        public int BaseId { get; private set; }\n\n        /// <summary>\n        ///     Creates a new DoorInfo object\n        /// </summary>\n        private DoorInfo()\n        { }\n\n        /// <summary>\n        ///     Creates a DoorInfo from an Xml node\n        /// </summary>\n        /// <param name=\"xNode\">The XmlNode to convert to a door info</param>\n        /// <returns>A Door Info object</returns>\n        public static DoorInfo FromXmlNode(XmlNode xNode)\n        {\n            var door = new DoorInfo\n            {\n                Name = xNode.Attributes[\"name\"].Value,\n                Item = xNode.Attributes[\"item\"]?.Value,\n                BaseId = xNode.Attributes[\"base\"]?.Value != null ? int.Parse(xNode.Attributes[\"base\"].Value) : 0\n            };\n\n            return door;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/StealthSteps.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant\r\n{\r\n    public class StealthSteps\r\n    {\r\n        private static int m_Count;\r\n        private static bool m_Hidden = false;\r\n\r\n        public static int Count\r\n        {\r\n            get { return m_Count; }\r\n        }\r\n\r\n        public static bool Counting\r\n        {\r\n            get { return m_Hidden; }\r\n        }\r\n\r\n        public static bool Hidden\r\n        {\r\n            get { return m_Hidden; }\r\n        }\r\n\r\n        public static void OnMove()\r\n        {\r\n            if (m_Hidden && Config.GetBool(\"CountStealthSteps\") && World.Player != null)\r\n            {\r\n                m_Count++;\r\n\r\n                string message = Config.GetString(\"StealthStepsFormat\").Replace(\"{step}\", m_Count.ToString());\r\n\r\n                if (string.IsNullOrEmpty(message))\r\n                    message = $\"Steps: {m_Count}\";\r\n\r\n                if (Config.GetBool(\"StealthOverhead\"))\r\n                {\r\n                    World.Player.OverheadMessage(message);\r\n                }\r\n                else\r\n                {\r\n                    World.Player.SendMessage(MsgLevel.Error, message);\r\n                }\r\n\r\n                if (m_Count > 30)\r\n                    Unhide();\r\n            }\r\n        }\r\n\r\n        public static void Hide()\r\n        {\r\n            m_Hidden = true;\r\n            m_Count = 0;\r\n        }\r\n\r\n        public static void Unhide()\r\n        {\r\n            m_Hidden = false;\r\n            m_Count = 0;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/SystemMessages.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\n\nnamespace Assistant.Core\n{\n    public static class SystemMessages\n    {\n        public static List<string> Messages { get; } = new List<string>();\n        \n        public static void Initialize()\n        {\n            MessageManager.OnSystemMessage += HandleSystemMessage;\n        }\n        \n        private static void HandleSystemMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\n            MessageType type, ushort hue, ushort font, string lang, string sourceName,\n            string text)\n        {\n            if (source == Serial.MinusOne && sourceName == \"System\")\n            {\n                if (Config.GetBool(\"FilterSnoopMsg\") && text.IndexOf(World.Player.Name) == -1 &&\n                    text.StartsWith(\"You notice\") && text.IndexOf(\"attempting to peek into\") != -1 &&\n                    text.IndexOf(\"belongings\") != -1)\n                {\n                    args.Block = true;\n                    return;\n                }\n\n                if (text.StartsWith(\"You've committed a criminal act\") || text.StartsWith(\"You are now a criminal\"))\n                {\n                    World.Player.ResetCriminalTimer();\n                }\n\n                // Overhead message override\n                OverheadManager.DisplayOverheadMessage(text);\n            }\n\n            if (!source.IsValid || source == World.Player.Serial || source.IsItem)\n            {\n                Add(text);\n            }\n\n            if (Config.GetBool(\"FilterSystemMessages\") && source == Serial.MinusOne || source == Serial.Zero)\n            {\n                if (!MessageQueue.Enqueue(source, null, graphic, type, hue, font, lang, sourceName, text))\n                {\n                    args.Block = true;\n                }\n            }\n        }\n\n        public static void Add(string text)\n        {\n            if (string.IsNullOrEmpty(text))\n            {\n                return;\n            }\n\n            Messages.Add(text);\n\n            if (Messages.Count >= 100)\n            {\n                Messages.RemoveRange(0, 10);\n            }\n        }\n\n        public static bool Exists(string text)\n        {\n            if (string.IsNullOrEmpty(text))\n            {\n                return false;\n            }\n\n            for (int i = Messages.Count - 1; i >= 0; i--)\n            {\n                if (Messages[i].IndexOf(text, StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    Messages.RemoveRange(0, i + 1);\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Core/Targeting.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing Assistant.Agents;\r\nusing Assistant.Core;\r\nusing Assistant.Macros;\r\nusing Assistant.Scripts;\r\n\r\nnamespace Assistant\r\n{\r\n    public class TargetInfo\r\n    {\r\n        public byte Type;\r\n        public uint TargID;\r\n        public byte Flags;\r\n        public Serial Serial;\r\n        public int X, Y;\r\n        public int Z;\r\n        public ushort Gfx;\r\n    }\r\n\r\n    public partial class Targeting\r\n    {\r\n        public const uint LocalTargID = 0x7FFFFFFF; // uid for target sent from razor\r\n\r\n        public delegate void TargetResponseCallback(bool location, Serial serial, Point3D p, ushort gfxid);\r\n\r\n        public delegate void CancelTargetCallback();\r\n\r\n        private static CancelTargetCallback _onCancel;\r\n        private static TargetResponseCallback _onTarget;\r\n\r\n        private static bool _intercept;\r\n        private static bool _hasTarget;\r\n        private static bool _clientTarget;\r\n        private static TargetInfo _lastTarget { get; set; }\r\n        private static TargetInfo _lastGroundTarget;\r\n        private static TargetInfo _lastBeneTarget;\r\n        private static TargetInfo _lastHarmTarget;\r\n\r\n\r\n        private static bool _fromGrabHotKey;\r\n\r\n        private static bool _allowGround;\r\n        private static uint _currentID;\r\n        private static byte _curFlags;\r\n\r\n        private static uint _previousID;\r\n        private static bool _previousGround;\r\n        private static byte _prevFlags;\r\n\r\n        private static Serial _lastCombatant;\r\n\r\n        private delegate bool QueueTarget();\r\n\r\n        private static readonly QueueTarget TargetSelfAction = new QueueTarget(DoTargetSelf);\r\n        private static readonly QueueTarget LastTargetAction = new QueueTarget(DoLastTarget);\r\n        private static QueueTarget _queueTarget;\r\n\r\n\r\n        public static uint SpellTargetID { get; set; } = 0;\r\n\r\n        private static List<uint> _filterCancel = new List<uint>();\r\n\r\n        public static bool HasTarget\r\n        {\r\n            get { return _hasTarget; }\r\n        }\r\n\r\n        public static short CursorType => _curFlags;\r\n\r\n        public static TargetInfo LastTargetInfo\r\n        {\r\n            get { return _lastTarget; }\r\n        }\r\n\r\n        public static bool FromGrabHotKey\r\n        {\r\n            get { return _fromGrabHotKey; }\r\n        }\r\n\r\n        private static List<ushort> _monsterIds = new List<ushort>()\r\n        {\r\n            0x1, 0x2, 0x3, 0x4, 0x7, 0x8, 0x9, 0xC, 0xD, 0xE, 0xF,\r\n            0x10, 0x11, 0x12, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,\r\n            0x1E, 0x1F, 0x21, 0x23, 0x24, 0x25, 0x27, 0x29, 0x2A, 0x2C,\r\n            0x2D, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,\r\n            0x39, 0x3B, 0x3C, 0x3D, 0x42, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,\r\n            0x4B, 0x4F, 0x50, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x59, 0x5A,\r\n            0x5B, 0x5C, 0x5D, 0x5E, 0x60, 0x61, 0x62, 0x69, 0x6A, 0x6B, 0x6C,\r\n            0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x87, 0x88, 0x89,\r\n            0x8A, 0x8B, 0x8C, 0x8E, 0x8F, 0x91, 0x93, 0x96, 0x99, 0x9B, 0x9E,\r\n            0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xB4, 0x4C, 0x4D, 0x3D\r\n        };\r\n\r\n        public enum TargetType\r\n        {\r\n            Invalid, // invalid/across server line\r\n            Innocent, //Blue\r\n            GuildAlly, //Green,\r\n            Attackable, //Attackable but not criminal (gray)\r\n            Criminal, //gray\r\n            Enemy, //orange\r\n            Murderer, //red\r\n\r\n            // Razor specfic\r\n            NonFriendly, //Attackable, Criminal, Enemy, Murderer\r\n            Friendly, //Innocent, Guild/Ally \r\n            Red, //Murderer\r\n            Blue, //Innocent\r\n            //Friend, //Friend list\r\n            Gray, //Attackable, Criminal\r\n            Grey, //Attackable, Criminal\r\n            Green, //GuildAlly\r\n            Guild, //GuildAlly\r\n        }\r\n\r\n\r\n        public static void Initialize()\r\n        {\r\n            PacketHandler.RegisterClientToServerViewer(0x6C, TargetResponse);\r\n            PacketHandler.RegisterServerToClientViewer(0x6C, NewTarget);\r\n            PacketHandler.RegisterServerToClientViewer(0xAA, CombatantChange);\r\n\r\n            HotKey.Add(HKCategory.Targets, LocString.LastTarget, LastTarget);\r\n            HotKey.Add(HKCategory.Targets, LocString.TargetSelf, TargetSelf);\r\n            HotKey.Add(HKCategory.Targets, LocString.ClearTargQueue, OnClearQueue);\r\n\r\n            HotKey.Add(HKCategory.Targets, LocString.SetLT, TargetSetLastTarget);\r\n            HotKey.Add(HKCategory.Targets, LocString.SetLastBeneficial, SetLastTargetBeneficial);\r\n            HotKey.Add(HKCategory.Targets, LocString.SetLastHarmful, SetLastTargetHarmful);\r\n\r\n            HotKey.Add(HKCategory.Targets, LocString.AttackLastComb, AttackLastComb);\r\n            HotKey.Add(HKCategory.Targets, LocString.AttackLastTarg, AttackLastTarg);\r\n            HotKey.Add(HKCategory.Targets, LocString.CancelTarget, CancelTarget);\r\n\r\n            InitRandomTarget();\r\n            InitNextPrevTargets();\r\n            InitClosestTargets();\r\n        }\r\n\r\n\r\n        private static void CombatantChange(PacketReader p, PacketHandlerEventArgs e)\r\n        {\r\n            Serial ser = p.ReadUInt32();\r\n            if (ser.IsMobile && ser != World.Player.Serial && ser != Serial.Zero && ser != Serial.MinusOne)\r\n                _lastCombatant = ser;\r\n        }\r\n\r\n        private static void AttackLastComb()\r\n        {\r\n            if (_lastCombatant.IsMobile)\r\n            {\r\n                Client.Instance.SendToServer(new AttackReq(_lastCombatant));\r\n                ShowAttackOverhead(_lastCombatant);\r\n            }\r\n                \r\n        }\r\n\r\n        public static void AttackLastTarg()\r\n        {\r\n            TargetInfo targ;\r\n            if (IsSmartTargetingEnabled())\r\n            {\r\n                // If Smart Targetting is being used we'll assume that the user would like to attack the harmful target.\r\n                targ = _lastHarmTarget;\r\n\r\n                // If there is no last harmful target, then we'll attack the last target.\r\n                if (targ == null)\r\n                    targ = _lastTarget;\r\n            }\r\n            else\r\n            {\r\n                targ = _lastTarget;\r\n            }\r\n\r\n            if (targ != null && targ.Serial.IsMobile)\r\n            {\r\n                Client.Instance.SendToServer(new AttackReq(targ.Serial));\r\n                ShowAttackOverhead(targ.Serial);\r\n            }\r\n        }\r\n\r\n        private static Serial _lastOverheadMessageAttack;\r\n\r\n        public static void ShowAttackOverhead(Serial serial)\r\n        {\r\n            if (!Config.GetBool(\"ShowAttackTargetOverhead\"))\r\n                return;\r\n\r\n            if (Config.GetBool(\"ShowAttackTargetNewOnly\") && serial == _lastOverheadMessageAttack)\r\n                return;\r\n\r\n            Mobile m = World.FindMobile(serial);\r\n            if (m == null)\r\n                return;\r\n\r\n            World.Player.OverheadMessage(FriendsManager.IsFriend(m.Serial) ? 63 : m.GetNotorietyColorInt(),\r\n                $\"Attack: {m.Name}\");\r\n\r\n            _lastOverheadMessageAttack = serial;\r\n        }\r\n\r\n        public static void OnClearQueue()\r\n        {\r\n            ClearQueue();\r\n\r\n            if (Config.GetBool(\"ShowTargetSelfLastClearOverhead\"))\r\n            {\r\n                World.Player.OverheadMessage(LocString.TQCleared);\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.TQCleared);\r\n            }\r\n        }\r\n\r\n        internal static void OneTimeTarget(TargetResponseCallback onTarget)\r\n        {\r\n            OneTimeTarget(false, onTarget, null);\r\n        }\r\n\r\n        internal static void OneTimeTarget(TargetResponseCallback onTarget, bool fromGrab)\r\n        {\r\n            _fromGrabHotKey = fromGrab;\r\n\r\n            OneTimeTarget(false, onTarget, null);\r\n        }\r\n\r\n        internal static void OneTimeTarget(bool ground, TargetResponseCallback onTarget)\r\n        {\r\n            OneTimeTarget(ground, onTarget, null);\r\n        }\r\n\r\n        internal static void OneTimeTarget(TargetResponseCallback onTarget, CancelTargetCallback onCancel)\r\n        {\r\n            OneTimeTarget(false, onTarget, onCancel);\r\n        }\r\n\r\n        internal static void OneTimeTarget(bool ground, TargetResponseCallback onTarget, CancelTargetCallback onCancel)\r\n        {\r\n            if (_intercept && _onCancel != null)\r\n            {\r\n                _onCancel();\r\n                CancelOneTimeTarget();\r\n            }\r\n\r\n            if (_hasTarget && _currentID != 0 && _currentID != LocalTargID)\r\n            {\r\n                _previousID = _currentID;\r\n                _previousGround = _allowGround;\r\n                _prevFlags = _curFlags;\r\n\r\n                _filterCancel.Add(_previousID);\r\n            }\r\n\r\n            _intercept = true;\r\n            _currentID = LocalTargID;\r\n            _onTarget = onTarget;\r\n            _onCancel = onCancel;\r\n\r\n            _clientTarget = _hasTarget = true;\r\n            Client.Instance.SendToClient(new Target(LocalTargID, ground));\r\n            ClearQueue();\r\n        }\r\n\r\n        internal static void CancelOneTimeTarget()\r\n        {\r\n            _clientTarget = _hasTarget = _fromGrabHotKey = false;\r\n\r\n            Client.Instance.SendToClient(new CancelTarget(LocalTargID));\r\n            EndIntercept();\r\n        }\r\n\r\n        private static bool _lastTargetWasSet;\r\n\r\n        public static void TargetSetLastTarget()\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                _lastTargetWasSet = false;\r\n                OneTimeTarget(false, OnSetLastTarget, OnSetLastTargetCancel);\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.TargSetLT);\r\n            }\r\n        }\r\n\r\n        public static void SetLastTarget(Mobile mobile)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                OnSetLastTarget(false, mobile.Serial, mobile.Position, mobile.Body);\r\n            }\r\n        }\r\n\r\n        public static void SetLastTarget(Item item)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                OnSetLastTarget(false, item.Serial, item.Position, item.ItemID.Value);\r\n            }\r\n        }\r\n\r\n        public static void SetLastTarget(Serial serial)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                OnSetLastTarget(false, serial, new Point3D(0, 0, 0), 0);\r\n            }\r\n        }\r\n\r\n        private static void OnSetLastTargetCancel()\r\n        {\r\n            if (_lastTarget != null)\r\n                _lastTargetWasSet = true;\r\n        }\r\n\r\n        private static void OnSetLastTarget(bool location, Serial serial, Point3D p, ushort gfxid)\r\n        {\r\n            if (serial == World.Player.Serial)\r\n            {\r\n                OnSetLastTargetCancel();\r\n                return;\r\n            }\r\n\r\n            _lastBeneTarget = _lastHarmTarget = _lastGroundTarget = _lastTarget = new TargetInfo();\r\n            _lastTarget.Flags = 0;\r\n            _lastTarget.Gfx = gfxid;\r\n            _lastTarget.Serial = serial;\r\n            _lastTarget.Type = (byte) (location ? 1 : 0);\r\n            _lastTarget.X = p.X;\r\n            _lastTarget.Y = p.Y;\r\n            _lastTarget.Z = p.Z;\r\n\r\n            _lastTargetWasSet = true;\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.LTSet);\r\n\r\n            if (serial.IsMobile)\r\n            {\r\n                LastTargetChanged();\r\n                Client.Instance.SendToClient(new ChangeCombatant(serial));\r\n                _lastCombatant = serial;\r\n            }\r\n        }\r\n\r\n        private static bool m_LTBeneWasSet;\r\n\r\n        /// <summary>\r\n        /// Sets the beneficial target\r\n        /// </summary>\r\n        private static void SetLastTargetBeneficial()\r\n        {\r\n            if (!IsSmartTargetingEnabled())\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"Smart Targeting is disabled\");\r\n                return;\r\n            }\r\n\r\n            if (World.Player != null)\r\n            {\r\n                m_LTBeneWasSet = false;\r\n                OneTimeTarget(false, OnSetLastTargetBeneficial, OnSLTBeneficialCancel);\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.NewBeneficialTarget);\r\n            }\r\n        }\r\n\r\n        private static void OnSLTBeneficialCancel()\r\n        {\r\n            if (_lastBeneTarget != null)\r\n                m_LTBeneWasSet = true;\r\n        }\r\n\r\n        private static void OnSetLastTargetBeneficial(bool location, Serial serial, Point3D p, ushort gfxid)\r\n        {\r\n            if (serial == World.Player.Serial)\r\n            {\r\n                OnSLTBeneficialCancel();\r\n                return;\r\n            }\r\n\r\n            _lastBeneTarget = new TargetInfo\r\n            {\r\n                Flags = 0,\r\n                Gfx = gfxid,\r\n                Serial = serial,\r\n                Type = (byte) (location ? 1 : 0),\r\n                X = p.X,\r\n                Y = p.Y,\r\n                Z = p.Z\r\n            };\r\n\r\n            m_LTBeneWasSet = true;\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SetLTBene);\r\n\r\n            if (serial.IsMobile)\r\n            {\r\n                LastBeneficialTargetChanged();\r\n            }\r\n        }\r\n\r\n        private static bool m_LTHarmWasSet;\r\n\r\n        /// <summary>\r\n        /// Sets the harmful target\r\n        /// </summary>\r\n        private static void SetLastTargetHarmful()\r\n        {\r\n            if (!IsSmartTargetingEnabled())\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Error, \"Smart Targeting is disabled\");\r\n                return;\r\n            }\r\n\r\n            if (World.Player != null)\r\n            {\r\n                OneTimeTarget(false, OnSetLastTargetHarmful, OnSLTHarmfulCancel);\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.NewHarmfulTarget);\r\n            }\r\n        }\r\n\r\n        private static void OnSLTHarmfulCancel()\r\n        {\r\n            if (_lastTarget != null)\r\n                m_LTHarmWasSet = true;\r\n        }\r\n\r\n        private static void OnSetLastTargetHarmful(bool location, Serial serial, Point3D p, ushort gfxid)\r\n        {\r\n            if (serial == World.Player.Serial)\r\n            {\r\n                OnSLTHarmfulCancel();\r\n                return;\r\n            }\r\n\r\n            _lastHarmTarget = new TargetInfo\r\n            {\r\n                Flags = 0,\r\n                Gfx = gfxid,\r\n                Serial = serial,\r\n                Type = (byte) (location ? 1 : 0),\r\n                X = p.X,\r\n                Y = p.Y,\r\n                Z = p.Z\r\n            };\r\n\r\n            m_LTHarmWasSet = true;\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SetLTHarm);\r\n\r\n            if (serial.IsMobile)\r\n            {\r\n                LastHarmfulTargetChanged();\r\n            }\r\n        }\r\n\r\n        private static Serial m_OldLT = Serial.Zero;\r\n        private static Serial m_OldBeneficialLT = Serial.Zero;\r\n        private static Serial m_OldHarmfulLT = Serial.Zero;\r\n\r\n        private static void RemoveTextFlags(UOEntity m)\r\n        {\r\n            if (m != null)\r\n            {\r\n                bool oplchanged = false;\r\n\r\n                oplchanged |= m.ObjPropList.Remove(Language.GetString(LocString.LastTarget));\r\n                oplchanged |= m.ObjPropList.Remove(Language.GetString(LocString.HarmfulTarget));\r\n                oplchanged |= m.ObjPropList.Remove(Language.GetString(LocString.BeneficialTarget));\r\n\r\n                if (oplchanged)\r\n                    m.OPLChanged();\r\n            }\r\n        }\r\n\r\n        private static void AddTextFlags(UOEntity m)\r\n        {\r\n            if (m != null)\r\n            {\r\n                bool oplchanged = false;\r\n\r\n                if (IsSmartTargetingEnabled())\r\n                {\r\n                    if (_lastHarmTarget != null && _lastHarmTarget.Serial == m.Serial)\r\n                    {\r\n                        oplchanged = true;\r\n                        m.ObjPropList.Add(Language.GetString(LocString.HarmfulTarget));\r\n                    }\r\n\r\n                    if (_lastBeneTarget != null && _lastBeneTarget.Serial == m.Serial)\r\n                    {\r\n                        oplchanged = true;\r\n                        m.ObjPropList.Add(Language.GetString(LocString.BeneficialTarget));\r\n                    }\r\n                }\r\n\r\n                if (!oplchanged && _lastTarget != null && _lastTarget.Serial == m.Serial)\r\n                {\r\n                    oplchanged = true;\r\n                    m.ObjPropList.Add(Language.GetString(LocString.LastTarget));\r\n                }\r\n\r\n                if (oplchanged)\r\n                    m.OPLChanged();\r\n            }\r\n        }\r\n\r\n        private static void LastTargetChanged()\r\n        {\r\n            if (_lastTarget != null)\r\n            {\r\n                bool lth = Config.GetInt(\"LTHilight\") != 0;\r\n\r\n                if (m_OldLT.IsItem)\r\n                {\r\n                    RemoveTextFlags(World.FindItem(m_OldLT));\r\n                }\r\n                else\r\n                {\r\n                    Mobile m = World.FindMobile(m_OldLT);\r\n                    if (m != null)\r\n                    {\r\n                        if (lth)\r\n                            Client.Instance.SendToClient(new MobileIncoming(m));\r\n\r\n                        RemoveTextFlags(m);\r\n                    }\r\n                }\r\n\r\n                if (_lastTarget.Serial.IsItem)\r\n                {\r\n                    AddTextFlags(World.FindItem(_lastTarget.Serial));\r\n                }\r\n                else\r\n                {\r\n                    Mobile m = World.FindMobile(_lastTarget.Serial);\r\n                    if (m != null)\r\n                    {\r\n                        if (IsLastTarget(m) && lth)\r\n                            Client.Instance.SendToClient(new MobileIncoming(m));\r\n\r\n                        CheckLastTargetRange(m);\r\n\r\n                        AddTextFlags(m);\r\n                    }\r\n                }\r\n\r\n                m_OldLT = _lastTarget.Serial;\r\n            }\r\n        }\r\n\r\n        private static void LastBeneficialTargetChanged()\r\n        {\r\n            if (_lastBeneTarget != null)\r\n            {\r\n                if (m_OldBeneficialLT.IsItem)\r\n                {\r\n                    RemoveTextFlags(World.FindItem(m_OldBeneficialLT));\r\n                }\r\n                else\r\n                {\r\n                    Mobile m = World.FindMobile(m_OldBeneficialLT);\r\n                    if (m != null)\r\n                    {\r\n                        RemoveTextFlags(m);\r\n                    }\r\n                }\r\n\r\n                if (_lastBeneTarget.Serial.IsItem)\r\n                {\r\n                    AddTextFlags(World.FindItem(_lastBeneTarget.Serial));\r\n                }\r\n                else\r\n                {\r\n                    Mobile m = World.FindMobile(_lastBeneTarget.Serial);\r\n                    if (m != null)\r\n                    {\r\n                        CheckLastTargetRange(m);\r\n\r\n                        AddTextFlags(m);\r\n                    }\r\n                }\r\n\r\n                m_OldBeneficialLT = _lastBeneTarget.Serial;\r\n            }\r\n        }\r\n\r\n        private static void LastHarmfulTargetChanged()\r\n        {\r\n            if (_lastHarmTarget != null)\r\n            {\r\n                if (m_OldHarmfulLT.IsItem)\r\n                {\r\n                    RemoveTextFlags(World.FindItem(m_OldHarmfulLT));\r\n                }\r\n                else\r\n                {\r\n                    Mobile m = World.FindMobile(m_OldHarmfulLT);\r\n                    if (m != null)\r\n                    {\r\n                        RemoveTextFlags(m);\r\n                    }\r\n                }\r\n\r\n                if (_lastHarmTarget.Serial.IsItem)\r\n                {\r\n                    AddTextFlags(World.FindItem(_lastHarmTarget.Serial));\r\n                }\r\n                else\r\n                {\r\n                    Mobile m = World.FindMobile(_lastHarmTarget.Serial);\r\n                    if (m != null)\r\n                    {\r\n                        CheckLastTargetRange(m);\r\n\r\n                        AddTextFlags(m);\r\n                    }\r\n                }\r\n\r\n                m_OldHarmfulLT = _lastHarmTarget.Serial;\r\n            }\r\n        }\r\n\r\n\r\n        public static bool LastTargetWasSet\r\n        {\r\n            get { return _lastTargetWasSet; }\r\n        }\r\n\r\n\r\n        public static void SetLastTargetTo(Mobile m)\r\n        {\r\n            SetLastTargetTo(m, 0);\r\n        }\r\n\r\n        public static void SetLastTargetTo(Mobile m, byte flagType)\r\n        {\r\n            TargetInfo targ = new TargetInfo();\r\n            _lastGroundTarget = _lastTarget = targ;\r\n\r\n            if ((_hasTarget && _curFlags == 1) || flagType == 1)\r\n                _lastHarmTarget = targ;\r\n            else if ((_hasTarget && _curFlags == 2) || flagType == 2)\r\n                _lastBeneTarget = targ;\r\n            else if (flagType == 0)\r\n                _lastHarmTarget = _lastBeneTarget = targ;\r\n\r\n            targ.Type = 0;\r\n            if (_hasTarget)\r\n                targ.Flags = _curFlags;\r\n            else\r\n                targ.Flags = flagType;\r\n\r\n            targ.Gfx = m.Body;\r\n            targ.Serial = m.Serial;\r\n            targ.X = m.Position.X;\r\n            targ.Y = m.Position.Y;\r\n            targ.Z = m.Position.Z;\r\n\r\n            Client.Instance.SendToClient(new ChangeCombatant(m));\r\n            _lastCombatant = m.Serial;\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.NewTargSet);\r\n\r\n            OverheadTargetMessage(targ);\r\n\r\n            bool wasSmart = Config.GetBool(\"SmartLastTarget\");\r\n            if (wasSmart)\r\n                Config.SetProperty(\"SmartLastTarget\", false);\r\n            LastTarget();\r\n            if (wasSmart)\r\n                Config.SetProperty(\"SmartLastTarget\", true);\r\n            LastTargetChanged();\r\n        }\r\n\r\n        private static void EndIntercept()\r\n        {\r\n            _intercept = false;\r\n            _onTarget = null;\r\n            _onCancel = null;\r\n            _fromGrabHotKey = false;\r\n        }\r\n\r\n        public static void TargetSelf()\r\n        {\r\n            TargetSelf(false);\r\n        }\r\n\r\n        public static void TargetSelf(bool forceQ)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            //if ( Macros.MacroManager.AcceptActions )\r\n            //\tMacroManager.Action( new TargetSelfAction() );\r\n\r\n            if (_hasTarget)\r\n            {\r\n                if (!DoTargetSelf())\r\n                    ResendTarget();\r\n            }\r\n            else if (forceQ || Config.GetBool(\"QueueTargets\"))\r\n            {\r\n                if (!forceQ)\r\n                {\r\n                    if (Config.GetBool(\"ShowTargetSelfLastClearOverhead\"))\r\n                    {\r\n                        World.Player.OverheadMessage(LocString.QueuedTS);\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Force, LocString.QueuedTS);\r\n                    }\r\n                }\r\n\r\n                _queueTarget = TargetSelfAction;\r\n            }\r\n        }\r\n\r\n        public static bool DoTargetSelf()\r\n        {\r\n            if (World.Player == null)\r\n                return false;\r\n\r\n            if (CheckHealPoisonTarg(_currentID, World.Player.Serial))\r\n                return false;\r\n\r\n            CancelClientTarget();\r\n            _hasTarget = false;\r\n            _fromGrabHotKey = false;\r\n\r\n            if (_intercept)\r\n            {\r\n                TargetInfo targ = new TargetInfo();\r\n                targ.Serial = World.Player.Serial;\r\n                targ.Gfx = World.Player.Body;\r\n                targ.Type = 0;\r\n                targ.X = World.Player.Position.X;\r\n                targ.Y = World.Player.Position.Y;\r\n                targ.Z = World.Player.Position.Z;\r\n                targ.TargID = LocalTargID;\r\n                targ.Flags = 0;\r\n\r\n                OneTimeResponse(targ);\r\n            }\r\n            else\r\n            {\r\n                Client.Instance.SendToServer(new TargetResponse(_currentID, World.Player));\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public static void LastTarget()\r\n        {\r\n            LastTarget(false);\r\n        }\r\n\r\n        public static void LastTarget(bool forceQ)\r\n        {\r\n            //if ( Macros.MacroManager.AcceptActions )\r\n            //\tMacroManager.Action( new LastTargetAction() );\r\n\r\n            if (FromGrabHotKey)\r\n                return;\r\n\r\n            if (_hasTarget)\r\n            {\r\n                if (!DoLastTarget())\r\n                    ResendTarget();\r\n            }\r\n            else if (forceQ || Config.GetBool(\"QueueTargets\"))\r\n            {\r\n                if (!forceQ)\r\n                {\r\n                    if (Config.GetBool(\"ShowTargetSelfLastClearOverhead\"))\r\n                    {\r\n                        World.Player.OverheadMessage(LocString.QueuedLT);\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Force, LocString.QueuedLT);\r\n                    }\r\n                }\r\n\r\n                _queueTarget = LastTargetAction;\r\n            }\r\n        }\r\n\r\n        public static bool DoLastTarget()\r\n        {\r\n            if (FromGrabHotKey)\r\n                return true;\r\n\r\n            TargetInfo targ;\r\n            if (IsSmartTargetingEnabled())\r\n            {\r\n                if (_allowGround && _lastGroundTarget != null)\r\n                    targ = _lastGroundTarget;\r\n                else if (_curFlags == 1)\r\n                    targ = _lastHarmTarget;\r\n                else if (_curFlags == 2)\r\n                    targ = _lastBeneTarget;\r\n                else\r\n                    targ = _lastTarget;\r\n\r\n                if (targ == null)\r\n                    targ = _lastTarget;\r\n            }\r\n            else\r\n            {\r\n                if (_allowGround && _lastGroundTarget != null)\r\n                    targ = _lastGroundTarget;\r\n                else\r\n                    targ = _lastTarget;\r\n            }\r\n\r\n            if (targ == null)\r\n                return false;\r\n\r\n            Point3D pos = Point3D.Zero;\r\n            if (targ.Serial.IsMobile)\r\n            {\r\n                Mobile m = World.FindMobile(targ.Serial);\r\n                if (m != null)\r\n                {\r\n                    pos = m.Position;\r\n\r\n                    targ.X = pos.X;\r\n                    targ.Y = pos.Y;\r\n                    targ.Z = pos.Z;\r\n                }\r\n                else\r\n                {\r\n                    pos = Point3D.Zero;\r\n                }\r\n            }\r\n            else if (targ.Serial.IsItem)\r\n            {\r\n                Item i = World.FindItem(targ.Serial);\r\n                if (i != null)\r\n                {\r\n                    pos = i.GetWorldPosition();\r\n\r\n                    targ.X = i.Position.X;\r\n                    targ.Y = i.Position.Y;\r\n                    targ.Z = i.Position.Z;\r\n                }\r\n                else\r\n                {\r\n                    pos = Point3D.Zero;\r\n                    targ.X = targ.Y = targ.Z = 0;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                if (!_allowGround && (targ.Serial == Serial.Zero || targ.Serial >= 0x80000000))\r\n                {\r\n                    World.Player.SendMessage(MsgLevel.Warning, LocString.LTGround);\r\n                    return false;\r\n                }\r\n                else\r\n                {\r\n                    pos = new Point3D(targ.X, targ.Y, targ.Z);\r\n                }\r\n            }\r\n\r\n            if (Config.GetBool(\"RangeCheckLT\") && Client.Instance.AllowBit(FeatureBit.RangeCheckLT) &&\r\n                (pos == Point3D.Zero || !Utility.InRange(World.Player.Position, pos, Config.GetInt(\"LTRange\"))))\r\n            {\r\n                if (Config.GetBool(\"QueueTargets\"))\r\n                    _queueTarget = LastTargetAction;\r\n                World.Player.SendMessage(MsgLevel.Warning, LocString.LTOutOfRange);\r\n                return false;\r\n            }\r\n\r\n            if (CheckHealPoisonTarg(_currentID, targ.Serial))\r\n                return false;\r\n\r\n            CancelClientTarget();\r\n            _hasTarget = false;\r\n\r\n            targ.TargID = _currentID;\r\n\r\n            if (_intercept)\r\n                OneTimeResponse(targ);\r\n            else\r\n                Client.Instance.SendToServer(new TargetResponse(targ));\r\n            return true;\r\n        }\r\n\r\n        public static void ClearQueue()\r\n        {\r\n            _queueTarget = null;\r\n        }\r\n\r\n        private static TimerCallbackState m_OneTimeRespCallback = new TimerCallbackState(OneTimeResponse);\r\n\r\n        private static void OneTimeResponse(object state)\r\n        {\r\n            TargetInfo info = state as TargetInfo;\r\n\r\n            if (info != null)\r\n            {\r\n                if ((info.X == 0xFFFF && info.X == 0xFFFF) && (info.Serial == 0 || info.Serial >= 0x80000000))\r\n                {\r\n                    if (_onCancel != null)\r\n                        _onCancel();\r\n                }\r\n                else\r\n                {\r\n                    if (Macros.MacroManager.AcceptActions)\r\n                        MacroManager.Action(new AbsoluteTargetAction(info));\r\n\r\n                    ScriptManager.AddToScript($\"target {info.Serial}\");\r\n\r\n                    if (_onTarget != null)\r\n                        _onTarget(info.Type == 1 ? true : false, info.Serial, new Point3D(info.X, info.Y, info.Z),\r\n                            info.Gfx);\r\n                }\r\n            }\r\n\r\n            EndIntercept();\r\n        }\r\n\r\n        public static void CancelTarget()\r\n        {\r\n            OnClearQueue();\r\n            CancelClientTarget();\r\n\r\n            _fromGrabHotKey = false;\r\n\r\n            ScriptManager.SetVariableActive = false;\r\n\r\n            if (_hasTarget)\r\n            {\r\n                Client.Instance.SendToServer(new TargetCancelResponse(_currentID));\r\n                _hasTarget = false;\r\n            }\r\n        }\r\n\r\n        private static void CancelClientTarget()\r\n        {\r\n            if (_clientTarget)\r\n            {\r\n                _filterCancel.Add((uint) _currentID);\r\n                Client.Instance.SendToClient(new CancelTarget(_currentID));\r\n                _clientTarget = false;\r\n            }\r\n        }\r\n\r\n        public static void Target(TargetInfo info)\r\n        {\r\n            if (_intercept)\r\n            {\r\n                OneTimeResponse(info);\r\n            }\r\n            else if (_hasTarget)\r\n            {\r\n                info.TargID = _currentID;\r\n                _lastGroundTarget = _lastTarget = info;\r\n                Client.Instance.SendToServer(new TargetResponse(info));\r\n            }\r\n\r\n            CancelClientTarget();\r\n            _hasTarget = false;\r\n            _fromGrabHotKey = false;\r\n        }\r\n\r\n        public static void Target(Point3D pt)\r\n        {\r\n            TargetInfo info = new TargetInfo();\r\n            info.Type = 1;\r\n            info.Flags = 0;\r\n            info.Serial = 0;\r\n            info.X = pt.X;\r\n            info.Y = pt.Y;\r\n            info.Z = pt.Z;\r\n            info.Gfx = 0;\r\n\r\n            Target(info);\r\n        }\r\n\r\n        public static void Target(Point3D pt, int gfx)\r\n        {\r\n            TargetInfo info = new TargetInfo();\r\n            info.Type = 1;\r\n            info.Flags = 0;\r\n            info.Serial = 0;\r\n            info.X = pt.X;\r\n            info.Y = pt.Y;\r\n            info.Z = pt.Z;\r\n            info.Gfx = (ushort) (gfx & 0x3FFF);\r\n\r\n            Target(info);\r\n        }\r\n\r\n        public static void Target(Serial s)\r\n        {\r\n            TargetInfo info = new TargetInfo();\r\n            info.Type = 0;\r\n            info.Flags = 0;\r\n            info.Serial = s;\r\n\r\n            if (s.IsItem)\r\n            {\r\n                Item item = World.FindItem(s);\r\n                if (item != null)\r\n                {\r\n                    info.X = item.Position.X;\r\n                    info.Y = item.Position.Y;\r\n                    info.Z = item.Position.Z;\r\n                    info.Gfx = item.ItemID;\r\n                }\r\n            }\r\n            else if (s.IsMobile)\r\n            {\r\n                Mobile m = World.FindMobile(s);\r\n                if (m != null)\r\n                {\r\n                    info.X = m.Position.X;\r\n                    info.Y = m.Position.Y;\r\n                    info.Z = m.Position.Z;\r\n                    info.Gfx = m.Body;\r\n                }\r\n            }\r\n\r\n            Target(info);\r\n        }\r\n\r\n        public static void Target(object o)\r\n        {\r\n            if (o is Item)\r\n            {\r\n                Item item = (Item) o;\r\n                TargetInfo info = new TargetInfo();\r\n                info.Type = 0;\r\n                info.Flags = 0;\r\n                info.Serial = item.Serial;\r\n                info.X = item.Position.X;\r\n                info.Y = item.Position.Y;\r\n                info.Z = item.Position.Z;\r\n                info.Gfx = item.ItemID;\r\n                Target(info);\r\n            }\r\n            else if (o is Mobile)\r\n            {\r\n                Mobile m = (Mobile) o;\r\n                TargetInfo info = new TargetInfo();\r\n                info.Type = 0;\r\n                info.Flags = 0;\r\n                info.Serial = m.Serial;\r\n                info.X = m.Position.X;\r\n                info.Y = m.Position.Y;\r\n                info.Z = m.Position.Z;\r\n                info.Gfx = m.Body;\r\n                Target(info);\r\n            }\r\n            else if (o is Serial)\r\n            {\r\n                Target((Serial) o);\r\n            }\r\n            else if (o is TargetInfo)\r\n            {\r\n                Target((TargetInfo) o);\r\n            }\r\n        }\r\n\r\n        private static DateTime _lastFlagCheck = DateTime.UtcNow;\r\n        private static Serial _lastFlagCheckSerial;\r\n\r\n        public static void CheckTextFlags(Mobile m)\r\n        {\r\n            if (DateTime.UtcNow - _lastFlagCheck < TimeSpan.FromMilliseconds(250) && m.Serial == _lastFlagCheckSerial)\r\n                return;\r\n\r\n            if (IgnoreAgent.IsIgnored(m.Serial))\r\n            {\r\n                m.OverheadMessage(Config.GetInt(\"SysColor\"), \"[Ignored]\");\r\n            }\r\n\r\n            if (IsSmartTargetingEnabled())\r\n            {\r\n                bool harm = _lastHarmTarget != null && _lastHarmTarget.Serial == m.Serial;\r\n                bool bene = _lastBeneTarget != null && _lastBeneTarget.Serial == m.Serial;\r\n\r\n                if (harm)\r\n                    m.OverheadMessage(0x90, $\"[{Language.GetString(LocString.HarmfulTarget)}]\");\r\n                if (bene)\r\n                    m.OverheadMessage(0x3F, $\"[{Language.GetString(LocString.BeneficialTarget)}]\");\r\n            }\r\n\r\n            if (_lastTarget != null && _lastTarget.Serial == m.Serial)\r\n                m.OverheadMessage(0x3B2, $\"[{Language.GetString(LocString.LastTarget)}]\");\r\n\r\n            _lastFlagCheck = DateTime.UtcNow;\r\n            _lastFlagCheckSerial = m.Serial;\r\n        }\r\n\r\n        public static bool IsLastTarget(Mobile m)\r\n        {\r\n            if (m != null)\r\n            {\r\n                if (IsSmartTargetingEnabled())\r\n                {\r\n                    if (_lastHarmTarget != null && _lastHarmTarget.Serial == m.Serial)\r\n                        return true;\r\n                }\r\n                else\r\n                {\r\n                    if (_lastTarget != null && _lastTarget.Serial == m.Serial)\r\n                        return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public static bool IsBeneficialTarget(Mobile m)\r\n        {\r\n            if (m != null)\r\n            {\r\n                if (IsSmartTargetingEnabled())\r\n                {\r\n                    if (_lastBeneTarget != null && _lastBeneTarget.Serial == m.Serial)\r\n                        return true;\r\n                }\r\n                else\r\n                {\r\n                    if (_lastTarget != null && _lastTarget.Serial == m.Serial)\r\n                        return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public static bool IsHarmfulTarget(Mobile m)\r\n        {\r\n            if (m != null)\r\n            {\r\n                if (IsSmartTargetingEnabled())\r\n                {\r\n                    if (_lastHarmTarget != null && _lastHarmTarget.Serial == m.Serial)\r\n                        return true;\r\n                }\r\n                else\r\n                {\r\n                    if (_lastTarget != null && _lastTarget.Serial == m.Serial)\r\n                        return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public static void CheckLastTargetRange(Mobile m)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            if (_hasTarget && m != null && _lastTarget != null && m.Serial == _lastTarget.Serial &&\r\n                _queueTarget == LastTargetAction)\r\n            {\r\n                if (Config.GetBool(\"RangeCheckLT\") && Client.Instance.AllowBit(FeatureBit.RangeCheckLT))\r\n                {\r\n                    if (Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\r\n                    {\r\n                        if (_queueTarget())\r\n                            ClearQueue();\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static bool CheckHealPoisonTarg(uint targID, Serial ser)\r\n        {\r\n            if (World.Player == null)\r\n                return false;\r\n\r\n            if (targID == SpellTargetID && ser.IsMobile &&\r\n                (World.Player.LastSpell == Spell.ToID(1, 4) || World.Player.LastSpell == Spell.ToID(4, 5)) &&\r\n                Config.GetBool(\"BlockHealPoison\") && Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n            {\r\n                Mobile m = World.FindMobile(ser);\r\n\r\n                if (m != null && m.Poisoned)\r\n                {\r\n                    World.Player.SendMessage(MsgLevel.Warning, LocString.HealPoisonBlocked);\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        private static void TargetResponse(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            TargetInfo info = new TargetInfo\r\n            {\r\n                Type = p.ReadByte(),\r\n                TargID = p.ReadUInt32(),\r\n                Flags = p.ReadByte(),\r\n                Serial = p.ReadUInt32(),\r\n                X = p.ReadUInt16(),\r\n                Y = p.ReadUInt16(),\r\n                Z = p.ReadInt16(),\r\n                Gfx = p.ReadUInt16()\r\n            };\r\n\r\n            _clientTarget = false;\r\n\r\n            OverheadTargetMessage(info);\r\n\r\n            // check for cancel\r\n            if (info.X == 0xFFFF && info.X == 0xFFFF && (info.Serial <= 0 || info.Serial >= 0x80000000))\r\n            {\r\n                _hasTarget = false;\r\n                _fromGrabHotKey = false;\r\n\r\n                if (_intercept)\r\n                {\r\n                    args.Block = true;\r\n                    Timer.DelayedCallbackState(TimeSpan.Zero, m_OneTimeRespCallback, info).Start();\r\n                    EndIntercept();\r\n\r\n                    if (_previousID != 0)\r\n                    {\r\n                        _currentID = _previousID;\r\n                        _allowGround = _previousGround;\r\n                        _curFlags = _prevFlags;\r\n\r\n                        _previousID = 0;\r\n\r\n                        ResendTarget();\r\n                    }\r\n                }\r\n                else if (_filterCancel.Contains((uint) info.TargID) || info.TargID == LocalTargID)\r\n                {\r\n                    args.Block = true;\r\n                }\r\n\r\n                _filterCancel.Clear();\r\n                return;\r\n            }\r\n\r\n            ClearQueue();\r\n\r\n            if (_intercept)\r\n            {\r\n                if (info.TargID == LocalTargID)\r\n                {\r\n                    Timer.DelayedCallbackState(TimeSpan.Zero, m_OneTimeRespCallback, info).Start();\r\n\r\n                    _hasTarget = false;\r\n                    _fromGrabHotKey = false;\r\n                    args.Block = true;\r\n\r\n                    if (_previousID != 0)\r\n                    {\r\n                        _currentID = _previousID;\r\n                        _allowGround = _previousGround;\r\n                        _curFlags = _prevFlags;\r\n\r\n                        _previousID = 0;\r\n\r\n                        ResendTarget();\r\n                    }\r\n\r\n                    _filterCancel.Clear();\r\n\r\n                    return;\r\n                }\r\n                else\r\n                {\r\n                    EndIntercept();\r\n                }\r\n            }\r\n\r\n            _hasTarget = false;\r\n\r\n            if (CheckHealPoisonTarg(_currentID, info.Serial))\r\n            {\r\n                ResendTarget();\r\n                args.Block = true;\r\n            }\r\n\r\n            if (info.Serial != World.Player.Serial)\r\n            {\r\n                if (info.Serial.IsValid)\r\n                {\r\n                    // only let lasttarget be a non-ground target\r\n\r\n                    _lastTarget = info;\r\n                    if (info.Flags == 1)\r\n                        _lastHarmTarget = info;\r\n                    else if (info.Flags == 2)\r\n                        _lastBeneTarget = info;\r\n\r\n                    LastTargetChanged();\r\n                    LastBeneficialTargetChanged();\r\n                    LastHarmfulTargetChanged();\r\n                }\r\n\r\n                _lastGroundTarget = info; // ground target is the true last target\r\n\r\n                if (Macros.MacroManager.AcceptActions)\r\n                    MacroManager.Action(new AbsoluteTargetAction(info));\r\n\r\n                ScriptManager.AddToScript(info.Serial == Serial.Zero\r\n                    ? $\"target 0x0 {info.X} {info.Y} {info.Z}\"\r\n                    : $\"target {info.Serial}\");\r\n\r\n\r\n                if (ScriptManager.Recording)\r\n                {\r\n                    if (info.Serial == Serial.Zero)\r\n                    {\r\n                    }\r\n                    else\r\n                    {\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                KeyData hk = HotKey.Get((int)LocString.TargetSelf);\r\n\r\n                if (MacroManager.AcceptActions)\r\n                {\r\n                    if (hk != null)\r\n                    {\r\n                        MacroManager.Action(new HotKeyAction(hk));\r\n                    }\r\n                    else\r\n                    {\r\n                        MacroManager.Action(new AbsoluteTargetAction(info));\r\n                    }\r\n                }\r\n\r\n                ScriptManager.AddToScript(hk != null ? \"target 'self'\" : $\"target {info.Serial}\");\r\n            }\r\n\r\n            if (World.Player.LastSpell == 52 && !GateTimer.Running)\r\n            {\r\n                GateTimer.Start();\r\n            }\r\n\r\n            _filterCancel.Clear();\r\n        }\r\n\r\n        private static void NewTarget(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            bool prevAllowGround = _allowGround;\r\n            uint prevID = _currentID;\r\n            byte prevFlags = _curFlags;\r\n            bool prevClientTarget = _clientTarget;\r\n\r\n            _allowGround = p.ReadBoolean(); // allow ground\r\n            _currentID = p.ReadUInt32(); // target uid\r\n            _curFlags = p.ReadByte(); // flags\r\n            // the rest of the packet is 0s\r\n\r\n            // check for a server cancel command\r\n            if (!_allowGround && _currentID == 0 && _curFlags == 3)\r\n            {\r\n                _hasTarget = false;\r\n                _fromGrabHotKey = false;\r\n\r\n                _clientTarget = false;\r\n                if (_intercept)\r\n                {\r\n                    EndIntercept();\r\n                    World.Player.SendMessage(MsgLevel.Error, LocString.OTTCancel);\r\n                }\r\n\r\n                return;\r\n            }\r\n\r\n            if (Spell.LastCastTime + TimeSpan.FromSeconds(3.0) > DateTime.UtcNow &&\r\n                Spell.LastCastTime + TimeSpan.FromSeconds(0.5) <= DateTime.UtcNow && SpellTargetID == 0)\r\n                SpellTargetID = _currentID;\r\n\r\n            _hasTarget = true;\r\n            _clientTarget = false;\r\n\r\n            if (_queueTarget == null && Macros.MacroManager.AcceptActions &&\r\n                MacroManager.Action(new WaitForTargetAction()))\r\n            {\r\n                args.Block = true;\r\n            }\r\n            else if (_queueTarget == null && ScriptManager.AddToScript(\"waitfortarget\"))\r\n            {\r\n                //args.Block = true;\r\n            }\r\n            else if (_queueTarget != null && _queueTarget())\r\n            {\r\n                ClearQueue();\r\n                args.Block = true;\r\n            }\r\n\r\n            if (args.Block)\r\n            {\r\n                if (prevClientTarget)\r\n                {\r\n                    _allowGround = prevAllowGround;\r\n                    _currentID = prevID;\r\n                    _curFlags = prevFlags;\r\n\r\n                    _clientTarget = true;\r\n\r\n                    if (!_intercept)\r\n                        CancelClientTarget();\r\n                }\r\n            }\r\n            else\r\n            {\r\n                _clientTarget = true;\r\n\r\n                if (_intercept)\r\n                {\r\n                    if (_onCancel != null)\r\n                        _onCancel();\r\n                    EndIntercept();\r\n                    World.Player.SendMessage(MsgLevel.Error, LocString.OTTCancel);\r\n\r\n                    _filterCancel.Add((uint) prevID);\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void ResendTarget()\r\n        {\r\n            if (!_clientTarget || !_hasTarget)\r\n            {\r\n                CancelClientTarget();\r\n                _clientTarget = _hasTarget = true;\r\n                Client.Instance.SendToClient(new Target(_currentID, _allowGround, _curFlags));\r\n            }\r\n        }\r\n\r\n        private static TargetInfo _lastOverheadMessageTarget = new TargetInfo();\r\n\r\n        public static void OverheadTargetMessage(TargetInfo info)\r\n        {\r\n            if (info == null)\r\n                return;\r\n\r\n            if (Config.GetBool(\"ShowAttackTargetNewOnly\") && info.Serial == _lastOverheadMessageTarget.Serial)\r\n                return;\r\n\r\n            Mobile m = null;\r\n\r\n            if (Config.GetBool(\"ShowAttackTargetOverhead\") && info.Serial != 0 && info.Serial.IsMobile)\r\n            {\r\n                m = World.FindMobile(info.Serial);\r\n\r\n                if (m == null)\r\n                    return;\r\n\r\n                World.Player.OverheadMessage(FriendsManager.IsFriend(m.Serial) ? 63 : m.GetNotorietyColorInt(),\r\n                    $\"Target: {m.Name}\");\r\n            }\r\n\r\n            if (Config.GetBool(\"ShowTextTargetIndicator\") && info.Serial != 0 && info.Serial.IsMobile)\r\n            {\r\n                // lets not look it up again they had the previous feature enabled\r\n                if (m == null)\r\n                    m = World.FindMobile(info.Serial);\r\n\r\n                if (m == null)\r\n                    return;\r\n\r\n                m.OverheadMessage(Config.GetInt(\"TargetIndicatorHue\"),\r\n                    Config.GetString(\"TargetIndicatorFormat\").Replace(\"{name}\", m.Name));\r\n            }\r\n\r\n            _lastOverheadMessageTarget = info;\r\n        }\r\n\r\n        private static bool IsSmartTargetingEnabled()\r\n        {\r\n            return Config.GetBool(\"SmartLastTarget\") && Client.Instance.AllowBit(FeatureBit.SmartLT);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/TargetingClosest.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\nusing Assistant.Core;\nusing Assistant.Filters;\nusing Assistant.Scripts;\n\nnamespace Assistant\n{\n    public partial class Targeting\n    {\n        private static void InitClosestTargets()\n        {\n            HotKey.Add(HKCategory.Targets, LocString.TargClosest, TargetClosest);\n\n            HotKey.Add(HKCategory.Targets, LocString.TargClosestFriend, TargetClosestFriend);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.TargCloseRed,\n                TargetCloseRed);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.TargCloseRedHumanoid,\n                TargetCloseRedHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.TargCloseRedMonster,\n                TargetCloseRedMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.TargCloseNFriend,\n                TargetCloseNonFriendly);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.TargClosestNFriendlyHuman,\n                TargetCloseNonFriendlyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.TargClosestNFriendlyMonster,\n                TargetCloseNonFriendlyMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.TargCloseFriend,\n                TargetCloseFriendly);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.TargClosestFriendlyHuman,\n                TargetCloseFriendlyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.TargClosestFriendlyMonster,\n                TargetCloseFriendlyMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.TargCloseBlue,\n                TargetCloseInnocent);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.TargCloseInnocentHuman,\n                TargetCloseInnocentHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.TargClosestInnocentMonster,\n                TargetCloseInnocentMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.TargCloseGrey,\n                TargetCloseGrey);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.TargCloseGreyHuman,\n                TargetCloseGreyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.TargCloseGreyMonster,\n                TargetCloseGreyMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.TargCloseCriminal,\n                TargetCloseCriminal);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.TargCloseCriminalHuman,\n                TargetCloseCriminalHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.TargClosestCriminalMonster,\n                TargetCloseCriminalMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.TargCloseEnemy,\n                TargetCloseEnemy);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.TargCloseEnemyHuman,\n                TargetCloseEnemyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.TargCloseEnemyMonster,\n                TargetCloseEnemyMonster);\n        }\n\n\n        public static void TargetCloseNonFriendly()\n        {\n            ClosestTarget((int) TargetType.Attackable, (int) TargetType.Criminal, (int) TargetType.Enemy,\n                (int) TargetType.Murderer);\n        }\n\n        public static void TargetCloseNonFriendlyHumanoid()\n        {\n            ClosestHumanoidTarget((int) TargetType.Attackable, (int) TargetType.Criminal, (int) TargetType.Enemy,\n                (int) TargetType.Murderer);\n        }\n\n        public static void TargetCloseNonFriendlyMonster()\n        {\n            ClosestMonsterTarget((int) TargetType.Attackable, (int) TargetType.Criminal, (int) TargetType.Enemy,\n                (int) TargetType.Murderer);\n        }\n\n        public static void TargetCloseFriendly()\n        {\n            ClosestTarget((int) TargetType.Invalid, (int) TargetType.Innocent, (int) TargetType.GuildAlly);\n        }\n\n        public static void TargetCloseFriendlyHumanoid()\n        {\n            ClosestHumanoidTarget((int) TargetType.Invalid, (int) TargetType.Innocent, (int) TargetType.GuildAlly);\n        }\n\n        public static void TargetCloseFriendlyMonster()\n        {\n            ClosestMonsterTarget((int) TargetType.Invalid, (int) TargetType.Innocent, (int) TargetType.GuildAlly);\n        }\n\n        public static void TargetCloseEnemy()\n        {\n            ClosestTarget((int) TargetType.Enemy);\n        }\n\n        public static void TargetCloseEnemyHumanoid()\n        {\n            ClosestHumanoidTarget((int) TargetType.Enemy);\n        }\n\n        public static void TargetCloseEnemyMonster()\n        {\n            ClosestMonsterTarget((int) TargetType.Enemy);\n        }\n\n        public static void TargetCloseRed()\n        {\n            ClosestTarget((int) TargetType.Murderer);\n        }\n\n        public static void TargetCloseRedMonster()\n        {\n            ClosestMonsterTarget((int) TargetType.Murderer);\n        }\n\n        public static void TargetCloseRedHumanoid()\n        {\n            ClosestHumanoidTarget((int) TargetType.Murderer);\n        }\n\n        public static void TargetCloseGrey()\n        {\n            ClosestTarget((int) TargetType.Attackable, (int) TargetType.Criminal);\n        }\n\n        public static void TargetCloseGreyMonster()\n        {\n            ClosestMonsterTarget((int) TargetType.Attackable, (int) TargetType.Criminal);\n        }\n\n        public static void TargetCloseGreyHumanoid()\n        {\n            ClosestHumanoidTarget((int) TargetType.Attackable, (int) TargetType.Criminal);\n        }\n\n        public static void TargetCloseCriminal()\n        {\n            ClosestTarget((int) TargetType.Criminal);\n        }\n\n        public static void TargetCloseCriminalHumanoid()\n        {\n            ClosestHumanoidTarget((int) TargetType.Criminal);\n        }\n\n        public static void TargetCloseCriminalMonster()\n        {\n            ClosestHumanoidTarget((int) TargetType.Criminal);\n        }\n\n        public static void TargetCloseInnocent()\n        {\n            ClosestTarget((int) TargetType.Innocent);\n        }\n\n        public static void TargetCloseInnocentHumanoid()\n        {\n            ClosestHumanoidTarget((int) TargetType.Innocent);\n        }\n\n        public static void TargetCloseInnocentMonster()\n        {\n            ClosestMonsterTarget((int) TargetType.Innocent);\n        }\n\n        public static void TargetClosestFriend()\n        {\n            ClosestFriendTarget();\n        }\n\n        public static void TargetClosest()\n        {\n            ClosestTarget();\n        }\n\n        public static void ClosestTarget(params int[] noto)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.ClosestTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n                if ((!FriendsManager.IsFriend(m.Serial) || noto.Length > 0 && noto[0] == 0) &&\n                    !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                {\n                    for (var i = 0; i < noto.Length; i++)\n                        if (noto[i] == m.Notoriety)\n                        {\n                            list.Add(m);\n                            break;\n                        }\n\n                    if (noto.Length == 0)\n                        list.Add(m);\n                }\n\n            Mobile closest = null;\n            var closestDist = double.MaxValue;\n\n            foreach (var m in list)\n            {\n                var dist = Utility.DistanceSqrt(m.Position, World.Player.Position);\n\n                if (dist < closestDist || closest == null)\n                {\n                    closestDist = dist;\n                    closest = m;\n                }\n            }\n\n            if (closest != null)\n            {\n                SetLastTargetTo(closest);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n\n        public static void ClosestHumanoidTarget(params int[] noto)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.ClosestTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n            {\n                if (m.Body != 0x0190 && m.Body != 0x0191 && m.Body != 0x025D && m.Body != 0x025E)\n                    continue;\n\n                if ((!FriendsManager.IsFriend(m.Serial) || noto.Length > 0 && noto[0] == 0) &&\n                    !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                {\n                    for (var i = 0; i < noto.Length; i++)\n                        if (noto[i] == m.Notoriety)\n                        {\n                            list.Add(m);\n                            break;\n                        }\n\n                    if (noto.Length == 0)\n                        list.Add(m);\n                }\n            }\n\n            Mobile closest = null;\n            var closestDist = double.MaxValue;\n\n            foreach (var m in list)\n            {\n                var dist = Utility.DistanceSqrt(m.Position, World.Player.Position);\n\n                if (dist < closestDist || closest == null)\n                {\n                    closestDist = dist;\n                    closest = m;\n                }\n            }\n\n            if (closest != null)\n            {\n                SetLastTargetTo(closest);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n\n        public static void ClosestMonsterTarget(params int[] noto)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.ClosestTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n            {\n                if (!m.IsMonster)\n                    continue;\n\n                if ((!FriendsManager.IsFriend(m.Serial) || noto.Length > 0 && noto[0] == 0) &&\n                    !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                {\n                    for (var i = 0; i < noto.Length; i++) \n                        if (noto[i] == m.Notoriety)\n                        {\n                            list.Add(m);\n                            break;\n                        }\n\n                    if (noto.Length == 0)\n                        list.Add(m);\n                }\n            }\n\n            Mobile closest = null;\n            var closestDist = double.MaxValue;\n\n            foreach (var m in list)\n            {\n                var dist = Utility.DistanceSqrt(m.Position, World.Player.Position);\n\n                if (dist < closestDist || closest == null)\n                {\n                    closestDist = dist;\n                    closest = m;\n                }\n            }\n\n            if (closest != null)\n            {\n                SetLastTargetTo(closest);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n\n        public static void ClosestFriendTarget()\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.ClosestTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n            {\n                if (FriendsManager.IsFriend(m.Serial) && !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                {\n                    list.Add(m);\n                }\n            }                \n\n            Mobile closest = null;\n            var closestDist = double.MaxValue;\n\n            foreach (var m in list)\n            {\n                var dist = Utility.DistanceSqrt(m.Position, World.Player.Position);\n\n                if (dist < closestDist || closest == null)\n                {\n                    closestDist = dist;\n                    closest = m;\n                }\n            }\n\n            if (closest != null)\n            {\n                SetLastTargetTo(closest);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/TargetingNextPrevious.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing Assistant.Core;\nusing Assistant.Filters;\nusing Assistant.Scripts;\n\nnamespace Assistant\n{\n    public partial class Targeting\n    {\n        /// <summary>\n        ///     Index used to keep track of the current Next/Prev target\n        /// </summary>\n        private static int _nextPrevTargetIndex;\n\n        private static void InitNextPrevTargets()\n        {\n            //Next targets\n            HotKey.Add(HKCategory.Targets, LocString.NextTarget, NextTarget);\n            HotKey.Add(HKCategory.Targets, LocString.NextTargetFriend, NextTargetFriend);\n            HotKey.Add(HKCategory.Targets, LocString.NextTargetNonFriendly, NextTargetNonFriend);\n\n            // Next humanoids\n            HotKey.Add(HKCategory.Targets, LocString.NextTargetHumanoid, NextTargetHumanoid);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.NextTargetEnemyHumanoid,\n                NextTargetEnemyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.NextTargetCriminalHumanoid,\n                NextTargetCriminalHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.NextTargetMurdererHumanoid,\n                NextTargetMurdererHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.NextTargetInnocentHumanoid,\n                NextTargetInnocentHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.NextTargetFriendlyHumanoid,\n                NextTargetFriendlyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.NextTargetFriendly,\n                NextTargetFriendly);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.NextTargetGreyHumanoid,\n                NextTargetGreyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.NextTargetNonFriendlyHumanoid,\n                NextTargetNonFriendlyHumanoid);\n\n            // Next monsters\n            HotKey.Add(HKCategory.Targets, LocString.NextTargetMonster, NextTargetMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.NextTargetEnemyMonster,\n                NextTargetEnemyMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.NextTargetCriminalMonster,\n                NextTargetCriminalMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.NextTargetMurdererMonster,\n                NextTargetMurdererMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.NextTargetInnocentMonster,\n                NextTargetInnocentMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.NextTargetFriendlyMonster,\n                NextTargetFriendlyMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.NextTargetGreyMonster,\n                NextTargetGreyMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.NextTargetNonFriendlyMonster,\n                NextTargetNonFriendlyMonster);\n\n            //Previous targets\n            HotKey.Add(HKCategory.Targets, LocString.PrevTarget, PrevTarget);\n            HotKey.Add(HKCategory.Targets, LocString.PrevTargetNonFriendly, PrevTargetNonFriend);\n\n            HotKey.Add(HKCategory.Targets, LocString.PrevTargetHumanoid, PrevTargetHumanoid);\n            HotKey.Add(HKCategory.Targets, LocString.PrevTargetMonster, PrevTargetMonster);\n            HotKey.Add(HKCategory.Targets, LocString.PrevTargetFriend, PrevTargetFriend);\n\n            // Previous humanoids\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.PrevTargetEnemyHumanoid,\n                PrevTargetEnemyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.PrevTargetFriendlyHumanoid,\n                PrevTargetFriendlyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.PrevTargetFriendly,\n                PrevTargetFriendly);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.PrevTargetGreyHumanoid,\n                PrevTargetGreyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.PrevTargetNonFriendlyHumanoid,\n                PrevTargetNonFriendlyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.PrevTargetCriminalHumanoid,\n                PrevTargetCriminalHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.PrevTargetMurdererHumanoid,\n                PrevTargetMurdererHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.PrevTargetInnocentHumanoid,\n                PrevTargetInnocentHumanoid);\n\n            // Previous monsters\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.PrevTargetEnemyMonster,\n                PrevTargetEnemyMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.PrevTargetFriendlyMonster,\n                PrevTargetFriendlyMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.PrevTargetGreyMonster,\n                PrevTargetGreyMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.PrevTargetNonFriendlyMonster,\n                PrevTargetNonFriendlyMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.PrevTargetCriminalMonster,\n                PrevTargetCriminalMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.PrevTargetMurdererMonster,\n                PrevTargetMurdererMonster);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.PrevTargetInnocentMonster,\n                PrevTargetInnocentMonster);\n        }\n\n        public static bool IsNextPrevFriend(Mobile mobile)\n        {\n            return Config.GetBool(\"NextPrevTargetIgnoresFriends\") && FriendsManager.IsFriend(mobile.Serial);\n        }\n\n        /// <summary>\n        ///     Handles the common Next/Prev logic based on a list of targets passed in already filtered by the calling\n        ///     functions conditions.\n        /// </summary>\n        /// <param name=\"targets\">The list of targets (already filtered)</param>\n        /// <param name=\"nextTarget\">next target true, previous target false</param>\n        /// <param name=\"isFriend\">Indicates this was the Next/Prev Friend hot key</param>\n        /// <param name=\"isFriendly\"></param>\n        /// <param name=\"isNonFriendly\"></param>\n        public static void NextPrevTarget(List<Mobile> targets, bool nextTarget, bool isFriend = false,\n            bool isFriendly = false, bool isNonFriendly = false)\n        {\n            if (targets.Count <= 0)\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n                return;\n            }\n\n            if (Config.GetBool(\"NextPrevAlphabetical\"))\n            {\n                targets = targets.OrderBy(m => m.Name).ToList();\n            }\n\n            Mobile mobile = null, old = World.FindMobile(_lastTarget?.Serial ?? Serial.Zero);\n            var target = new TargetInfo();\n\n            // Loop through 3 times and break out if you can't get a target for some reason\n            for (var i = 0; i < 3; i++)\n            {\n                if (nextTarget)\n                {\n                    _nextPrevTargetIndex++;\n\n                    if (_nextPrevTargetIndex >= targets.Count)\n                        _nextPrevTargetIndex = 0;\n                }\n                else\n                {\n                    _nextPrevTargetIndex--;\n\n                    if (_nextPrevTargetIndex < 0)\n                        _nextPrevTargetIndex = targets.Count - 1;\n                }\n\n                try\n                {\n                    mobile = targets[_nextPrevTargetIndex];\n                }\n                catch\n                {\n                    mobile = null;\n                }\n\n                if (mobile != null && mobile != World.Player && mobile != old) break;\n\n                mobile = null;\n            }\n\n            if (mobile == null)\n                mobile = old;\n\n            if (mobile == null)\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n                return;\n            }\n\n            _lastGroundTarget = _lastTarget = target;\n\n            if (IsSmartTargetingEnabled())\n            {\n                if (Config.GetBool(\"OnlyNextPrevBeneficial\") && isFriend ||\n                    Config.GetBool(\"FriendlyBeneficialOnly\") && isFriendly)\n                {\n                    _lastBeneTarget = target;\n                }\n                else if (Config.GetBool(\"OnlyNextPrevBeneficial\") && !isFriend ||\n                         Config.GetBool(\"NonFriendlyHarmfulOnly\") && isNonFriendly)\n                {\n                    _lastHarmTarget = target;\n                }\n                else\n                {\n                    _lastBeneTarget = _lastHarmTarget = target;\n                }\n            }\n            else\n            {\n                _lastBeneTarget = _lastHarmTarget = target;\n            }\n\n            if (_hasTarget)\n                target.Flags = _curFlags;\n            else\n                target.Type = 0;\n\n            target.Gfx = mobile.Body;\n            target.Serial = mobile.Serial;\n            target.X = mobile.Position.X;\n            target.Y = mobile.Position.Y;\n            target.Z = mobile.Position.Z;\n\n            if (!isFriend || Config.GetBool(\"HighlightFriend\"))\n            {\n                Client.Instance.SendToClient(new ChangeCombatant(mobile));\n                _lastCombatant = mobile.Serial;\n            }\n\n            World.Player.SendMessage(MsgLevel.Force, LocString.NewTargSet);\n\n            OverheadTargetMessage(target);\n\n            ScriptManager.TargetFound = true;\n        }\n\n        public static void NextTarget()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => !IsNextPrevFriend(x) && !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetHumanoid()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsHuman && !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetEnemyHumanoid()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsHuman && x.Notoriety == (int) TargetType.Enemy && !IsNextPrevFriend(x) && !x.Blessed &&\n                    !x.IsGhost && x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetEnemyMonster()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsMonster && x.Notoriety == (int) TargetType.Enemy && !IsNextPrevFriend(x) && !x.Blessed &&\n                    !x.IsGhost && x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetMonster()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsMonster && !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost &&\n                    x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetFriend()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    FriendsManager.IsFriend(x.Serial) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial)\n                .ToList();\n\n            NextPrevTarget(mobiles, true, true);\n        }\n\n        public static void NextTargetNonFriend()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => (x.Notoriety == (int) TargetType.Attackable ||\n                                          x.Notoriety == (int) TargetType.Criminal ||\n                                          x.Notoriety == (int) TargetType.Enemy ||\n                                          x.Notoriety == (int) TargetType.Murderer) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)\n                ).ToList();\n\n            NextPrevTarget(mobiles, true, false, false, true);\n        }\n\n        public static void PrevTarget()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => !IsNextPrevFriend(x) && !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetHumanoid()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsHuman && !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetEnemyHumanoid()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsHuman && x.Notoriety == (int) TargetType.Enemy && !IsNextPrevFriend(x) && !x.Blessed &&\n                    !x.IsGhost && x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetEnemyMonster()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsMonster && x.Notoriety == (int) TargetType.Enemy && !IsNextPrevFriend(x) && !x.Blessed &&\n                    !x.IsGhost && x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetMonster()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsMonster && !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost &&\n                    x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetFriend()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                FriendsManager.IsFriend(x.Serial) && !x.Blessed && !x.IsGhost &&\n                x.Serial != World.Player.Serial).ToList();\n\n            NextPrevTarget(mobiles, false, true);\n        }\n\n        public static void NextTargetCriminalHumanoid()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsHuman && x.Notoriety == (int) TargetType.Criminal && !IsNextPrevFriend(x) && !x.Blessed &&\n                    !x.IsGhost && x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetMurdererHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && x.Notoriety == (int) TargetType.Murderer && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetInnocentHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && x.Notoriety == (int) TargetType.Innocent && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetCriminalMonster()\n        {\n            var mobiles = World.MobilesInRange().Where(x =>\n                    x.IsMonster && x.Notoriety == (int) TargetType.Criminal && !IsNextPrevFriend(x) && !x.Blessed &&\n                    !x.IsGhost && x.Serial != World.Player.Serial && !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetMurdererMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && x.Notoriety == (int) TargetType.Murderer && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetInnocentMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && x.Notoriety == (int) TargetType.Innocent && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void PrevTargetCriminalHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && x.Notoriety == (int) TargetType.Criminal && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetCriminalMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && x.Notoriety == (int) TargetType.Criminal && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetMurdererHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && x.Notoriety == (int) TargetType.Murderer && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetMurdererMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && x.Notoriety == (int) TargetType.Murderer && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetInnocentHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && x.Notoriety == (int) TargetType.Innocent && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetInnocentMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && x.Notoriety == (int) TargetType.Innocent && !IsNextPrevFriend(x) &&\n                            !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)).ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void NextTargetFriendlyHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && (x.Notoriety == (int) TargetType.Innocent ||\n                                          x.Notoriety == (int) TargetType.Invalid ||\n                                          x.Notoriety == (int) TargetType.GuildAlly) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true, false, true);\n        }\n\n        public static void NextTargetFriendly()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => (x.Notoriety == (int)TargetType.Innocent ||\n                                          x.Notoriety == (int)TargetType.Invalid ||\n                                          x.Notoriety == (int)TargetType.GuildAlly) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true, false, true);\n        }\n\n        public static void NextTargetFriendlyMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && (x.Notoriety == (int) TargetType.Innocent ||\n                                            x.Notoriety == (int) TargetType.Invalid ||\n                                            x.Notoriety == (int) TargetType.GuildAlly) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true, false, true);\n        }\n\n        public static void NextTargetGreyHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && (x.Notoriety == (int) TargetType.Attackable ||\n                                          x.Notoriety == (int) TargetType.Criminal) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetGreyMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && (x.Notoriety == (int) TargetType.Attackable ||\n                                            x.Notoriety == (int) TargetType.Criminal) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, true);\n        }\n\n        public static void NextTargetNonFriendlyHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && (x.Notoriety == (int) TargetType.Attackable ||\n                                          x.Notoriety == (int) TargetType.Criminal ||\n                                          x.Notoriety == (int) TargetType.Enemy ||\n                                          x.Notoriety == (int) TargetType.Murderer) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)\n                ).ToList();\n\n            NextPrevTarget(mobiles, true, false, false, true);\n        }\n\n        public static void NextTargetNonFriendlyMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && (x.Notoriety == (int) TargetType.Attackable ||\n                                            x.Notoriety == (int) TargetType.Criminal ||\n                                            x.Notoriety == (int) TargetType.Enemy ||\n                                            x.Notoriety == (int) TargetType.Murderer) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial)\n                ).ToList();\n\n            NextPrevTarget(mobiles, true, false, false, true);\n        }\n\n        public static void PrevTargetFriendlyHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && (x.Notoriety == (int) TargetType.Innocent ||\n                                          x.Notoriety == (int) TargetType.Invalid ||\n                                          x.Notoriety == (int) TargetType.GuildAlly) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false, false, true);\n        }\n\n        public static void PrevTargetFriendly()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => (x.Notoriety == (int)TargetType.Innocent ||\n                                          x.Notoriety == (int)TargetType.Invalid ||\n                                          x.Notoriety == (int)TargetType.GuildAlly) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false, false, true);\n        }\n\n        public static void PrevTargetFriendlyMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && (x.Notoriety == (int) TargetType.Innocent ||\n                                            x.Notoriety == (int) TargetType.Invalid ||\n                                            x.Notoriety == (int) TargetType.GuildAlly) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false, false, true);\n        }\n\n        public static void PrevTargetGreyHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && (x.Notoriety == (int) TargetType.Attackable ||\n                                          x.Notoriety == (int) TargetType.Criminal) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetGreyMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && (x.Notoriety == (int) TargetType.Attackable ||\n                                            x.Notoriety == (int) TargetType.Criminal) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false);\n        }\n\n        public static void PrevTargetNonFriendlyHumanoid()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && (x.Notoriety == (int) TargetType.Attackable ||\n                                          x.Notoriety == (int) TargetType.Criminal ||\n                                          x.Notoriety == (int) TargetType.Enemy ||\n                                          x.Notoriety == (int) TargetType.Murderer) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false, false, false, true);\n        }\n\n        public static void PrevTargetNonFriendlyMonster()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && (x.Notoriety == (int) TargetType.Attackable ||\n                                            x.Notoriety == (int) TargetType.Criminal ||\n                                            x.Notoriety == (int) TargetType.Enemy ||\n                                            x.Notoriety == (int) TargetType.Murderer) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false, false, false, true);\n        }\n\n        public static void PrevTargetNonFriend()\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => (x.Notoriety == (int) TargetType.Attackable ||\n                                            x.Notoriety == (int) TargetType.Criminal ||\n                                            x.Notoriety == (int) TargetType.Enemy ||\n                                            x.Notoriety == (int) TargetType.Murderer) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, false, false, false, true);\n        }\n\n        public static void NextPrevTargetNotoriety(bool next, params int[] notoriety)\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => notoriety.Contains(x.Notoriety) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, next);\n        }\n\n        public static void NextPrevTargetNotorietyMonster(bool next, params int[] notoriety)\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsMonster && notoriety.Contains(x.Notoriety) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, next);\n        }\n\n        public static void NextPrevTargetNotorietyHumanoid(bool next, params int[] notoriety)\n        {\n            var mobiles = World.MobilesInRange()\n                .Where(x => x.IsHuman && notoriety.Contains(x.Notoriety) &&\n                            !IsNextPrevFriend(x) && !x.Blessed && !x.IsGhost && x.Serial != World.Player.Serial &&\n                            !TargetFilterManager.IsFilteredTarget(x.Serial))\n                .ToList();\n\n            NextPrevTarget(mobiles, next);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/TargetingRandom.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\nusing Assistant.Core;\nusing Assistant.Filters;\nusing Assistant.Scripts;\n\nnamespace Assistant\n{\n    public partial class Targeting\n    {\n        private static void InitRandomTarget()\n        {\n            HotKey.Add(HKCategory.Targets, LocString.TargetRandom, TargetRandAnyone);\n\n            HotKey.Add(HKCategory.Targets, LocString.TargRandomFriend, TargetRandFriend);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.TargRandRed,\n                TargetRandRed);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.TargRandomRedHuman,\n                TargetRandRedHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetMurderer, LocString.TargRandomRedMonster,\n                TargetRandRedMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.TargRandNFriend,\n                TargetRandNonFriendly);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.TargRandomNFriendlyHuman,\n                TargetRandNonFriendlyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetNonFriendly, LocString.TargRandomNFriendlyMonster,\n                TargetRandNonFriendlyMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.TargRandFriend,\n                TargetRandFriendly);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.TargRandomFriendlyHuman,\n                TargetRandFriendlyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetFriendly, LocString.TargRandomFriendlyMonster,\n                TargetRandFriendlyMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.TargRandBlue,\n                TargetRandInnocent);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.TargRandInnocentHuman,\n                TargetRandInnocentHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetInnocent, LocString.TargRandomInnocentMonster,\n                TargetRandInnocentMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.TargRandGrey, TargetRandGrey);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.TargRandGreyHuman,\n                TargetRandGreyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetGrey, LocString.TargRandGreyMonster,\n                TargetRandGreyMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.TargRandEnemy,\n                TargetRandEnemy);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.TargRandEnemyHuman,\n                TargetRandEnemyHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetEnemy, LocString.TargRandEnemyMonster,\n                TargetRandEnemyMonster);\n\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.TargRandCriminal,\n                TargetRandCriminal);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.TargRandCriminalHuman,\n                TargetRandCriminalHumanoid);\n            HotKey.Add(HKCategory.Targets, HKSubCat.SubTargetCriminal, LocString.TargRandomCriminalMonster,\n                TargetRandCriminalMonster);\n        }\n\n\n        public static void TargetRandNonFriendly()\n        {\n            RandomTarget((int) TargetType.Attackable, (int) TargetType.Criminal, (int) TargetType.Enemy,\n                (int) TargetType.Murderer);\n        }\n\n        public static void TargetRandNonFriendlyHumanoid()\n        {\n            RandomHumanoidTarget((int) TargetType.Attackable, (int) TargetType.Criminal, (int) TargetType.Enemy,\n                (int) TargetType.Murderer);\n        }\n\n        public static void TargetRandNonFriendlyMonster()\n        {\n            RandomMonsterTarget((int) TargetType.Attackable, (int) TargetType.Criminal, (int) TargetType.Enemy,\n                (int) TargetType.Murderer);\n        }\n\n        public static void TargetRandFriendly()\n        {\n            RandomTarget((int) TargetType.Invalid, (int) TargetType.Innocent, (int) TargetType.GuildAlly);\n        }\n\n        public static void TargetRandFriendlyHumanoid()\n        {\n            RandomHumanoidTarget((int) TargetType.Invalid, (int) TargetType.Innocent, (int) TargetType.GuildAlly);\n        }\n\n        public static void TargetRandFriendlyMonster()\n        {\n            RandomMonsterTarget((int) TargetType.Invalid, (int) TargetType.Innocent, (int) TargetType.GuildAlly);\n        }\n\n        public static void TargetRandEnemy()\n        {\n            RandomTarget((int) TargetType.Enemy);\n        }\n\n        public static void TargetRandEnemyMonster()\n        {\n            RandomMonsterTarget((int) TargetType.Enemy);\n        }\n\n        public static void TargetRandEnemyHumanoid()\n        {\n            RandomHumanoidTarget((int) TargetType.Enemy);\n        }\n\n        public static void TargetRandRed()\n        {\n            RandomTarget((int) TargetType.Murderer);\n        }\n\n        public static void TargetRandRedHumanoid()\n        {\n            RandomHumanoidTarget((int) TargetType.Murderer);\n        }\n\n        public static void TargetRandRedMonster()\n        {\n            RandomMonsterTarget((int) TargetType.Murderer);\n        }\n\n        public static void TargetRandGrey()\n        {\n            RandomTarget((int) TargetType.Attackable, (int) TargetType.Criminal);\n        }\n\n        public static void TargetRandGreyMonster()\n        {\n            RandomMonsterTarget((int) TargetType.Attackable, (int) TargetType.Criminal);\n        }\n\n        public static void TargetRandGreyHumanoid()\n        {\n            RandomHumanoidTarget((int) TargetType.Attackable, (int) TargetType.Criminal);\n        }\n\n        public static void TargetRandCriminal()\n        {\n            RandomTarget((int) TargetType.Criminal);\n        }\n\n        public static void TargetRandCriminalHumanoid()\n        {\n            RandomHumanoidTarget((int) TargetType.Criminal);\n        }\n\n        public static void TargetRandCriminalMonster()\n        {\n            RandomMonsterTarget((int) TargetType.Criminal);\n        }\n\n        public static void TargetRandInnocent()\n        {\n            RandomTarget((int) TargetType.Innocent);\n        }\n\n        public static void TargetRandInnocentHumanoid()\n        {\n            RandomHumanoidTarget((int) TargetType.Innocent);\n        }\n\n        public static void TargetRandInnocentMonster()\n        {\n            RandomMonsterTarget((int) TargetType.Innocent);\n        }\n\n        public static void TargetRandFriend()\n        {\n            RandomFriendTarget();\n        }\n\n        public static void TargetRandAnyone()\n        {\n            RandomTarget();\n        }\n\n        public static void RandomTarget(params int[] noto)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.RandomTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n                if ((!FriendsManager.IsFriend(m.Serial) || noto.Length > 0 && noto[0] == 0) &&\n                    !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                {\n                    for (var i = 0; i < noto.Length; i++)\n                        if (noto[i] == m.Notoriety)\n                        {\n                            list.Add(m);\n                            break;\n                        }\n\n                    if (noto.Length == 0)\n                        list.Add(m);\n                }\n\n            if (list.Count > 0)\n            {\n                SetLastTargetTo(list[Utility.Random(list.Count)]);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n\n        public static void RandomHumanoidTarget(params int[] noto)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.RandomTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n            {\n                if (m.Body != 0x0190 && m.Body != 0x0191 && m.Body != 0x025D && m.Body != 0x025E)\n                    continue;\n\n                if ((!FriendsManager.IsFriend(m.Serial) || noto.Length > 0 && noto[0] == 0) &&\n                    !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                {\n                    for (var i = 0; i < noto.Length; i++)\n                        if (noto[i] == m.Notoriety)\n                        {\n                            list.Add(m);\n                            break;\n                        }\n\n                    if (noto.Length == 0)\n                        list.Add(m);\n                }\n            }\n\n            if (list.Count > 0)\n            {\n                SetLastTargetTo(list[Utility.Random(list.Count)]);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n\n        public static void RandomMonsterTarget(params int[] noto)\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.RandomTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n            {\n                if (!m.IsMonster)\n                    continue;\n\n                if ((!FriendsManager.IsFriend(m.Serial) || noto.Length > 0 && noto[0] == 0) &&\n                    !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                {\n                    for (var i = 0; i < noto.Length; i++)\n                        if (noto[i] == m.Notoriety)\n                        {\n                            list.Add(m);\n                            break;\n                        }\n\n                    if (noto.Length == 0)\n                        list.Add(m);\n                }\n            }\n\n            if (list.Count > 0)\n            {\n                SetLastTargetTo(list[Utility.Random(list.Count)]);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n\n        public static void RandomFriendTarget()\n        {\n            if (!Client.Instance.AllowBit(FeatureBit.RandomTargets))\n                return;\n\n            var list = new List<Mobile>();\n            foreach (var m in World.MobilesInRange(12))\n                if (FriendsManager.IsFriend(m.Serial) &&\n                    !m.Blessed && !m.IsGhost && m.Serial != World.Player.Serial &&\n                    !TargetFilterManager.IsFilteredTarget(m.Serial) &&\n                    Utility.InRange(World.Player.Position, m.Position, Config.GetInt(\"LTRange\")))\n                    list.Add(m);\n\n            if (list.Count > 0)\n            {\n                SetLastTargetTo(list[Utility.Random(list.Count)]);\n                ScriptManager.TargetFound = true;\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, LocString.TargNoOne);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/TextFilterManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Agents;\nusing Assistant.UI;\n\nnamespace Assistant.Core\n{\n    public static class TextFilterManager\n    {\n        private static ListBox _filterTextList;\n\n        public static List<string> FilteredText = new List<string>();\n        \n        public static void Initialize()\n        {\n            MessageManager.OnMobileMessage += HandleMobileMessage;\n        }\n        \n        public static void HandleMobileMessage(Packet p, PacketHandlerEventArgs args, Serial source, ushort graphic,\n            MessageType type, ushort hue, ushort font, string lang, string sourceName,\n            string text)\n        {\n            if ((type == MessageType.Emote || type == MessageType.Regular || type == MessageType.Whisper || type == MessageType.Yell) && source.IsMobile && source != World.Player.Serial)\n            {\n                if (IgnoreAgent.IsIgnored(source))\n                {\n                    args.Block = true;\n                    return;\n                }\n\n                if (IsFiltered(text))\n                {\n                    args.Block = true;\n                }\n            }\n        }\n\n        public static void SetControls(ListBox filterTextList)\n        {\n            _filterTextList = filterTextList;\n        }\n\n        public static void AddFilter(string filter)\n        {\n            FilteredText.Add(filter);\n\n            RedrawList();\n        }\n\n        public static void RemoveFilter(string filter)\n        {\n            FilteredText.Remove(filter);\n\n            RedrawList();\n        }\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (var text in FilteredText)\n            {\n                xml.WriteStartElement(\"filter\");\n                xml.WriteAttributeString(\"text\", text);\n                xml.WriteEndElement();\n            }\n        }\n\n        public static bool IsFiltered(string text)\n        {\n            if (!Config.GetBool(\"EnableTextFilter\"))\n                return false;\n\n            foreach (string filteredText in FilteredText)\n            {\n                if (text.IndexOf(filteredText, StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"filter\"))\n                {\n                    FilteredText.Add(Convert.ToString(el.GetAttribute(\"text\")));\n                }\n\n                RedrawList();\n            }\n            catch (Exception ex)\n            {\n                Debug.WriteLine(ex);\n            }\n        }\n\n        public static void ClearAll()\n        {\n            FilteredText.Clear();\n        }\n\n        public static void RedrawList()\n        {\n            _filterTextList?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                foreach (string text in FilteredText)\n                {\n                    s.Items.Add(text);\n                }\n\n                s.EndUpdate();\n            });\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/Timer.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections;\r\n\r\nnamespace Assistant\r\n{\r\n    public class MinHeap\r\n    {\r\n        private ArrayList m_List;\r\n        private int m_Size;\r\n\r\n        public MinHeap() : this(1)\r\n        {\r\n        }\r\n\r\n        public MinHeap(int capacity)\r\n        {\r\n            m_List = new ArrayList(capacity + 1);\r\n            m_Size = 0;\r\n            m_List.Add(null); // 0th index is never used, always null\r\n        }\r\n\r\n        public MinHeap(ICollection c) : this(c.Count)\r\n        {\r\n            foreach (IComparable o in c)\r\n                m_List.Add(o);\r\n            m_Size = c.Count;\r\n            Heapify();\r\n        }\r\n\r\n        public void Heapify()\r\n        {\r\n            for (int i = m_Size / 2; i > 0; i--)\r\n                PercolateDown(i);\r\n        }\r\n\r\n        private void PercolateDown(int hole)\r\n        {\r\n            IComparable tmp = (IComparable) m_List[hole];\r\n            int child;\r\n\r\n            for (; hole * 2 <= m_Size; hole = child)\r\n            {\r\n                child = hole * 2;\r\n                if (child != m_Size && ((IComparable) m_List[child + 1]).CompareTo(m_List[child]) < 0)\r\n                    child++;\r\n\r\n                if (tmp.CompareTo(m_List[child]) >= 0)\r\n                    m_List[hole] = m_List[child];\r\n                else\r\n                    break;\r\n            }\r\n\r\n            m_List[hole] = tmp;\r\n        }\r\n\r\n        public IComparable Peek()\r\n        {\r\n            return m_List[1] as IComparable;\r\n        }\r\n\r\n        public IComparable Pop()\r\n        {\r\n            IComparable top = Peek();\r\n\r\n            m_List[1] = m_List[m_Size--];\r\n            PercolateDown(1);\r\n\r\n            return top;\r\n        }\r\n\r\n        public void Remove(IComparable o)\r\n        {\r\n            for (int i = 1; i <= m_Size; i++)\r\n            {\r\n                if (m_List[i] == o)\r\n                {\r\n                    m_List[i] = m_List[m_Size--];\r\n                    PercolateDown(i);\r\n                    // TODO: Do we ever need to shrink?\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n\r\n        public void Clear()\r\n        {\r\n            int capacity = m_List.Count / 2;\r\n            if (capacity < 2)\r\n                capacity = 2;\r\n            m_Size = 0;\r\n            m_List = new ArrayList(capacity);\r\n            m_List.Add(null);\r\n        }\r\n\r\n        public void Add(IComparable o)\r\n        {\r\n            // PercolateUp\r\n            int hole = ++m_Size;\r\n\r\n            // Grow the list if needed\r\n            while (m_List.Count <= m_Size)\r\n                m_List.Add(null);\r\n\r\n            for (; hole > 1 && o.CompareTo(m_List[hole / 2]) < 0; hole /= 2)\r\n                m_List[hole] = m_List[hole / 2];\r\n            m_List[hole] = o;\r\n        }\r\n\r\n        public void AddMultiple(ICollection col)\r\n        {\r\n            if (col != null && col.Count > 0)\r\n            {\r\n                foreach (object o in col)\r\n                {\r\n                    int hole = ++m_Size;\r\n\r\n                    // Grow the list as needed\r\n                    while (m_List.Count <= m_Size)\r\n                        m_List.Add(null);\r\n\r\n                    m_List[hole] = o;\r\n                }\r\n\r\n                Heapify();\r\n            }\r\n        }\r\n\r\n        public int Count\r\n        {\r\n            get { return m_Size; }\r\n        }\r\n\r\n        public bool IsEmpty\r\n        {\r\n            get { return Count <= 0; }\r\n        }\r\n\r\n        public ArrayList GetRawList()\r\n        {\r\n            ArrayList copy = new ArrayList(m_Size);\r\n            for (int i = 1; i <= m_Size; i++)\r\n                copy.Add(m_List[i]);\r\n            return copy;\r\n        }\r\n    }\r\n\r\n    public delegate void TimerCallback();\r\n\r\n    public delegate void TimerCallbackState(object state);\r\n\r\n    public abstract class Timer : IComparable\r\n    {\r\n        private DateTime m_Next;\r\n        private TimeSpan m_Delay;\r\n        private TimeSpan m_Interval;\r\n        private bool m_Running;\r\n        private int m_Index, m_Count;\r\n\r\n        protected abstract void OnTick();\r\n\r\n        public Timer(TimeSpan delay) : this(delay, TimeSpan.Zero, 1)\r\n        {\r\n        }\r\n\r\n        public Timer(TimeSpan interval, int count) : this(interval, interval, count)\r\n        {\r\n        }\r\n\r\n        public Timer(TimeSpan delay, TimeSpan interval) : this(delay, interval, 0)\r\n        {\r\n        }\r\n\r\n        public Timer(TimeSpan delay, TimeSpan interval, int count)\r\n        {\r\n            m_Delay = delay;\r\n            m_Interval = interval;\r\n            m_Count = count;\r\n        }\r\n\r\n        public void Start()\r\n        {\r\n            if (!m_Running)\r\n            {\r\n                m_Index = 0;\r\n                m_Next = DateTime.UtcNow + m_Delay;\r\n                m_Running = true;\r\n                m_Heap.Add(this);\r\n                ChangedNextTick(true);\r\n            }\r\n        }\r\n\r\n        public void Stop()\r\n        {\r\n            if (m_Running)\r\n            {\r\n                m_Running = false;\r\n                m_Heap.Remove(this);\r\n                //ChangedNextTick();\r\n            }\r\n        }\r\n\r\n        public int CompareTo(object obj)\r\n        {\r\n            if (obj is Timer)\r\n                return this.TimeUntilTick.CompareTo(((Timer) obj).TimeUntilTick);\r\n            else\r\n                return -1;\r\n        }\r\n\r\n        public TimeSpan TimeUntilTick\r\n        {\r\n            get { return m_Running ? m_Next - DateTime.UtcNow : TimeSpan.MaxValue; }\r\n        }\r\n\r\n        public bool Running\r\n        {\r\n            get { return m_Running; }\r\n        }\r\n\r\n        public TimeSpan Delay\r\n        {\r\n            get { return m_Delay; }\r\n            set { m_Delay = value; }\r\n        }\r\n\r\n        public TimeSpan Interval\r\n        {\r\n            get { return m_Interval; }\r\n            set { m_Interval = value; }\r\n        }\r\n\r\n        private static MinHeap m_Heap = new MinHeap();\r\n\r\n        private static void ChangedNextTick()\r\n        {\r\n            ChangedNextTick(false);\r\n        }\r\n\r\n        private static void ChangedNextTick(bool allowImmediate)\r\n        {\r\n            if (!m_Heap.IsEmpty)\r\n            {\r\n                int interval = (int) Math.Round(((Timer) m_Heap.Peek()).TimeUntilTick.TotalMilliseconds);\r\n                if (allowImmediate && interval <= 0)\r\n                {\r\n                    Slice();\r\n                }\r\n                else\r\n                {\r\n                    if (interval <= 0)\r\n                        interval = 1;\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Slice()\r\n        {\r\n            int breakCount = 100;\r\n            ArrayList readd = new ArrayList();\r\n\r\n            while (!m_Heap.IsEmpty && ((Timer) m_Heap.Peek()).TimeUntilTick < TimeSpan.Zero)\r\n            {\r\n                if (breakCount-- <= 0)\r\n                    break;\r\n\r\n                Timer t = (Timer) m_Heap.Pop();\r\n\r\n                if (t != null && t.Running)\r\n                {\r\n                    t.OnTick();\r\n\r\n                    if (t.Running && (t.m_Count == 0 || (++t.m_Index) < t.m_Count))\r\n                    {\r\n                        t.m_Next = DateTime.UtcNow + t.m_Interval;\r\n                        readd.Add(t);\r\n                    }\r\n                    else\r\n                    {\r\n                        t.Stop();\r\n                    }\r\n                }\r\n            }\r\n\r\n            m_Heap.AddMultiple(readd);\r\n\r\n            ChangedNextTick();\r\n        }\r\n\r\n        private class OneTimeTimer : Timer\r\n        {\r\n            private TimerCallback m_Call;\r\n\r\n            public OneTimeTimer(TimeSpan d, TimerCallback call) : base(d)\r\n            {\r\n                m_Call = call;\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                m_Call();\r\n            }\r\n        }\r\n\r\n        public static Timer DelayedCallback(TimeSpan delay, TimerCallback call)\r\n        {\r\n            return new OneTimeTimer(delay, call);\r\n        }\r\n\r\n        private class OneTimeTimerState : Timer\r\n        {\r\n            private TimerCallbackState m_Call;\r\n            private object m_State;\r\n\r\n            public OneTimeTimerState(TimeSpan d, TimerCallbackState call, object state) : base(d)\r\n            {\r\n                m_Call = call;\r\n                m_State = state;\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                m_Call(m_State);\r\n            }\r\n        }\r\n\r\n        public static Timer DelayedCallbackState(TimeSpan delay, TimerCallbackState call, object state)\r\n        {\r\n            return new OneTimeTimerState(delay, call, state);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/UOEntity.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System.IO;\r\nusing System.Collections.Generic;\r\n\r\nnamespace Assistant\r\n{\r\n    public class UOEntity\r\n    {\r\n        public class ContextMenuList : List<KeyValuePair<ushort, ushort>>\r\n        {\r\n            public void Add(ushort key, ushort value)\r\n            {\r\n                var element = new KeyValuePair<ushort, ushort>(key, value);\r\n                Add(element);\r\n            }\r\n        }\r\n\r\n        private Serial _serial;\r\n        private Point3D _pos;\r\n        private ushort _hue;\r\n        private bool _deleted;\r\n        private ContextMenuList _contextMenu = new ContextMenuList();\r\n        protected ObjectPropertyList _objPropList = null;\r\n\r\n        public ObjectPropertyList ObjPropList\r\n        {\r\n            get { return _objPropList; }\r\n        }\r\n\r\n        public virtual void AfterLoad()\r\n        {\r\n        }\r\n\r\n        public UOEntity(Serial ser)\r\n        {\r\n            _objPropList = new ObjectPropertyList(this);\r\n\r\n            _serial = ser;\r\n            _deleted = false;\r\n        }\r\n\r\n        public Serial Serial\r\n        {\r\n            get { return _serial; }\r\n        }\r\n\r\n        public virtual Point3D Position\r\n        {\r\n            get { return _pos; }\r\n            set\r\n            {\r\n                if (value != _pos)\r\n                {\r\n                    var oldPos = _pos;\r\n                    _pos = value;\r\n                    OnPositionChanging(oldPos);\r\n                }\r\n            }\r\n        }\r\n\r\n        public bool Deleted\r\n        {\r\n            get { return _deleted; }\r\n        }\r\n\r\n        public ContextMenuList ContextMenu\r\n        {\r\n            get { return _contextMenu; }\r\n        }\r\n\r\n        public virtual ushort Hue\r\n        {\r\n            get { return _hue; }\r\n            set { _hue = value; }\r\n        }\r\n\r\n        public virtual void Remove()\r\n        {\r\n            _deleted = true;\r\n        }\r\n\r\n        public virtual void OnPositionChanging(Point3D oldPos)\r\n        {\r\n        }\r\n\r\n        public override int GetHashCode()\r\n        {\r\n            return _serial.GetHashCode();\r\n        }\r\n\r\n        public int OPLHash\r\n        {\r\n            get\r\n            {\r\n                if (_objPropList != null)\r\n                    return _objPropList.Hash;\r\n                else\r\n                    return 0;\r\n            }\r\n            set\r\n            {\r\n                if (_objPropList != null)\r\n                    _objPropList.Hash = value;\r\n            }\r\n        }\r\n\r\n        public bool ModifiedOPL\r\n        {\r\n            get { return _objPropList.Customized; }\r\n        }\r\n\r\n        public void ReadPropertyList(PacketReader p)\r\n        {\r\n            _objPropList.Read(p);\r\n        }\r\n\r\n        /*public Packet BuildOPLPacket()\r\n        { \r\n            return m_ObjPropList.BuildPacket();\r\n        }*/\r\n\r\n        public void OPLChanged()\r\n        {\r\n            //Client.Instance.SendToClient( m_ObjPropList.BuildPacket() );\r\n            Client.Instance.SendToClient(new OPLInfo(Serial, OPLHash));\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/Utility.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Text;\r\nusing System.Globalization;\r\nusing System.Runtime.InteropServices;\r\nusing System.Diagnostics;\r\nusing System.Windows.Forms;\r\n\r\nnamespace Assistant\r\n{\r\n    public class Utility\r\n    {\r\n        private static Random m_Random = new Random();\r\n\r\n        public static int Random(int min, int max)\r\n        {\r\n            return m_Random.Next(max - min + 1) + min;\r\n        }\r\n\r\n        public static int Random(int num)\r\n        {\r\n            return m_Random.Next(num);\r\n        }\r\n\r\n        public static bool InRange(IPoint2D from, IPoint2D to, int range)\r\n        {\r\n            return (to.X >= (from.X - range))\r\n                   && (to.X <= (from.X + range))\r\n                   && (to.Y >= (from.Y - range))\r\n                   && (to.Y <= (from.Y + range));\r\n        }\r\n\r\n        public static int Distance(int fx, int fy, int tx, int ty)\r\n        {\r\n            int xDelta = Math.Abs(fx - tx);\r\n            int yDelta = Math.Abs(fy - ty);\r\n\r\n            return (xDelta > yDelta ? xDelta : yDelta);\r\n        }\r\n\r\n        public static int Distance(IPoint2D from, IPoint2D to)\r\n        {\r\n            int xDelta = Math.Abs(from.X - to.X);\r\n            int yDelta = Math.Abs(from.Y - to.Y);\r\n\r\n            return (xDelta > yDelta ? xDelta : yDelta);\r\n        }\r\n\r\n        public static double DistanceSqrt(IPoint2D from, IPoint2D to)\r\n        {\r\n            float xDelta = Math.Abs(from.X - to.X);\r\n            float yDelta = Math.Abs(from.Y - to.Y);\r\n\r\n            return Math.Sqrt(xDelta * xDelta + yDelta * yDelta);\r\n        }\r\n\r\n        public static void Offset(Direction d, ref int x, ref int y)\r\n        {\r\n            switch (d & Direction.Mask)\r\n            {\r\n                case Direction.North:\r\n                    --y;\r\n                    break;\r\n                case Direction.South:\r\n                    ++y;\r\n                    break;\r\n                case Direction.West:\r\n                    --x;\r\n                    break;\r\n                case Direction.East:\r\n                    ++x;\r\n                    break;\r\n                case Direction.Right:\r\n                    ++x;\r\n                    --y;\r\n                    break;\r\n                case Direction.Left:\r\n                    --x;\r\n                    ++y;\r\n                    break;\r\n                case Direction.Down:\r\n                    ++x;\r\n                    ++y;\r\n                    break;\r\n                case Direction.Up:\r\n                    --x;\r\n                    --y;\r\n                    break;\r\n            }\r\n        }\r\n\r\n        public static void FormatBuffer(TextWriter output, Stream input, int length)\r\n        {\r\n            output.WriteLine(\"        0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F\");\r\n            output.WriteLine(\"       -- -- -- -- -- -- -- --  -- -- -- -- -- -- -- --\");\r\n\r\n            int byteIndex = 0;\r\n\r\n            int whole = length >> 4;\r\n            int rem = length & 0xF;\r\n\r\n            for (int i = 0; i < whole; ++i, byteIndex += 16)\r\n            {\r\n                StringBuilder bytes = new StringBuilder(49);\r\n                StringBuilder chars = new StringBuilder(16);\r\n\r\n                for (int j = 0; j < 16; ++j)\r\n                {\r\n                    int c = input.ReadByte();\r\n\r\n                    bytes.Append(c.ToString(\"X2\"));\r\n\r\n                    if (j != 7)\r\n                    {\r\n                        bytes.Append(' ');\r\n                    }\r\n                    else\r\n                    {\r\n                        bytes.Append(\"  \");\r\n                    }\r\n\r\n                    if (c >= 0x20 && c < 0x80)\r\n                    {\r\n                        chars.Append((char) c);\r\n                    }\r\n                    else\r\n                    {\r\n                        chars.Append('.');\r\n                    }\r\n                }\r\n\r\n                output.Write(byteIndex.ToString(\"X4\"));\r\n                output.Write(\"   \");\r\n                output.Write(bytes.ToString());\r\n                output.Write(\"  \");\r\n                output.WriteLine(chars.ToString());\r\n            }\r\n\r\n            if (rem != 0)\r\n            {\r\n                StringBuilder bytes = new StringBuilder(49);\r\n                StringBuilder chars = new StringBuilder(rem);\r\n\r\n                for (int j = 0; j < 16; ++j)\r\n                {\r\n                    if (j < rem)\r\n                    {\r\n                        int c = input.ReadByte();\r\n\r\n                        bytes.Append(c.ToString(\"X2\"));\r\n\r\n                        if (j != 7)\r\n                        {\r\n                            bytes.Append(' ');\r\n                        }\r\n                        else\r\n                        {\r\n                            bytes.Append(\"  \");\r\n                        }\r\n\r\n                        if (c >= 0x20 && c < 0x80)\r\n                        {\r\n                            chars.Append((char) c);\r\n                        }\r\n                        else\r\n                        {\r\n                            chars.Append('.');\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        bytes.Append(\"   \");\r\n                    }\r\n                }\r\n\r\n                output.Write(byteIndex.ToString(\"X4\"));\r\n                output.Write(\"   \");\r\n                output.Write(bytes.ToString());\r\n                if (rem <= 8)\r\n                    output.Write(\"   \");\r\n                else\r\n                    output.Write(\"  \");\r\n                output.WriteLine(chars.ToString());\r\n            }\r\n        }\r\n\r\n        public static unsafe void FormatBuffer(TextWriter output, byte* buff, int length)\r\n        {\r\n            output.WriteLine(\"        0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F\");\r\n            output.WriteLine(\"       -- -- -- -- -- -- -- --  -- -- -- -- -- -- -- --\");\r\n\r\n            int byteIndex = 0;\r\n\r\n            int whole = length >> 4;\r\n            int rem = length & 0xF;\r\n\r\n            for (int i = 0; i < whole; ++i, byteIndex += 16)\r\n            {\r\n                StringBuilder bytes = new StringBuilder(49);\r\n                StringBuilder chars = new StringBuilder(16);\r\n\r\n                for (int j = 0; j < 16; ++j)\r\n                {\r\n                    int c = *buff++;\r\n\r\n                    bytes.Append(c.ToString(\"X2\"));\r\n\r\n                    if (j != 7)\r\n                    {\r\n                        bytes.Append(' ');\r\n                    }\r\n                    else\r\n                    {\r\n                        bytes.Append(\"  \");\r\n                    }\r\n\r\n                    if (c >= 0x20 && c < 0x80)\r\n                    {\r\n                        chars.Append((char) c);\r\n                    }\r\n                    else\r\n                    {\r\n                        chars.Append('.');\r\n                    }\r\n                }\r\n\r\n                output.Write(byteIndex.ToString(\"X4\"));\r\n                output.Write(\"   \");\r\n                output.Write(bytes.ToString());\r\n                output.Write(\"  \");\r\n                output.WriteLine(chars.ToString());\r\n            }\r\n\r\n            if (rem != 0)\r\n            {\r\n                StringBuilder bytes = new StringBuilder(49);\r\n                StringBuilder chars = new StringBuilder(rem);\r\n\r\n                for (int j = 0; j < 16; ++j)\r\n                {\r\n                    if (j < rem)\r\n                    {\r\n                        int c = *buff++;\r\n\r\n                        bytes.Append(c.ToString(\"X2\"));\r\n\r\n                        if (j != 7)\r\n                        {\r\n                            bytes.Append(' ');\r\n                        }\r\n                        else\r\n                        {\r\n                            bytes.Append(\"  \");\r\n                        }\r\n\r\n                        if (c >= 0x20 && c < 0x80)\r\n                        {\r\n                            chars.Append((char) c);\r\n                        }\r\n                        else\r\n                        {\r\n                            chars.Append('.');\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        bytes.Append(\"   \");\r\n                    }\r\n                }\r\n\r\n                output.Write(byteIndex.ToString(\"X4\"));\r\n                output.Write(\"   \");\r\n                output.Write(bytes.ToString());\r\n                if (rem <= 8)\r\n                    output.Write(\"   \");\r\n                else\r\n                    output.Write(\"  \");\r\n                output.WriteLine(chars.ToString());\r\n            }\r\n        }\r\n\r\n        private static char[] pathChars = new char[] {'\\\\', '/'};\r\n\r\n        public static string PathDisplayStr(string path, int maxLen)\r\n        {\r\n            if (path == null || path.Length <= maxLen || path.Length < 5)\r\n                return path;\r\n\r\n            int first = (maxLen - 3) / 2;\r\n            int last = path.LastIndexOfAny(pathChars);\r\n            if (last == -1 || last < maxLen / 4)\r\n                last = path.Length - first;\r\n            first = maxLen - last - 3;\r\n            if (first < 0)\r\n                first = 1;\r\n            if (last < first)\r\n                last = first;\r\n\r\n            return $\"{path.Substring(0, first)}...{path.Substring(last)}\";\r\n        }\r\n\r\n        public static string FormatSize(long size)\r\n        {\r\n            if (size < 1024) // 1 K\r\n                return $\"{size:#,##0} B\";\r\n            else if (size < 1048576) // 1 M\r\n                return $\"{size / 1024.0:#,###.0} KB\";\r\n            else\r\n                return $\"{size / 1048576.0:#,###.0} MB\";\r\n        }\r\n\r\n        public static string FormatTime(int sec)\r\n        {\r\n            int m = sec / 60;\r\n            int h = m / 60;\r\n            m = m % 60;\r\n            return $\"{h:#0}:{m:00}:{sec % 60:00}\";\r\n        }\r\n\r\n        public static string FormatTimeMS(int ms)\r\n        {\r\n            int s = ms / 1000;\r\n            int m = s / 60;\r\n            int h = m / 60;\r\n\r\n            ms = ms % 1000;\r\n            s = s % 60;\r\n            m = m % 60;\r\n\r\n            if (h > 0 || m > 55)\r\n                return $\"{h:#0}:{m:00}:{s:00}.{ms:000}\";\r\n            else\r\n                return $\"{m:00}:{s:00}.{ms:000}\";\r\n        }\r\n\r\n        public static int ToInt32(string str, int def)\r\n        {\r\n            if (str == null)\r\n                return def;\r\n\r\n            if (str == null)\r\n                return def;\r\n\r\n            int val;\r\n            if (str.StartsWith(\"0x\"))\r\n            {\r\n                if (int.TryParse(str.Substring(2), NumberStyles.HexNumber, Engine.Culture, out val))\r\n                    return val;\r\n            }\r\n            else if (int.TryParse(str, out val))\r\n                return val;\r\n\r\n            return def;\r\n        }\r\n\r\n        public static uint ToUInt32(string str, uint def)\r\n        {\r\n            if (str == null)\r\n                return def;\r\n\r\n            uint val;\r\n            if (str.StartsWith(\"0x\"))\r\n            {\r\n                if (uint.TryParse(str.Substring(2), NumberStyles.HexNumber, Engine.Culture, out val))\r\n                    return val;\r\n            }\r\n            else if (uint.TryParse(str, out val))\r\n                return val;\r\n\r\n            return def;\r\n        }\r\n\r\n        public static double ToDouble(string str, double def)\r\n        {\r\n            if (str == null)\r\n                return def;\r\n\r\n            if (double.TryParse(str, out double d))\r\n                return d;\r\n            return def;\r\n        }\r\n\r\n        public static ushort ToUInt16(string str, ushort def)\r\n        {\r\n            if (str == null)\r\n                return def;\r\n\r\n            ushort val;\r\n            if (str.StartsWith(\"0x\"))\r\n            {\r\n                if (ushort.TryParse(str.Substring(2), NumberStyles.HexNumber, Engine.Culture, out val))\r\n                    return val;\r\n            }\r\n            else if (ushort.TryParse(str, out val))\r\n                return val;\r\n\r\n            return def;\r\n        }\r\n        \r\n        public static long ToLong(string str, ushort def)\r\n        {\r\n            if (str == null)\r\n                return def;\r\n\r\n            long val;\r\n            if (str.StartsWith(\"0x\"))\r\n            {\r\n                if (long.TryParse(str.Substring(2), NumberStyles.HexNumber, Engine.Culture, out val))\r\n                    return val;\r\n            }\r\n            else if (long.TryParse(str, out val))\r\n                return val;\r\n\r\n            return def;\r\n        }\r\n\r\n        public static void LaunchBrowser(string url)\r\n        {\r\n            try\r\n            {\r\n                Process.Start(url);\r\n\r\n                /*if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\r\n                {\r\n                    ProcessStartInfo psi = new ProcessStartInfo\r\n                    {\r\n                        FileName = url,\r\n                        UseShellExecute = true\r\n                    };\r\n                    Process.Start(psi);\r\n                }\r\n                else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))\r\n                {\r\n                    Process.Start(\"open\", url);\r\n                }\r\n                else\r\n                {\r\n                    Process.Start(\"xdg-open\", url);\r\n                }*/\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                MessageBox.Show(null, ex.Message, \"Unable to open directory\", MessageBoxButtons.OK,\r\n                                MessageBoxIcon.Warning);\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/WaypointManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\n\nnamespace Assistant.Core\n{\n    public static class WaypointManager\n    {\n        private static ListBox _waypointList;\n        private static WaypointDistanceTimer _waypointTimer;\n\n        public static Waypoint CurrentWaypoint;\n        private static int _curWaypointIndex;\n\n        public static List<Waypoint> Waypoints = new List<Waypoint>();\n\n        public static void Initialize()\n        {\n            HotKey.Add(HKCategory.Misc, LocString.NextWaypoint, new HotKeyCallback(NextWaypoint));\n            HotKey.Add(HKCategory.Misc, LocString.PrevWaypoint, new HotKeyCallback(PrevWaypoint));\n            HotKey.Add(HKCategory.Misc, LocString.HideWaypoint, new HotKeyCallback(ClearWaypoint));\n        }\n\n        public static void SetControls(ListBox waypointList)\n        {\n            _waypointList = waypointList;\n            _waypointTimer = new WaypointDistanceTimer();\n            _waypointTimer.Stop();\n        }\n\n        public class Waypoint\n        {\n            public int X { get; set; }\n            public int Y { get; set; }\n            public string Name { get; set; }\n\n            public override string ToString()\n            {\n                return $\"{Name} ({X}, {Y})\";\n            }\n        }\n\n        public static void NextWaypoint()\n        {\n            _curWaypointIndex++;\n\n            if (_curWaypointIndex >= Waypoints.Count)\n                _curWaypointIndex = 0;\n\n            ShowWaypoint(Waypoints[_curWaypointIndex]);\n        }\n\n        public static void PrevWaypoint()\n        {\n            _curWaypointIndex--;\n\n            if (_curWaypointIndex < 0)\n                _curWaypointIndex = Waypoints.Count - 1;\n\n            ShowWaypoint(Waypoints[_curWaypointIndex]);\n        }\n\n        public static void AddWaypoint(Waypoint waypoint)\n        {\n            Waypoints.Add(waypoint);\n\n            RedrawList();\n        }\n\n        public static void RemoveWaypoint(Waypoint waypoint)\n        {\n            ClearWaypoint();\n\n            Waypoints.Remove(waypoint);\n\n            RedrawList();\n        }\n\n        public static void ShowWaypoint(Waypoint waypoint)\n        {\n            Client.Instance.SendToClient(new QuestArrow(true, Convert.ToUInt16(waypoint.X), Convert.ToUInt16(waypoint.Y)));\n            \n            CurrentWaypoint = waypoint;\n\n            SendMessage($\"Waypoint: {CurrentWaypoint}\");\n\n            if (Config.GetBool(\"ShowWaypointDistance\"))\n            {\n                _waypointTimer.Start();\n            }\n        }\n\n        public static void ClearWaypoint()\n        {\n            Client.Instance.SendToClient(new QuestArrow(false, 0, 0));\n\n            CurrentWaypoint = null;\n\n            _waypointTimer.Stop();\n        }\n\n        public static void ResetTimer()\n        {\n            if (_waypointTimer.Running)\n            {\n                _waypointTimer.Stop();\n                _waypointTimer = new WaypointDistanceTimer();\n                _waypointTimer.Start();\n            }\n            else\n            {\n                _waypointTimer = new WaypointDistanceTimer();\n                _waypointTimer.Stop();\n            }\n        }\n\n        public static void StartTimer()\n        {\n            _waypointTimer.Start();\n        }\n\n        public static void StopTimer()\n        {\n            _waypointTimer.Stop();\n        }\n\n        private static void SendMessage(string msg)\n        {\n            if (Config.GetBool(\"ShowWaypointOverhead\"))\n            {\n                World.Player.OverheadMessage(msg);\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Info, msg);\n            }\n        }\n\n        private class WaypointDistanceTimer : Timer\n        {\n            public WaypointDistanceTimer() : base(TimeSpan.FromSeconds(Config.GetInt(\"ShowWaypointSeconds\")),\n                TimeSpan.FromSeconds(Config.GetInt(\"ShowWaypointSeconds\")))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                if (World.Player == null || CurrentWaypoint == null)\n                {\n                    Stop();\n                    return;\n                }\n\n                int dist = Utility.Distance(World.Player.Position.X, World.Player.Position.Y, CurrentWaypoint.X,\n                    CurrentWaypoint.Y);\n\n                if (Config.GetBool(\"ClearWaypoint\") && dist <= Config.GetInt(\"HideWaypointDistance\"))\n                {\n                    SendMessage($\"Arrived at '{CurrentWaypoint}'\");\n\n                    Stop();\n                    ClearWaypoint();\n                }\n                else\n                {\n                    SendMessage($\"{CurrentWaypoint.Name}: {dist} tiles away\");\n                }\n            }\n        }\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (var waypoint in Waypoints)\n            {\n                xml.WriteStartElement(\"waypoint\");\n                xml.WriteAttributeString(\"x\", waypoint.X.ToString());\n                xml.WriteAttributeString(\"y\", waypoint.Y.ToString());\n                xml.WriteAttributeString(\"name\", waypoint.Name);\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"waypoint\"))\n                {\n                    Waypoint waypoint = new Waypoint\n                    {\n                        X = Convert.ToInt32(el.GetAttribute(\"x\")),\n                        Y = Convert.ToInt32(el.GetAttribute(\"y\")),\n                        Name = el.GetAttribute(\"name\")\n                    };\n\n                    Waypoints.Add(waypoint);\n                }\n\n                RedrawList();\n            }\n            catch (Exception ex)\n            {\n                Debug.WriteLine(ex);\n            }\n        }\n\n        public static void ClearAll()\n        {\n            Waypoints.Clear();\n        }\n\n        public static void RedrawList()\n        {\n            _waypointList?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                foreach (Waypoint waypoint in Waypoints)\n                {\n                    s.Items.Add(waypoint);\n                }\n\n                s.EndUpdate();\n            });\n        }\n    }\n}"
  },
  {
    "path": "Razor/Core/World.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\n\r\nnamespace Assistant\r\n{\r\n    public class World\r\n    {\r\n        private static Dictionary<Serial, Item> m_Items;\r\n        private static Dictionary<Serial, Mobile> m_Mobiles;\r\n        private static PlayerData m_Player;\r\n        private static string m_ShardName, m_PlayerName, m_AccountName;\r\n        private static Dictionary<ushort, string> m_Servers;\r\n\r\n        static World()\r\n        {\r\n            m_Servers = new Dictionary<ushort, string>();\r\n            m_Items = new Dictionary<Serial, Item>();\r\n            m_Mobiles = new Dictionary<Serial, Mobile>();\r\n            m_ShardName = \"[None]\";\r\n        }\r\n\r\n        internal static Dictionary<ushort, string> Servers\r\n        {\r\n            get { return m_Servers; }\r\n        }\r\n\r\n        internal static Dictionary<Serial, Item> Items\r\n        {\r\n            get { return m_Items; }\r\n        }\r\n\r\n        internal static Dictionary<Serial, Mobile> Mobiles\r\n        {\r\n            get { return m_Mobiles; }\r\n        }\r\n\r\n        internal static Item FindItem(Serial serial)\r\n        {\r\n            m_Items.TryGetValue(serial, out Item it);\r\n            return it;\r\n        }\r\n\r\n        internal static Item FindItemByType(int itemId)\r\n        {\r\n            foreach (KeyValuePair<Serial, Item> item in m_Items)\r\n            {\r\n                if (item.Value.ItemID.Value == itemId)\r\n                    return item.Value;\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        internal static List<Item> FindItemsByName(string name)\r\n        {\r\n            List<Item> items = new List<Item>();\r\n\r\n            foreach (KeyValuePair<Serial, Item> item in m_Items)\r\n            {\r\n                if (item.Value.ItemID.ItemData.Name.Equals(name, StringComparison.OrdinalIgnoreCase))\r\n                    items.Add(item.Value);\r\n            }\r\n\r\n            return items;\r\n        }\r\n\r\n        internal static List<Item> FindItemsById(ushort id)\r\n        {\r\n            List<Item> items = new List<Item>();\r\n\r\n            foreach (KeyValuePair<Serial, Item> item in m_Items)\r\n            {\r\n                if (item.Value.ItemID == id)\r\n                    items.Add(item.Value);\r\n            }\r\n\r\n            return items;\r\n        }\r\n\r\n        internal static Mobile FindMobile(Serial serial)\r\n        {\r\n            m_Mobiles.TryGetValue(serial, out Mobile m);\r\n            return m;\r\n        }\r\n\r\n        internal static List<Mobile> FindMobilesByName(string name)\r\n        {\r\n            List<Mobile> mobiles = new List<Mobile>();\r\n            foreach (KeyValuePair<Serial, Mobile> item in m_Mobiles)\r\n            {\r\n                if (item.Value.Name.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1)\r\n                    mobiles.Add(item.Value);\r\n            }\r\n\r\n            return mobiles;\r\n        }\r\n\r\n        internal static List<Mobile> MobilesInRange(int range)\r\n        {\r\n            List<Mobile> list = new List<Mobile>();\r\n\r\n            if (World.Player == null)\r\n                return list;\r\n\r\n            foreach (Mobile m in World.Mobiles.Values)\r\n            {\r\n                if (Utility.InRange(World.Player.Position, m.Position, World.Player.VisRange))\r\n                    list.Add(m);\r\n            }\r\n\r\n            return list;\r\n        }\r\n\r\n        internal static List<Mobile> MobilesInRange()\r\n        {\r\n            if (Player == null)\r\n                return MobilesInRange(18);\r\n            else\r\n                return MobilesInRange(Player.VisRange);\r\n        }\r\n\r\n        internal static void AddItem(Item item)\r\n        {\r\n            m_Items[item.Serial] = item;\r\n        }\r\n\r\n        internal static void AddMobile(Mobile mob)\r\n        {\r\n            m_Mobiles[mob.Serial] = mob;\r\n        }\r\n\r\n        internal static void RequestMobileStatus(Mobile m)\r\n        {\r\n            Client.Instance.SendToServer(new StatusQuery(m));\r\n        }\r\n\r\n        internal static void RemoveMobile(Mobile mob)\r\n        {\r\n            m_Mobiles.Remove(mob.Serial);\r\n        }\r\n\r\n        internal static void RemoveItem(Item item)\r\n        {\r\n            m_Items.Remove(item.Serial);\r\n        }\r\n\r\n        internal static PlayerData Player\r\n        {\r\n            get { return m_Player; }\r\n            set { m_Player = value; }\r\n        }\r\n\r\n        internal static string ShardName\r\n        {\r\n            get { return m_ShardName; }\r\n            set { m_ShardName = value; }\r\n        }\r\n\r\n        internal static string OrigPlayerName\r\n        {\r\n            get { return m_PlayerName; }\r\n            set { m_PlayerName = value; }\r\n        }\r\n\r\n        internal static string AccountName\r\n        {\r\n            get { return m_AccountName; }\r\n            set { m_AccountName = value; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Core/ZLib.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace Assistant\r\n{\r\n    public enum ZLibError : int\r\n    {\r\n        Z_OK = 0,\r\n        Z_STREAM_END = 1,\r\n        Z_NEED_DICT = 2,\r\n        Z_ERRNO = (-1),\r\n        Z_STREAM_ERROR = (-2),\r\n        Z_DATA_ERROR = (-3), // Data was corrupt\r\n        Z_MEM_ERROR = (-4), //  Not Enough Memory\r\n        Z_BUF_ERROR = (-5), // Not enough buffer space\r\n        Z_VERSION_ERROR = (-6)\r\n    }\r\n\r\n    [Flags]\r\n    public enum ZLibCompressionLevel : int\r\n    {\r\n        Z_NO_COMPRESSION = 0,\r\n        Z_BEST_SPEED = 1,\r\n        Z_BEST_COMPRESSION = 9,\r\n        Z_DEFAULT_COMPRESSION = (-1)\r\n    }\r\n\r\n    public class ZLib\r\n    {\r\n        [DllImport(\"zlib\")]\r\n        internal static extern string zlibVersion();\r\n\r\n        [DllImport(\"zlib\")]\r\n        internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);\r\n\r\n        [DllImport(\"zlib\")]\r\n        internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength,\r\n            ZLibCompressionLevel level);\r\n\r\n        [DllImport(\"zlib\")]\r\n        internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);\r\n    }\r\n\r\n    // Be careful when writing raw data, as it may confuse the GZBlockIn if not accounted for when reading.\r\n    // Seeking in the compressed stream is HIGHLY unrecommended\r\n    // If you need to seek, use BufferAll to keep all data in the buffer, seek as much as you want, then\r\n    // turn off BufferAll and flush the data to disk.\r\n    // Once the data is flushed, you CANNOT seek back to it!\r\n    public class GZBlockOut : Stream\r\n    {\r\n        private BinaryWriter m_Out;\r\n        private MemoryStream m_Buffer;\r\n        private BinaryWriter m_Self;\r\n        private int m_BlockSize;\r\n        private bool m_BufferAll;\r\n        private bool m_IsCompressed;\r\n\r\n        public override bool CanSeek\r\n        {\r\n            get { return false; }\r\n        }\r\n\r\n        public override bool CanRead\r\n        {\r\n            get { return false; }\r\n        }\r\n\r\n        public override bool CanWrite\r\n        {\r\n            get { return true; }\r\n        }\r\n\r\n        public override long Length\r\n        {\r\n            get { return RawStream.Length; }\r\n        }\r\n\r\n        public override long Position\r\n        {\r\n            get { return m_IsCompressed ? m_Buffer.Position : RawStream.Position; }\r\n            set { }\r\n        }\r\n\r\n        public Stream RawStream\r\n        {\r\n            get { return m_Out.BaseStream; }\r\n        }\r\n\r\n        public BinaryWriter Raw\r\n        {\r\n            get { return m_Out; }\r\n        }\r\n\r\n        public BinaryWriter Compressed\r\n        {\r\n            get { return m_Self; }\r\n        }\r\n\r\n        public MemoryStream Buffer\r\n        {\r\n            get { return m_Buffer; }\r\n        }\r\n\r\n        public int BlockSize\r\n        {\r\n            get { return m_BlockSize; }\r\n            set { m_BlockSize = value; }\r\n        }\r\n\r\n        public bool BufferAll\r\n        {\r\n            get { return m_BufferAll; }\r\n            set { m_BufferAll = value; }\r\n        }\r\n\r\n        public bool IsCompressed\r\n        {\r\n            get { return m_IsCompressed; }\r\n            set\r\n            {\r\n                ForceFlush();\r\n                m_IsCompressed = value;\r\n            }\r\n        }\r\n\r\n        public GZBlockOut(string filename, int blockSize)\r\n        {\r\n            m_IsCompressed = true;\r\n\r\n            m_Out = new BinaryWriter(new FileStream(filename, FileMode.Create, FileAccess.ReadWrite, FileShare.None));\r\n            m_BlockSize = blockSize;\r\n            m_Buffer = new MemoryStream(blockSize + 1024);\r\n\r\n            m_Self = new BinaryWriter(this);\r\n        }\r\n\r\n        public override void Write(byte[] buffer, int offset, int count)\r\n        {\r\n            if (m_IsCompressed)\r\n            {\r\n                m_Buffer.Write(buffer, offset, count);\r\n                if (m_Buffer.Position >= m_BlockSize)\r\n                    FlushBuffer();\r\n            }\r\n            else\r\n            {\r\n                RawStream.Write(buffer, offset, count);\r\n            }\r\n        }\r\n\r\n        public override void WriteByte(byte value)\r\n        {\r\n            if (m_IsCompressed)\r\n            {\r\n                m_Buffer.WriteByte(value);\r\n                if (m_Buffer.Position >= m_BlockSize)\r\n                    FlushBuffer();\r\n            }\r\n            else\r\n            {\r\n                RawStream.WriteByte(value);\r\n            }\r\n        }\r\n\r\n        private static byte[] m_CompBuff = null;\r\n\r\n        public void FlushBuffer()\r\n        {\r\n            if (!m_IsCompressed || m_BufferAll || m_Buffer.Position <= 0)\r\n                return;\r\n\r\n            int outLen = (int) (m_Buffer.Position * 1.1);\r\n            if (m_CompBuff == null || m_CompBuff.Length < outLen)\r\n                m_CompBuff = new byte[outLen];\r\n            else\r\n                outLen = m_CompBuff.Length;\r\n\r\n            ZLibError error = ZLib.compress2(m_CompBuff, ref outLen, m_Buffer.ToArray(), (int) m_Buffer.Position,\r\n                ZLibCompressionLevel.Z_BEST_COMPRESSION);\r\n            if (error != ZLibError.Z_OK)\r\n                throw new Exception(\"ZLib error during copression: \" + error.ToString());\r\n\r\n            Raw.Write((int) outLen);\r\n            Raw.Write((int) m_Buffer.Position);\r\n            Raw.Write(m_CompBuff, 0, outLen);\r\n\r\n            m_Buffer.Position = 0;\r\n        }\r\n\r\n        public override void Flush()\r\n        {\r\n            FlushBuffer();\r\n            RawStream.Flush();\r\n        }\r\n\r\n        public void ForceFlush()\r\n        {\r\n            bool old = m_BufferAll;\r\n            m_BufferAll = false;\r\n            Flush();\r\n            m_BufferAll = old;\r\n        }\r\n\r\n        public override long Seek(long offset, SeekOrigin origin)\r\n        {\r\n            if (m_IsCompressed)\r\n                return m_Buffer.Seek(offset, origin);\r\n            else\r\n                return RawStream.Seek(offset, origin);\r\n        }\r\n\r\n        public override void SetLength(long value)\r\n        {\r\n            RawStream.SetLength(value);\r\n        }\r\n\r\n        public override int Read(byte[] buffer, int offset, int count)\r\n        {\r\n            return 0;\r\n        }\r\n\r\n        public override void Close()\r\n        {\r\n            ForceFlush();\r\n\r\n            base.Close();\r\n            m_Out.Close();\r\n            m_Buffer.Close();\r\n            m_Self = null;\r\n        }\r\n    }\r\n\r\n    // Represents a block compressed stream written by GZBlockOut\r\n    // If there is uncompressed data in the stream, you may seek to\r\n    // it and read from is as you wish using Raw/RawStream.  If you have\r\n    // not yet started reading compressed data, you must position rawstream\r\n    // at the begining of the compressed data.  If you've already read\r\n    // compressed data, you must reposition the file pointer back to its previous\r\n    // position in the stream.  This is really important.\r\n    //\r\n    // Seeking in the compressed stream should be okay, DO NOT attempt to seek outside\r\n    // of the compressed data.\r\n    public class GZBlockIn : Stream\r\n    {\r\n        private MemoryStream m_Uncomp;\r\n        private BinaryReader m_In;\r\n        private BinaryReader m_Self;\r\n        private bool m_Compressed;\r\n\r\n        public Stream RawStream\r\n        {\r\n            get { return m_In.BaseStream; }\r\n        }\r\n\r\n        public BinaryReader Raw\r\n        {\r\n            get { return m_In; }\r\n        }\r\n\r\n        public BinaryReader Compressed\r\n        {\r\n            get { return m_Compressed ? m_Self : m_In; }\r\n        }\r\n\r\n        public bool IsCompressed\r\n        {\r\n            get { return m_Compressed; }\r\n            set { m_Compressed = value; }\r\n        }\r\n\r\n        public override bool CanSeek\r\n        {\r\n            get { return true; }\r\n        }\r\n\r\n        public override bool CanRead\r\n        {\r\n            get { return true; }\r\n        }\r\n\r\n        public override bool CanWrite\r\n        {\r\n            get { return false; }\r\n        }\r\n\r\n        public override long Length\r\n        {\r\n            get\r\n            {\r\n                return m_Compressed\r\n                    ? (RawStream.Position < RawStream.Length ? int.MaxValue : m_Uncomp.Length)\r\n                    : RawStream.Length;\r\n            }\r\n        }\r\n\r\n        public override long Position\r\n        {\r\n            get { return m_Compressed ? m_Uncomp.Position : RawStream.Position; }\r\n            set\r\n            {\r\n                if (m_Compressed) m_Uncomp.Position = value;\r\n                else RawStream.Position = value;\r\n            }\r\n        }\r\n\r\n        public GZBlockIn(string filename)\r\n        {\r\n            m_Compressed = true;\r\n\r\n            m_In = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read));\r\n            m_Uncomp = new MemoryStream();\r\n            m_Self = new BinaryReader(this);\r\n        }\r\n\r\n        public override void Write(byte[] buffer, int offset, int count)\r\n        {\r\n        }\r\n\r\n        public override void Flush()\r\n        {\r\n            RawStream.Flush();\r\n            m_Uncomp.Flush();\r\n        }\r\n\r\n        private static byte[] m_ReadBuff = null;\r\n        private static byte[] m_CompBuff = null;\r\n\r\n        public override long Seek(long offset, SeekOrigin origin)\r\n        {\r\n            if (m_Compressed)\r\n            {\r\n                long absPos = offset;\r\n                if (origin == SeekOrigin.Current)\r\n                    absPos += m_Uncomp.Position;\r\n\r\n                if (absPos < 0)\r\n                    throw new Exception(\"Cannot seek past the begining of the stream.\");\r\n\r\n                long pos = m_Uncomp.Position;\r\n                m_Uncomp.Seek(0, SeekOrigin.End);\r\n\r\n                while ((origin == SeekOrigin.End || absPos >= m_Uncomp.Length) && RawStream.Position < RawStream.Length)\r\n                {\r\n                    int block = Raw.ReadInt32();\r\n                    int ucLen = Raw.ReadInt32();\r\n                    if (m_ReadBuff == null || m_ReadBuff.Length < block)\r\n                        m_ReadBuff = new byte[block];\r\n\r\n                    if (m_CompBuff == null || m_CompBuff.Length < ucLen)\r\n                        m_CompBuff = new byte[ucLen];\r\n                    else\r\n                        ucLen = m_CompBuff.Length;\r\n\r\n                    Raw.Read(m_ReadBuff, 0, block);\r\n\r\n                    ZLibError error = ZLib.uncompress(m_CompBuff, ref ucLen, m_ReadBuff, block);\r\n                    if (error != ZLibError.Z_OK)\r\n                        throw new Exception(\"ZLib error uncompressing: \" + error.ToString());\r\n\r\n                    m_Uncomp.Write(m_CompBuff, 0, ucLen);\r\n                }\r\n\r\n                m_Uncomp.Position = pos;\r\n                return m_Uncomp.Seek(offset, origin);\r\n            }\r\n            else\r\n            {\r\n                return RawStream.Seek(offset, origin);\r\n            }\r\n        }\r\n\r\n        public override void SetLength(long value)\r\n        {\r\n        }\r\n\r\n        public override int Read(byte[] buffer, int offset, int count)\r\n        {\r\n            if (m_Compressed)\r\n            {\r\n                long pos = m_Uncomp.Position;\r\n                m_Uncomp.Seek(0, SeekOrigin.End);\r\n\r\n                while (pos + count > m_Uncomp.Length && RawStream.Position + 8 < RawStream.Length)\r\n                {\r\n                    int block = Raw.ReadInt32();\r\n                    int ucLen = Raw.ReadInt32();\r\n\r\n                    if (block > 0x10000000 || block <= 0 || ucLen > 0x10000000 || ucLen <= 0)\r\n                        break;\r\n\r\n                    if (RawStream.Position + block > RawStream.Length)\r\n                        break;\r\n\r\n                    if (m_ReadBuff == null || m_ReadBuff.Length < block)\r\n                        m_ReadBuff = new byte[block];\r\n\r\n                    if (m_CompBuff == null || m_CompBuff.Length < ucLen)\r\n                        m_CompBuff = new byte[ucLen];\r\n                    else\r\n                        ucLen = m_CompBuff.Length;\r\n\r\n                    Raw.Read(m_ReadBuff, 0, block);\r\n\r\n                    ZLibError error = ZLib.uncompress(m_CompBuff, ref ucLen, m_ReadBuff, block);\r\n                    if (error != ZLibError.Z_OK)\r\n                        throw new Exception(\"ZLib error uncompressing: \" + error.ToString());\r\n\r\n                    m_Uncomp.Write(m_CompBuff, 0, ucLen);\r\n                }\r\n\r\n                m_Uncomp.Position = pos;\r\n                return m_Uncomp.Read(buffer, offset, count);\r\n            }\r\n            else\r\n            {\r\n                return RawStream.Read(buffer, offset, count);\r\n            }\r\n        }\r\n\r\n        public override void Close()\r\n        {\r\n            m_In.Close();\r\n            m_Uncomp.Close();\r\n            m_Self = null;\r\n        }\r\n\r\n        public bool EndOfFile\r\n        {\r\n            get\r\n            {\r\n                return ((!m_Compressed || m_Uncomp.Position >= m_Uncomp.Length) &&\r\n                        RawStream.Position >= RawStream.Length);\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/Death.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public class DeathFilter : Filter\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            Filter.Register(new DeathFilter());\r\n        }\r\n\r\n        private DeathFilter()\r\n        {\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0x2C}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return LocString.DeathStatus; }\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            args.Block = true;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/Filter.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections;\r\nusing System.Windows.Forms;\r\nusing System.Xml;\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public abstract class Filter\r\n    {\r\n        private static ArrayList m_Filters = new ArrayList();\r\n\r\n        public static ArrayList List\r\n        {\r\n            get { return m_Filters; }\r\n        }\r\n\r\n        public static void Register(Filter filter)\r\n        {\r\n            m_Filters.Add(filter);\r\n        }\r\n\r\n        public static void Load(XmlElement xml)\r\n        {\r\n            DisableAll();\r\n\r\n            if (xml == null)\r\n                return;\r\n\r\n            foreach (XmlElement el in xml.GetElementsByTagName(\"filter\"))\r\n            {\r\n                try\r\n                {\r\n                    LocString name = (LocString) Convert.ToInt32(el.GetAttribute(\"name\"));\r\n                    string enable = el.GetAttribute(\"enable\");\r\n\r\n                    for (int i = 0; i < m_Filters.Count; i++)\r\n                    {\r\n                        Filter f = (Filter) m_Filters[i];\r\n                        if (f.Name == name)\r\n                        {\r\n                            if (Convert.ToBoolean(enable))\r\n                                f.OnEnable();\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void DisableAll()\r\n        {\r\n            for (int i = 0; i < m_Filters.Count; i++)\r\n                ((Filter) m_Filters[i]).OnDisable();\r\n        }\r\n\r\n        public static void Save(XmlTextWriter xml)\r\n        {\r\n            for (int i = 0; i < m_Filters.Count; i++)\r\n            {\r\n                Filter f = (Filter) m_Filters[i];\r\n                if (f.Enabled)\r\n                {\r\n                    xml.WriteStartElement(\"filter\");\r\n                    xml.WriteAttributeString(\"name\", ((int) f.Name).ToString());\r\n                    xml.WriteAttributeString(\"enable\", f.Enabled.ToString());\r\n                    xml.WriteEndElement();\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Draw(CheckedListBox list)\r\n        {\r\n            list.BeginUpdate();\r\n            list.Items.Clear();\r\n\r\n            for (int i = 0; i < m_Filters.Count; i++)\r\n            {\r\n                Filter f = (Filter) m_Filters[i];\r\n                list.Items.Add(f);\r\n                list.SetItemChecked(i, f.Enabled);\r\n            }\r\n\r\n            list.EndUpdate();\r\n        }\r\n\r\n        public abstract void OnFilter(PacketReader p, PacketHandlerEventArgs args);\r\n        public abstract byte[] PacketIDs { get; }\r\n        public abstract LocString Name { get; }\r\n\r\n        public bool Enabled\r\n        {\r\n            get { return m_Enabled; }\r\n        }\r\n\r\n        private bool m_Enabled;\r\n        private PacketViewerCallback m_Callback;\r\n\r\n        protected Filter()\r\n        {\r\n            m_Enabled = false;\r\n            m_Callback = new PacketViewerCallback(this.OnFilter);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.GetString(this.Name);\r\n        }\r\n\r\n        public virtual void OnEnable()\r\n        {\r\n            m_Enabled = true;\r\n            for (int i = 0; i < PacketIDs.Length; i++)\r\n                PacketHandler.RegisterServerToClientViewer(PacketIDs[i], m_Callback);\r\n        }\r\n\r\n        public virtual void OnDisable()\r\n        {\r\n            m_Enabled = false;\r\n            for (int i = 0; i < PacketIDs.Length; i++)\r\n                PacketHandler.RemoveServerToClientViewer(PacketIDs[i], m_Callback);\r\n        }\r\n\r\n        public void OnCheckChanged(CheckState newValue)\r\n        {\r\n            if (Enabled && newValue == CheckState.Unchecked)\r\n                OnDisable();\r\n            else if (!Enabled && newValue == CheckState.Checked)\r\n                OnEnable();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/Light.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public class LightFilter : Filter\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            Filter.Register(new LightFilter());\r\n        }\r\n\r\n        private LightFilter()\r\n        {\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0x4E, 0x4F}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return LocString.LightFilter; }\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (Client.Instance.AllowBit(FeatureBit.LightFilter))\r\n            {\r\n                args.Block = true;\r\n                if (World.Player != null)\r\n                {\r\n                    World.Player.LocalLightLevel = 0;\r\n                    World.Player.GlobalLightLevel = 0;\r\n                }\r\n            }\r\n        }\r\n\r\n        public override void OnEnable()\r\n        {\r\n            base.OnEnable();\r\n\r\n            if (Client.Instance.AllowBit(FeatureBit.LightFilter) && World.Player != null)\r\n            {\r\n                World.Player.LocalLightLevel = 0;\r\n                World.Player.GlobalLightLevel = 0;\r\n\r\n                Client.Instance.SendToClient(new GlobalLightLevel(0));\r\n                Client.Instance.SendToClient(new PersonalLightLevel(World.Player));\r\n            }\r\n        }\r\n\r\n        public override void OnDisable()\r\n        {\r\n            base.OnDisable();\r\n\r\n            if (Client.Instance.AllowBit(FeatureBit.LightFilter) && World.Player != null)\r\n            {\r\n                World.Player.LocalLightLevel = 6;\r\n                World.Player.GlobalLightLevel = 2;\r\n\r\n                Client.Instance.SendToClient(new GlobalLightLevel(26));\r\n                Client.Instance.SendToClient(new PersonalLightLevel(World.Player));\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/MessageFilter.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public class AsciiMessageFilter : Filter\r\n    {\r\n        private LocString m_Name;\r\n        private string[] m_Strings;\r\n        private MessageType m_Type;\r\n\r\n        private AsciiMessageFilter(LocString name, MessageType type, string[] msgs)\r\n        {\r\n            m_Name = name;\r\n            m_Strings = msgs;\r\n            m_Type = type;\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0x1C}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return m_Name; }\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (args.Block)\r\n                return;\r\n\r\n            // 0, 1, 2\r\n            Serial serial = p.ReadUInt32(); // 3, 4, 5, 6\r\n            ushort body = p.ReadUInt16(); // 7, 8\r\n            MessageType type = (MessageType) p.ReadByte(); // 9\r\n\r\n            if (type != m_Type)\r\n                return;\r\n\r\n            ushort hue = p.ReadUInt16(); // 10, 11\r\n            ushort font = p.ReadUInt16();\r\n            string name = p.ReadStringSafe(30);\r\n            string text = p.ReadStringSafe();\r\n\r\n            for (int i = 0; i < m_Strings.Length; i++)\r\n            {\r\n                if (text.IndexOf(m_Strings[i]) != -1)\r\n                {\r\n                    args.Block = true;\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    public class LocMessageFilter : Filter\r\n    {\r\n        public static void Initialize()\r\n        {\r\n        }\r\n\r\n        private LocString m_Name;\r\n        private int[] m_Nums;\r\n        private MessageType m_Type;\r\n\r\n        private LocMessageFilter(LocString name, MessageType type, int[] msgs)\r\n        {\r\n            m_Name = name;\r\n            m_Nums = msgs;\r\n            m_Type = type;\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0xC1}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return m_Name; }\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (args.Block)\r\n                return;\r\n\r\n            Serial serial = p.ReadUInt32();\r\n            ushort body = p.ReadUInt16();\r\n            MessageType type = (MessageType) p.ReadByte();\r\n            ushort hue = p.ReadUInt16();\r\n            ushort font = p.ReadUInt16();\r\n            int num = p.ReadInt32();\r\n\r\n            // paladin spells\r\n            if (num >= 1060718 && num <= 1060727)\r\n                type = MessageType.Spell;\r\n            if (type != m_Type)\r\n                return;\r\n\r\n            for (int i = 0; i < m_Nums.Length; i++)\r\n            {\r\n                if (num == m_Nums[i])\r\n                {\r\n                    args.Block = true;\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/MobileFilter.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.IO;\n\nnamespace Assistant.Filters\n{\n    public static class MobileFilter\n    {\n        private static ushort[] _filters;\n\n        public static void Load()\n        {\n            _filters = new ushort[4];\n            _filters[0] = (ushort) Config.GetInt(\"DragonGraphic\");\n            _filters[1] = (ushort) Config.GetInt(\"DrakeGraphic\");\n            _filters[2] = (ushort) Config.GetInt(\"DaemonGraphic\");\n            _filters[3] = (ushort) Config.GetInt(\"WyrmGraphic\");\n        }\n\n        public static void Apply(Packet p, Mobile m)\n        {\n            Apply(p, m.Body);\n        }\n\n        public static void Apply(Packet p, ushort body)\n        {\n            if ((body == 0xC || body == 0x3B) && Config.GetBool(\"FilterDragonGraphics\"))\n            {\n                p.Seek(-2, SeekOrigin.Current);\n                p.Write(_filters[0]);\n            }\n            else if ((body == 0x3C || body == 0x3D) && Config.GetBool(\"FilterDrakeGraphics\"))\n            {\n                p.Seek(-2, SeekOrigin.Current);\n                p.Write(_filters[1]);\n            }\n            else if (body == 0x9 && Config.GetBool(\"FilterDaemonGraphics\"))\n            {\n                p.Seek(-2, SeekOrigin.Current);\n                p.Write(_filters[2]);\n            }\n            else if ((body == 0x31 || body == 0xB4) && Config.GetBool(\"FilterWyrmGraphics\"))\n            {\n                p.Seek(-2, SeekOrigin.Current);\n                p.Write(_filters[3]);\n            }\n        }\n\n        private static int Get(ushort body)\n        {\n            switch (body)\n            {\n                case 0xC:\n                case 0x3B:\n                    return _filters[0];\n                case 0x3C:\n                case 0x3D:\n                    return _filters[1];\n                case 0x9:\n                    return _filters[2];\n                case 0x31:\n                case 0xB4:\n                    return _filters[3];\n                default:\n                    return body;\n            }\n        }\n\n        public static void ApplyToMobiles()\n        {\n            foreach (Mobile mobile in World.MobilesInRange())\n            {\n                ushort body = (ushort)Get(mobile.Body);\n\n                if (mobile.Body != body)\n                {\n                    mobile.Body = body;\n                    Client.Instance.SendToClient(new MobileIncoming(mobile));\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Filters/SoundFilters.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public class SoundFilter : Filter\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            Filter.Register(new SoundFilter(LocString.BardMusic, 0x38, 0x39, 0x43, 0x44, 0x45, 0x46, 0x4C, 0x4D, 0x52,\r\n                0x53));\r\n            Filter.Register(new SoundFilter(LocString.DogSounds, GetRange(0x85, 0x89)));\r\n            Filter.Register(new SoundFilter(LocString.CatSounds, GetRange(0x69, 0x6D)));\r\n            Filter.Register(new SoundFilter(LocString.HorseSounds, GetRange(0xA8, 0xAC)));\r\n            Filter.Register(new SoundFilter(LocString.SheepSounds, GetRange(0xD6, 0xDA)));\r\n            Filter.Register(new SoundFilter(LocString.SS_Sound, 0x24A));\r\n            Filter.Register(new SoundFilter(LocString.FizzleSound, 0x5C));\r\n            Filter.Register(new SoundFilter(LocString.PackSound, 0x48));\r\n            Filter.Register(new SoundFilter(LocString.DeerSounds, 0x82, 0x83, 0x84, 0x85, 0x2BE, 0x2BF, 0x2C0, 0x4CB,\r\n                0x4CC));\r\n            Filter.Register(new SoundFilter(LocString.CyclopTitanSounds, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262,\r\n                0x263, 0x264, 0x265, 0x266));\r\n            Filter.Register(new SoundFilter(LocString.BullSounds, 0x065, 0x066, 0x067, 0x068, 0x069));\r\n\r\n            Filter.Register(new SoundFilter(LocString.DragonSounds, 0x2C8, 0x2C9, 0x2CA, 0x2CB, 0x2CC, 0x2CD, 0x2CE,\r\n                0x2CF,\r\n                0x2D0, 0x2D1, 0x2D2, 0x2D3, 0x2D4, 0x2D5, 0x2D6, 0x16B, 0x16C, 0x16D, 0x16E, 0x16F, 0x15F, 0x160,\r\n                0x161));\r\n\r\n            Filter.Register(new SoundFilter(LocString.ChickenSounds, 0x06F, 0x070, 0x071, 0x072, 0x073));\r\n\r\n            Filter.Register(new SoundFilter(LocString.BirdSounds, 0x017, 0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D,\r\n                0x01E, 0x01F, 0x270, 0x271, 0x272, 0x273, 0x274, 0x29B, 0x275, 0x29C, 0x276, 0x29D, 0x277, 0x29E, 0x278,\r\n                0x29F, 0x279, 0x2A0));\r\n        }\r\n\r\n        public static ushort[] GetRange(ushort min, ushort max)\r\n        {\r\n            if (max < min)\r\n                return new ushort[0];\r\n\r\n            ushort[] range = new ushort[max - min + 1];\r\n            for (ushort i = min; i <= max; i++)\r\n                range[i - min] = i;\r\n            return range;\r\n        }\r\n\r\n        private LocString m_Name;\r\n        private ushort[] m_Sounds;\r\n\r\n        private SoundFilter(LocString name, params ushort[] blockSounds)\r\n        {\r\n            m_Name = name;\r\n            m_Sounds = blockSounds;\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0x54}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return m_Name; }\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            p.ReadByte(); // flags\r\n\r\n            ushort sound = p.ReadUInt16();\r\n            for (int i = 0; i < m_Sounds.Length; i++)\r\n            {\r\n                if (m_Sounds[i] == sound)\r\n                {\r\n                    args.Block = true;\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/SoundMusicManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.UI;\n\nnamespace Assistant.Filters\n{\n    public static class SoundMusicManager\n    {\n        private static CheckedListBox _soundFilterList;\n        private static ComboBox _playableMusicList;\n\n        private static List<Sound> SoundFilters = new List<Sound>();\n        private static List<Sound> SoundList = new List<Sound>();\n\n        private static List<Music> MusicList = new List<Music>();\n\n        public static void SetControls(CheckedListBox soundFilterList, ComboBox playableMusicList)\n        {\n            _soundFilterList = soundFilterList;\n            _playableMusicList = playableMusicList;\n        }\n\n        public class Sound\n        {\n            public string Name { get; set; }\n            public Serial Serial { get; set; }\n\n            public override string ToString()\n            {\n                return $\"{Name} ({Serial})\";\n            }\n        }\n\n        public class Music\n        {\n            public string Name { get; set; }\n            public int Id { get; set; }\n            public bool Loop { get; set; }\n\n            public override string ToString()\n            {\n                return $\"{Name} ({Id})\";\n            }\n        }\n\n        public static bool IsFilteredSound(Serial serial, out string name)\n        {\n            foreach (Sound filter in SoundFilters)\n            {\n                if (filter.Serial == serial)\n                {\n                    name = filter.Name;\n                    return true;\n                }\n            }\n\n            name = string.Empty;\n            return false;\n        }\n\n        public static bool IsFilteredSound(ushort serial, out string name)\n        {\n            foreach (Sound filter in SoundFilters)\n            {\n                if (filter.Serial == serial)\n                {\n                    name = filter.Name;\n                    return true;\n                }\n            }\n\n            name = string.Empty;\n            return false;\n        }\n\n        public static string GetSoundName(ushort soundId)\n        {\n            if (SoundList.Count == 0)\n                RedrawList();\n\n            foreach (Sound sound in SoundList)\n            {\n                if (sound.Serial == soundId)\n                {\n                    return sound.Name;\n                }\n            }\n\n            return \"(unknown)\";\n        }\n        \n        public static int GetSoundId(string name)\n        {\n            if (SoundList.Count == 0)\n                RedrawList();\n\n            foreach (Sound sound in SoundList)\n            {\n                if (sound.Name.Equals(name))\n                {\n                    return sound.Serial;\n                }\n            }\n\n            return Serial.MinusOne;\n        }\n\n        public static List<Sound> GetAllSounds()\n        {\n            if (SoundList.Count == 0)\n                RedrawList();\n\n            return SoundList;\n        }\n\n        public static string GetMusicName(int musicId, out bool loop)\n        {\n            if (MusicList.Count == 0)\n                RedrawList();\n\n            foreach (Music music in MusicList)\n            {\n                if (music.Id == musicId)\n                {\n                    loop = music.Loop;\n                    return music.Name;\n                }\n            }\n\n            loop = false;\n            return \"(unknown)\";\n        }\n\n        public static void AddSoundFilter(Sound filter)\n        {\n            int index = SoundFilters.FindIndex(x => x.Name == filter.Name && x.Serial == filter.Serial);\n\n            if (index < 0)\n            {\n                SoundFilters.Add(filter);\n            }\n        }\n\n        public static void RemoveSoundFilter(Sound filter)\n        {\n            int index = SoundFilters.FindIndex(x => x.Name == filter.Name && x.Serial == filter.Serial);\n\n            if (index >= 0)\n            {\n                SoundFilters.RemoveAt(index);\n            }\n        }\n\n        public static void LoadMusic()\n        {\n            MusicList.Clear();\n\n            if (File.Exists($\"{Client.Instance.GetUoFilePath()}\\\\Music\\\\Digital\\\\Config.txt\"))\n            {\n                string[] musicInfo =\n                    File.ReadAllLines($\"{Client.Instance.GetUoFilePath()}\\\\Music\\\\Digital\\\\Config.txt\");\n\n                foreach (string music in musicInfo)\n                {\n                    if (music.StartsWith(\"#\"))\n                    {\n                        continue;\n                    }\n\n                    string[] parsedMusic = music.Split(' ');\n\n                    try\n                    {\n                        MusicList.Add(new Music\n                        {\n                            Id = Convert.ToInt32(parsedMusic[0]),\n                            Name = parsedMusic[1].Split(',')[0],\n                            Loop = parsedMusic[1].Contains(\",\") && parsedMusic[1].Split(',')[1].Equals(\"loop\")\n                        });\n                    }\n                    catch\n                    {\n                        // ignored, just don't load that line\n                    }\n                }\n            }\n            else\n            {\n                MusicList.Add(new Music\n                {\n                    Id = 0,\n                    Name = \"oldult01\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 1,\n                    Name = \"create1\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 2,\n                    Name = \"dragflit\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 3,\n                    Name = \"oldult02\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 4,\n                    Name = \"oldult03\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 5,\n                    Name = \"oldult04\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 6,\n                    Name = \"oldult05\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 7,\n                    Name = \"oldult06\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 8,\n                    Name = \"stones2\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 9,\n                    Name = \"britain1\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 10,\n                    Name = \"britain2\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 11,\n                    Name = \"bucsden\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 12,\n                    Name = \"jhelom\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 13,\n                    Name = \"lbcastle\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 14,\n                    Name = \"linelle\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 15,\n                    Name = \"magincia\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 16,\n                    Name = \"minoc\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 17,\n                    Name = \"ocllo\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 18,\n                    Name = \"samlethe\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 19,\n                    Name = \"serpents\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 20,\n                    Name = \"skarabra\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 21,\n                    Name = \"trinsic\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 22,\n                    Name = \"vesper\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 23,\n                    Name = \"wind\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 24,\n                    Name = \"yew\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 25,\n                    Name = \"cave01\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 26,\n                    Name = \"dungeon9\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 27,\n                    Name = \"forest_a\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 28,\n                    Name = \"intown01\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 29,\n                    Name = \"jungle_a\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 30,\n                    Name = \"mountn_a\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 31,\n                    Name = \"plains_a\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 32,\n                    Name = \"sailing\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 33,\n                    Name = \"swamp_a\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 34,\n                    Name = \"tavern01\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 35,\n                    Name = \"tavern02\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 36,\n                    Name = \"tavern03\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 37,\n                    Name = \"tavern04\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 38,\n                    Name = \"combat1\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 39,\n                    Name = \"combat2\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 40,\n                    Name = \"combat3\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 41,\n                    Name = \"approach\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 42,\n                    Name = \"death\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 43,\n                    Name = \"victory\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 44,\n                    Name = \"btcastle\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 45,\n                    Name = \"nujelm\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 46,\n                    Name = \"dungeon2\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 47,\n                    Name = \"cove\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 48,\n                    Name = \"moonglow\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 49,\n                    Name = \"zento\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 50,\n                    Name = \"tokunodungeon\",\n                    Loop = false\n                });\n\n\n                MusicList.Add(new Music\n                {\n                    Id = 51,\n                    Name = \"Taiko\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 52,\n                    Name = \"dreadhornarea\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 53,\n                    Name = \"elfcity\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 54,\n                    Name = \"grizzledungeon\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 55,\n                    Name = \"melisandeslair\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 56,\n                    Name = \"paroxysmuslair\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 57,\n                    Name = \"gwennoconversation\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 58,\n                    Name = \"goodendgame\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 59,\n                    Name = \"goodvsevil\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 60,\n                    Name = \"greatearthserpents\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 61,\n                    Name = \"humanoids_u9\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 62,\n                    Name = \"minocnegative\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 63,\n                    Name = \"paws\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 64,\n                    Name = \"selimsbar\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 65,\n                    Name = \"serpentislecombat_u7\",\n                    Loop = false\n                });\n\n                MusicList.Add(new Music\n                {\n                    Id = 66,\n                    Name = \"valoriaships\",\n                    Loop = false\n                });\n            }\n        }\n\n        public static void LoadSounds()\n        {\n            SoundList.Clear();\n\n            for (int i = 0; i <= 0xFFE; ++i)\n            {\n                if (Ultima.Sounds.IsValidSound(i, out string wavName))\n                {\n                    Serial serial = Serial.Parse($\"0x{i:X3}\");\n\n                    Sound sound = new Sound\n                    {\n                        Name = wavName,\n                        Serial = serial\n                    };\n\n                    SoundList.Add(sound);\n                }\n            }\n\n            SoundList = SoundList.OrderBy(s => s.Name).ToList();\n        }\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (var filter in SoundFilters)\n            {\n                xml.WriteStartElement(\"soundfilter\");\n                xml.WriteAttributeString(\"name\", filter.Name);\n                xml.WriteAttributeString(\"serial\", filter.Serial.ToString());\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"soundfilter\"))\n                {\n                    try\n                    {\n                        Sound filter = new Sound\n                        {\n                            Name = el.GetAttribute(\"name\"),\n                            Serial = Serial.Parse(el.GetAttribute(\"serial\")),\n                        };\n\n                        SoundFilters.Add(filter);\n                    }\n                    catch\n                    {\n                        // bad entry, ignore\n                    }\n                }\n            }\n            catch\n            {\n                // must not be in the profile, move on\n            }\n\n            RedrawList();\n        }\n\n        public static void ClearAll()\n        {\n            SoundFilters.Clear();\n        }\n\n        public static void RedrawList()\n        {\n            _soundFilterList?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                if (SoundList.Count == 0)\n                {\n                    LoadSounds();\n                }\n\n                foreach (Sound sound in SoundList)\n                {\n                    bool isFiltered = IsFilteredSound(sound.Serial, out string name);\n                    s.Items.Add(sound, isFiltered);\n                }\n\n                s.EndUpdate();\n            });\n\n            _playableMusicList?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                if (MusicList.Count == 0)\n                {\n                    LoadMusic();\n                }\n\n                foreach (Music music in MusicList)\n                {\n                    s.Items.Add(music);\n                }\n\n                s.SelectedIndex = 0;\n                s.EndUpdate();\n            });\n        }\n    }\n}"
  },
  {
    "path": "Razor/Filters/StaffItems.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public class StaffItemFilter : Filter\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            Filter.Register(new StaffItemFilter());\r\n        }\r\n\r\n        private StaffItemFilter()\r\n        {\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0x1A}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return LocString.StaffOnlyItems; }\r\n        }\r\n\r\n        private static bool IsStaffItem(ItemID itemID)\r\n        {\r\n            return (\r\n                itemID == 0x36FF || // LOS blocker\r\n                itemID == 0x1183 // Movement blocker\r\n            );\r\n        }\r\n\r\n        private static bool IsStaffItem(Item i)\r\n        {\r\n            return i.OnGround && (IsStaffItem(i.ItemID) || !i.Visible);\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            uint serial = p.ReadUInt32();\r\n            ushort itemID = p.ReadUInt16();\r\n\r\n            if ((serial & 0x80000000) != 0)\r\n                p.ReadUInt16(); // amount\r\n\r\n            if ((itemID & 0x8000) != 0)\r\n                itemID = (ushort) ((itemID & 0x7FFF) + p.ReadSByte()); // itemID offset\r\n\r\n            ushort x = p.ReadUInt16();\r\n            ushort y = p.ReadUInt16();\r\n\r\n            if ((x & 0x8000) != 0)\r\n                p.ReadByte(); // direction\r\n\r\n            short z = p.ReadSByte();\r\n\r\n            if ((y & 0x8000) != 0)\r\n                p.ReadUInt16(); // hue\r\n\r\n            bool visable = true;\r\n            if ((y & 0x4000) != 0)\r\n            {\r\n                int flags = p.ReadByte();\r\n\r\n                visable = ((flags & 0x80) == 0);\r\n            }\r\n\r\n            if (IsStaffItem(itemID) || !visable)\r\n                args.Block = true;\r\n        }\r\n\r\n        public override void OnEnable()\r\n        {\r\n            base.OnEnable();\r\n\r\n            if (World.Player != null)\r\n            {\r\n                foreach (Item i in World.Items.Values)\r\n                {\r\n                    if (IsStaffItem(i))\r\n                        Client.Instance.SendToClient(new RemoveObject(i));\r\n                }\r\n            }\r\n        }\r\n\r\n        public override void OnDisable()\r\n        {\r\n            base.OnDisable();\r\n\r\n            if (World.Player != null)\r\n            {\r\n                foreach (Item i in World.Items.Values)\r\n                {\r\n                    if (IsStaffItem(i))\r\n                        Client.Instance.SendToClient(new WorldItem(i));\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/TargetFilterManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Windows.Forms;\nusing System.Xml;\nusing Assistant.Core;\nusing Assistant.UI;\n\nnamespace Assistant.Filters\n{\n    public static class TargetFilterManager\n    {\n        private static ListBox _targetFilterList;\n\n        private static List<TargetFilter> TargetFilters = new List<TargetFilter>();\n\n        public static void SetControls(ListBox targetFilterList)\n        {\n            _targetFilterList = targetFilterList;\n        }\n\n        public static void OnTargetAddTargetFilter()\n        {\n            World.Player.SendMessage(MsgLevel.Friend, \"Target mobile to be filtered\");\n            Targeting.OneTimeTarget(OnAddFriendTargetFilter);\n        }\n\n        public static void OnAddFriendTargetFilter(bool location, Serial serial, Point3D loc, ushort gfx)\n        {\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\n\n            if (!location && serial.IsMobile && serial != World.Player.Serial)\n            {\n                Mobile m = World.FindMobile(serial);\n\n                if (m == null)\n                    return;\n\n                AddTargetFilter(m.Name, serial);\n\n                RedrawList();\n            }\n        }\n\n        public class TargetFilter\n        {\n            public string Name { get; set; }\n            public Serial Serial { get; set; }\n\n            public override string ToString()\n            {\n                return $\"{Name} ({Serial})\";\n            }\n        }\n\n        public static void AddTargetFilter(string name, Serial serial)\n        {\n            if (TargetFilters.Any(f => f.Serial == serial) == false)\n            {\n                if (FriendsManager.IsFriend(serial))\n                {\n                    World.Player.SendMessage(MsgLevel.Warning,\n                        $\"'{name}' ({serial}) is a friend, not adding to target filter list\");\n                    return;\n                }\n\n                TargetFilter newFilter = new TargetFilter\n                {\n                    Name = name,\n                    Serial = serial\n                };\n\n                TargetFilters.Add(newFilter);\n\n                World.Player.SendMessage(MsgLevel.Info, $\"Added '{name}' ({serial}) to the target filter list\");\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Warning, $\"'{name}' ({serial}) is already on the target filter\");\n            }\n        }\n\n        public static void AddAllMobileAsTargetFilters()\n        {\n            List<Mobile> mobiles = World.MobilesInRange(12);\n\n            foreach (Mobile mobile in mobiles)\n            {\n                if (!FriendsManager.IsFriend(mobile.Serial) && mobile.Serial.IsMobile &&\n                    mobile.Serial != World.Player.Serial)\n                {\n                    AddTargetFilter(mobile.Name, mobile.Serial);\n                    /*if (AddTargetFilter(mobile.Name, mobile.Serial))\n                    {\n                        mobile.ObjPropList.Add(Language.GetString(LocString.RazorFriend));\n                        mobile.OPLChanged();\n                    }*/\n                }\n            }\n        }\n\n        public static void AddAllHumanoidsAsTargetFilters()\n        {\n            List<Mobile> mobiles = World.MobilesInRange(12);\n\n            foreach (Mobile mobile in mobiles)\n            {\n                if (!FriendsManager.IsFriend(mobile.Serial) && mobile.Serial.IsMobile &&\n                    mobile.Serial != World.Player.Serial &&\n                    mobile.IsHuman)\n                {\n                    AddTargetFilter(mobile.Name, mobile.Serial);\n                    /*if (AddFriend(mobile.Name, mobile.Serial))\n                    {\n                        mobile.ObjPropList.Add(Language.GetString(LocString.RazorFriend));\n                        mobile.OPLChanged();\n                    }*/\n                }\n            }\n        }\n\n        public static bool IsFilteredTarget(Serial serial)\n        {\n            if (!Config.GetBool(\"TargetFilterEnabled\"))\n                return false;\n\n            foreach (var filter in TargetFilters)\n            {\n                if (filter.Serial == serial)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static bool RemoveTargetFilter(int index)\n        {\n            TargetFilters.RemoveAt(index);\n            RedrawList();\n\n            return true;\n        }\n\n        public static void ClearTargetFilters()\n        {\n            TargetFilters.Clear();\n            RedrawList();\n        }\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (var filter in TargetFilters)\n            {\n                xml.WriteStartElement(\"targetfilter\");\n                xml.WriteAttributeString(\"name\", filter.Name);\n                xml.WriteAttributeString(\"serial\", filter.Serial.ToString());\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"targetfilter\"))\n                {\n                    try\n                    {\n                        TargetFilter filter = new TargetFilter\n                        {\n                            Name = el.GetAttribute(\"name\"),\n                            Serial = Serial.Parse(el.GetAttribute(\"serial\"))\n                        };\n\n                        TargetFilters.Add(filter);\n                    }\n                    catch\n                    {\n                        // bad entry, ignore\n                    }\n                }\n            }\n            catch\n            {\n                // must not be in the profile, move on\n            }\n\n            RedrawList();\n        }\n\n        public static void ClearAll()\n        {\n            TargetFilters.Clear();\n        }\n\n        public static void RedrawList()\n        {\n            _targetFilterList?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                foreach (var target in TargetFilters)\n                {\n                    s.Items.Add(target);\n                }\n\n                s.EndUpdate();\n            });\n        }\n    }\n}"
  },
  {
    "path": "Razor/Filters/VetRewardGump.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public class VetRewardGumpFilter : Filter\r\n    {\r\n        // 1006046 = You have reward items available.  Click 'ok' below to get the selection menu or 'cancel' to be prompted upon your next login.\r\n        private static string m_VetRewardStr = \"{ xmfhtmlgump 52 35 420 55 1006046 1 1 }\";\r\n\r\n        public static void Initialize()\r\n        {\r\n            Filter.Register(new VetRewardGumpFilter());\r\n        }\r\n\r\n        private VetRewardGumpFilter()\r\n        {\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0xB0, 0xDD}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return LocString.VetRewardGump; }\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            // completely skip this filter if we've been connected for more thn 1 minute\r\n            if (Client.Instance.ConnectionStart + TimeSpan.FromMinutes(1.0) < DateTime.UtcNow)\r\n                return;\r\n\r\n            try\r\n            {\r\n                p.Seek(0, System.IO.SeekOrigin.Begin);\r\n                byte packetID = p.ReadByte();\r\n\r\n                p.MoveToData();\r\n\r\n                uint ser = p.ReadUInt32();\r\n                uint tid = p.ReadUInt32();\r\n                int x = p.ReadInt32();\r\n                int y = p.ReadInt32();\r\n                string layout = null;\r\n\r\n                if (packetID == 0xDD)\r\n                {\r\n                    layout = p.GetCompressedReader().ReadString();\r\n                }\r\n                else\r\n                {\r\n                    ushort layoutLength = p.ReadUInt16();\r\n                    layout = p.ReadString(layoutLength);\r\n                }\r\n\r\n                if (layout != null && layout.IndexOf(m_VetRewardStr) != -1)\r\n                    args.Block = true;\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Filters/WallStaticFilter.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Assistant.Filters\n{\n    public class WallStaticFilter\n    {\n        const ushort WallStaticID = 0x28A8;\n        const ushort WallStaticIDStone = 0x0750;\n\n        internal enum WallColor : ushort\n        {\n            Stone = 0x3B1,\n            Fire = 0x0845,\n            Poison = 0x016A,\n            Paralyze = 0x00DA,\n            Energy = 0x0125\n        }\n\n        internal static bool MakeWallStatic(Assistant.Item wall)\n        {\n            switch (wall.ItemID)\n            {\n                case 0x0080:\n                case 0x0082:\n                    wall.ItemID = WallStaticIDStone;\n                    wall.Hue = (ushort) WallColor.Stone;\n                    Client.Instance.SendToClient(new WorldItem(wall));\n                    if (Config.GetBool(\"ShowStaticWallLabels\"))\n                        Client.Instance.SendToClient(new UnicodeMessage(wall.Serial, wall.ItemID, MessageType.Regular,\n                            (ushort) WallColor.Stone, 3, Language.CliLocName, wall.Name, \"[Wall Of Stone]\"));\n                    return true;\n                case 0x3996:\n                case 0x398C:\n                    wall.ItemID = WallStaticID;\n                    wall.Hue = (ushort) WallColor.Fire;\n                    Client.Instance.SendToClient(new WorldItem(wall));\n                    if (Config.GetBool(\"ShowStaticWallLabels\"))\n                        Client.Instance.SendToClient(new UnicodeMessage(wall.Serial, wall.ItemID, MessageType.Regular,\n                            (ushort) WallColor.Fire, 3, Language.CliLocName, wall.Name, \"[Fire Field]\"));\n                    return true;\n                case 0x3915:\n                case 0x3920:\n                case 0x3922:\n                    wall.ItemID = WallStaticID;\n                    wall.Hue = (ushort) WallColor.Poison;\n                    Client.Instance.SendToClient(new WorldItem(wall));\n                    if (Config.GetBool(\"ShowStaticWallLabels\"))\n                        Client.Instance.SendToClient(new UnicodeMessage(wall.Serial, wall.ItemID, MessageType.Regular,\n                            (ushort) WallColor.Poison, 3, Language.CliLocName, wall.Name, \"[Poison Field]\"));\n                    return true;\n                case 0x3967:\n                case 0x3979:\n                    wall.ItemID = WallStaticID;\n                    wall.Hue = (ushort) WallColor.Paralyze;\n                    Client.Instance.SendToClient(new WorldItem(wall));\n                    if (Config.GetBool(\"ShowStaticWallLabels\"))\n                        Client.Instance.SendToClient(new UnicodeMessage(wall.Serial, wall.ItemID, MessageType.Regular,\n                            (ushort) WallColor.Paralyze, 3, Language.CliLocName, wall.Name, \"[Paralyze Field]\"));\n                    return true;\n                case 0x3946:\n                case 0x3956:\n                    wall.ItemID = WallStaticID;\n                    wall.Hue = (ushort) WallColor.Energy;\n                    Client.Instance.SendToClient(new WorldItem(wall));\n                    if (Config.GetBool(\"ShowStaticWallLabels\"))\n                        Client.Instance.SendToClient(new UnicodeMessage(wall.Serial, wall.ItemID, MessageType.Regular,\n                            (ushort) WallColor.Energy, 3, Language.CliLocName, wall.Name, \"[Energy Field]\"));\n                    return true;\n                default:\n                    return false;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Filters/Weather.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant.Filters\r\n{\r\n    public class WeatherFilter : Filter\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            Filter.Register(new WeatherFilter());\r\n        }\r\n\r\n        private WeatherFilter()\r\n        {\r\n        }\r\n\r\n        public override byte[] PacketIDs\r\n        {\r\n            get { return new byte[] {0x65}; }\r\n        }\r\n\r\n        public override LocString Name\r\n        {\r\n            get { return LocString.Weather; }\r\n        }\r\n\r\n        public override void OnFilter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (Client.Instance.AllowBit(FeatureBit.WeatherFilter))\r\n                args.Block = true;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Gumps/Gump.cs",
    "content": "﻿#region license\n/* Copyright (C) 2009 Matthew Geyer\n * \n * This file is part of UO Machine.\n * \n * UO Machine is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * UO Machine is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with UO Machine.  If not, see <http://www.gnu.org/licenses/>. */\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing Assistant.Core.Gumps;\nusing Assistant.Network;\n\nnamespace Assistant.Gumps\n{\n    public class Gump\n    {\n        private static readonly Random _random = new Random();\n\n        private static readonly byte[] BeginLayout = StringToBuffer(\"{ \");\n        private static readonly byte[] EndLayout = StringToBuffer(\" }\");\n\n        private static readonly byte[] NoMove = StringToBuffer(\"{ nomove }\");\n        private static readonly byte[] NoClose = StringToBuffer(\"{ noclose }\");\n        private static readonly byte[] NoDispose = StringToBuffer(\"{ nodispose }\");\n        private static readonly byte[] NoResize = StringToBuffer(\"{ noresize }\");\n\n        private static readonly byte[] True = StringToBuffer(\" 1\");\n        private static readonly byte[] False = StringToBuffer(\" 0\");\n\n        private static readonly byte[] BeginTextSeparator = StringToBuffer(\" @\");\n        private static readonly byte[] EndTextSeparator = StringToBuffer(\"@\");\n\n        public readonly string Layout;\n        public readonly GumpPage[] Pages;\n\n        private List<GumpElement> _elements;\n        private List<string> _strings;\n        public int Serial;\n        public int X;\n        public int Y;\n\n        public Gump(int x, int y, uint id, int serial, string layout, string[] strings, GumpElement[] elements,\n            GumpPage[] pages)\n        {\n            X = x;\n            Y = y;\n            ID = id;\n            Serial = serial;\n            Layout = layout;\n            Strings = strings;\n            GumpElements = elements;\n            Pages = pages;\n\n            foreach (GumpPage gp in pages)\n            {\n                gp.ParentGump = this;\n            }\n        }\n\n        public Gump(int x, int y, int serial = 0, uint id = 0)\n        {\n            X = x;\n            Y = y;\n\n            Serial = serial;\n            ID = id;\n\n            string fullName = GetType().FullName;\n\n            if (ID == 0 && fullName != null)\n            {\n                ID = (uint) fullName.GetHashCode();\n            }\n\n            if (Serial == 0 && fullName != null)\n            {\n                uint hashCode = (uint) fullName.GetHashCode();\n\n                hashCode &= 0x0000FFFF;\n                hashCode <<= 8;\n                hashCode |= (uint) 0xFF << 24;\n\n                Serial = (int) (hashCode + _random.Next(0, 0xFF));\n            }\n\n            _elements = new List<GumpElement>();\n            _strings = new List<string>();\n        }\n\n        public bool Closable { get; set; }\n\n        public bool Disposable { get; set; }\n\n        public GumpElement[] GumpElements\n        {\n            get => _elements.ToArray();\n            set\n            {\n                _elements = new List<GumpElement>();\n\n                for (int i = 0; i < value.Length; i++)\n                {\n                    _elements.Add(value[i]);\n                }\n            }\n        }\n\n        public uint ID { get; }\n\n        public bool Movable { get; set; }\n\n        public bool Resizable { get; set; }\n\n        public bool Resend { get; set; }\n\n        public string[] Strings\n        {\n            get => _strings.ToArray();\n            set\n            {\n                _strings = new List<string>();\n\n                for (int i = 0; i < value.Length; i++)\n                {\n                    _strings.Add(value[i]);\n                }\n            }\n        }\n\n        /// <summary>\n        ///     Get array of GumpElements which match the specified ElementType from all pages.\n        /// </summary>\n        public GumpElement[] GetElementsByType(ElementType type)\n        {\n            List<GumpElement> elementList = new List<GumpElement>();\n\n            if (GumpElements != null)\n            {\n                elementList.AddRange(GumpElements.Where(ge => ge.Type == type));\n            }\n\n            if (Pages != null)\n            {\n                elementList.AddRange(from p in Pages from ge in p.GumpElements where ge.Type == type select ge);\n            }\n\n            return elementList.ToArray();\n        }\n\n        /// <summary>\n        ///     Get the GumpElement with the specified ID.  Searches all pages/elements.\n        /// </summary>\n        /// <returns>True on success.</returns>\n        public bool GetElementByID(int id, out GumpElement element)\n        {\n            if (GumpElements != null)\n            {\n                foreach (GumpElement ge in GumpElements)\n                {\n                    if (ge.ElementID == id)\n                    {\n                        element = ge;\n                        return true;\n                    }\n                }\n            }\n\n            if (Pages != null)\n            {\n                foreach (GumpPage p in Pages)\n                {\n                    foreach (GumpElement ge in p.GumpElements)\n                    {\n                        if (ge.ElementID == id)\n                        {\n                            element = ge;\n                            return true;\n                        }\n                    }\n                }\n            }\n\n            element = null;\n            return false;\n        }\n\n        /// <summary>\n        ///     Get the GumpElement nearest to the specified GumpElement.\n        /// </summary>\n        /// <returns>True on success.</returns>\n        public bool GetNearestElement(GumpElement source, out GumpElement element)\n        {\n            GumpElement nearest = null;\n            double closest = 0;\n\n            if (source.ParentPage != null)\n            {\n                return source.ParentPage.GetNearestElement(source, out element);\n            }\n\n            foreach (GumpElement ge in GumpElements)\n            {\n                if (ge == source)\n                {\n                    continue;\n                }\n\n                double distance = Utility.Distance(source.X, source.Y, ge.X, ge.Y);\n\n                if (nearest == null)\n                {\n                    closest = distance;\n                    nearest = ge;\n                }\n                else\n                {\n                    if (distance < closest)\n                    {\n                        closest = distance;\n                        nearest = ge;\n                    }\n                }\n            }\n\n            element = nearest;\n            return nearest != null;\n        }\n\n        /// <summary>\n        ///     Get nearest GumpElement to source, but only if it's ElementType is contained in the include list.\n        /// </summary>\n        /// <param name=\"source\">Source GumpElement</param>\n        /// <param name=\"includeTypes\">Array of ElementTypes which specifies valid GumpElements to search.</param>\n        /// <param name=\"element\">GumpElement (out).</param>\n        /// <returns>True on success.</returns>\n        public bool GetNearestElement(GumpElement source, ElementType[] includeTypes, out GumpElement element)\n        {\n            GumpElement nearest = null;\n            double closest = 0;\n\n            if (source.ParentPage != null)\n            {\n                return source.ParentPage.GetNearestElement(source, includeTypes, out element);\n            }\n\n            foreach (GumpElement ge in GumpElements)\n            {\n                if (ge == source)\n                {\n                    continue;\n                }\n\n                bool found = includeTypes.Any(et => ge.Type == et);\n\n                if (!found)\n                {\n                    continue;\n                }\n\n                double distance = Utility.Distance(source.X, source.Y, ge.X, ge.Y);\n\n                if (nearest == null)\n                {\n                    closest = distance;\n                    nearest = ge;\n                }\n                else\n                {\n                    if (distance < closest)\n                    {\n                        closest = distance;\n                        nearest = ge;\n                    }\n                }\n            }\n\n            element = nearest;\n            return nearest != null;\n        }\n\n        public bool GetElementByXY(int x, int y, out GumpElement gumpElement)\n        {\n            gumpElement = null;\n\n            if (GumpElements == null)\n            {\n                return false;\n            }\n\n            GumpElement element = GumpElements.FirstOrDefault(m => m.X == x && m.Y == y);\n\n            if (element != null)\n            {\n                gumpElement = element;\n            }\n\n            return gumpElement != null;\n        }\n\n        public GumpElement GetElementByXY(int x, int y)\n        {\n            return GetElementByXY(x, y, out GumpElement element) ? element : null;\n        }\n\n        public bool GetElementByCliloc(int cliloc, out GumpElement gumpElement)\n        {\n            gumpElement = null;\n\n            if (GumpElements == null)\n            {\n                return false;\n            }\n\n            GumpElement element = GumpElements.FirstOrDefault(m => m.Cliloc == cliloc);\n\n            if (element != null)\n            {\n                gumpElement = element;\n            }\n\n            return gumpElement != null;\n        }\n\n        public GumpElement GetElementByCliloc(int cliloc)\n        {\n            return GetElementByCliloc(cliloc, out GumpElement element) ? element : null;\n        }\n\n        public override int GetHashCode()\n        {\n            return ID.GetHashCode() ^ Layout?.GetHashCode() ?? 0;\n        }\n\n        public virtual void OnResponse(int buttonID, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            if (Resend)\n                SendGump();\n        }\n\n        public virtual void SendGump()\n        {\n            byte[] bytes = Compile();\n\n            World.Player.InternalGumps.Add(this);\n\n            Client.Instance.SendPacketToClient(bytes, bytes.Length);\n        }\n\n        public void CloseGump()\n        {\n            Client.Instance.SendToClient(new CloseGump(ID));\n        }\n\n        public int GetButtonId(int type, int index) => 1 + index * 11 + type;\n\n        public void Add(GumpElement e)\n        {\n            e.ParentGump = this;\n            _elements.Add(e);\n        }\n\n        public void AddPage(int page)\n        {\n            GumpElement ge = new GumpElement {Type = ElementType.page, PageNumber = page};\n            Add(ge);\n        }\n\n        public void AddAlphaRegion(int x, int y, int width, int height)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.checkertrans,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height\n            };\n            Add(ge);\n        }\n\n        public void AddBackground(int x, int y, int width, int height, int gumpID)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.resizepic,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                ElementID = gumpID\n            };\n            Add(ge);\n        }\n\n        public void AddButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.button,\n                X = x,\n                Y = y,\n                InactiveID = normalID,\n                ActiveID = pressedID,\n                ButtonType = (int) type,\n                ElementID = buttonID,\n                Param = param\n            };\n            Add(ge);\n        }\n\n        public void AddCheck(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.checkbox,\n                X = x,\n                Y = y,\n                InactiveID = inactiveID,\n                ActiveID = activeID,\n                InitialState = initialState,\n                ElementID = switchID\n            };\n            Add(ge);\n        }\n\n        public void AddGroup(int group)\n        {\n            GumpElement ge = new GumpElement {Type = ElementType.group, Group = group};\n            Add(ge);\n        }\n\n        public void AddTooltip(int number)\n        {\n            GumpElement ge = new GumpElement {Type = ElementType.tooltip, Cliloc = number};\n            Add(ge);\n        }\n\n        public void AddHtml(int x, int y, int width, int height, string text, bool background, bool scrollbar)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.htmlgump,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                Text = text,\n                ScrollBar = scrollbar,\n                Background = background\n            };\n            Add(ge);\n        }\n\n        public void AddHtmlLocalized(int x, int y, int width, int height, int number, bool background, bool scrollbar)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.xmfhtmlgump,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                Cliloc = number,\n                Background = background,\n                ScrollBar = scrollbar\n            };\n            Add(ge);\n        }\n\n        public void AddHtmlLocalized(int x, int y, int width, int height, int number, int color, bool background,\n            bool scrollbar)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.xmfhtmlgumpcolor,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                Cliloc = number,\n                Hue = color,\n                Background = background,\n                ScrollBar = scrollbar\n            };\n            Add(ge);\n        }\n\n        public void AddHtmlLocalized(int x, int y, int width, int height, int number, string args, int color,\n            bool background, bool scrollbar)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.xmfhtmltok,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                Cliloc = number,\n                Args = args,\n                Hue = color,\n                Background = background,\n                ScrollBar = scrollbar\n            };\n            Add(ge);\n        }\n\n        public void AddImage(int x, int y, int gumpID)\n        {\n            AddImage(x, y, gumpID, 0);\n        }\n\n        public void AddImage(int x, int y, int gumpID, int hue)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.gumppic,\n                X = x,\n                Y = y,\n                ElementID = gumpID,\n                Hue = hue\n            };\n            Add(ge);\n        }\n\n        public void AddImageTiled(int x, int y, int width, int height, int gumpID)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.gumppictiled,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                ElementID = gumpID\n            };\n            Add(ge);\n        }\n\n        public void AddImageTiledButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type,\n            int param, int itemID, int hue, int width, int height)\n        {\n            AddImageTiledButton(x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height, -1);\n        }\n\n        public void AddImageTiledButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type,\n            int param, int itemID, int hue, int width, int height, int localizedTooltip)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.buttontileart,\n                X = x,\n                Y = y,\n                InactiveID = normalID,\n                ActiveID = pressedID,\n                ElementID = buttonID,\n                ButtonType = (int) type,\n                Param = param,\n                ItemID = itemID,\n                Hue = hue,\n                Height = height,\n                Width = width,\n                Cliloc = localizedTooltip\n            };\n            Add(ge);\n        }\n\n        public void AddItem(int x, int y, int itemID)\n        {\n            GumpElement ge = new GumpElement {Type = ElementType.tilepic, X = x, Y = y, ItemID = itemID};\n            Add(ge);\n        }\n\n        public void AddItem(int x, int y, int itemID, int hue)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.tilepic,\n                X = x,\n                Y = y,\n                ItemID = itemID,\n                Hue = hue\n            };\n            Add(ge);\n        }\n\n        public void AddLabel(int x, int y, int hue, string text)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.text,\n                X = x,\n                Y = y,\n                Hue = hue,\n                Text = text\n            };\n            Add(ge);\n        }\n\n        public void AddLabelCropped(int x, int y, int width, int height, int hue, string text)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.croppedtext,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                Hue = hue,\n                Text = text\n            };\n            Add(ge);\n        }\n\n        public void AddRadio(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.radio,\n                X = x,\n                Y = y,\n                InactiveID = inactiveID,\n                ActiveID = activeID,\n                InitialState = initialState,\n                ElementID = switchID\n            };\n            Add(ge);\n        }\n\n        public void AddTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.textentry,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                Hue = hue,\n                ElementID = entryID,\n                Text = initialText\n            };\n            Add(ge);\n        }\n\n        public void AddTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText,\n            int size)\n        {\n            GumpElement ge = new GumpElement\n            {\n                Type = ElementType.textentrylimited,\n                X = x,\n                Y = y,\n                Width = width,\n                Height = height,\n                Hue = hue,\n                ElementID = entryID,\n                Text = initialText,\n                Size = size\n            };\n            Add(ge);\n        }\n\n        public void AddItemProperty(int serial)\n        {\n            GumpElement ge = new GumpElement {Type = ElementType.itemproperty, Serial = serial};\n            Add(ge);\n        }\n        \n        public void AddProgressBar(int x, int y, int w, int h, double min, double max, Color color, Color back, Color fore)\n        {\n            string bg = $\"<BODYBGCOLOR=#{back.ToArgb():X}>\";\n            string fg = $\"<BODYBGCOLOR=#{fore.ToArgb():X}>\";\n\n            AddHtml(x, y, w, h, bg, false, false);\n            AddHtml(x + 2, y + 2, (int) Math.Ceiling((w - 4) * (min / max)), h - 4, fg, false, false);\n        }\n\n        public int Intern(string value)\n        {\n            int indexOf = _strings.IndexOf(value);\n\n            if (indexOf >= 0)\n            {\n                return indexOf;\n            }\n\n            _strings.Add(value);\n            return _strings.Count - 1;\n        }\n\n        internal static byte[] StringToBuffer(string str)\n        {\n            return Encoding.ASCII.GetBytes(str);\n        }\n\n        private byte[] Compile()\n        {\n            IGumpWriter disp = new GumpWriter(this);\n\n            if (!Movable)\n            {\n                disp.AppendLayout(NoMove);\n            }\n\n            if (!Closable)\n            {\n                disp.AppendLayout(NoClose);\n            }\n\n            if (!Disposable)\n            {\n                disp.AppendLayout(NoDispose);\n            }\n\n            if (!Resizable)\n            {\n                disp.AppendLayout(NoResize);\n            }\n\n            int count = GumpElements.Length;\n\n            for (int i = 0; i < count; ++i)\n            {\n                GumpElement e = GumpElements[i];\n\n                disp.AppendLayout(BeginLayout);\n                e.AppendTo(disp);\n                disp.AppendLayout(EndLayout);\n            }\n\n            List<string> strings = new List<string>();\n\n            if (Strings != null)\n            {\n                for (int i = 0; i < Strings.Length; i++)\n                {\n                    strings.Add(Strings[i]);\n                }\n            }\n\n            disp.WriteStrings(strings);\n\n            disp.Flush();\n\n            return disp.ToArray();\n        }\n\n        internal interface IGumpWriter\n        {\n            int Switches { get; set; }\n            int TextEntries { get; set; }\n\n            void AppendLayout(bool val);\n            void AppendLayout(int val);\n            void AppendLayoutNS(int val);\n            void AppendLayout(string text);\n            void AppendLayout(byte[] buffer);\n            void WriteStrings(List<string> strings);\n            void Flush();\n            byte[] ToArray();\n        }\n\n        internal class GumpWriter : IGumpWriter, IDisposable\n        {\n            private readonly byte[] _buffer = new byte[48];\n\n            private readonly PacketWriter _packet;\n\n            private int m_LayoutLength;\n            private int m_PacketLength;\n            private int m_StringsLength;\n\n            public GumpWriter(Gump g)\n            {\n                /*_packet = new Packet(0xB0);\n\n                _packet.EnsureCapacity(4096);\n\n                //_packet.Write((short)0);\n                _packet.Write( g.Serial );\n                _packet.Write( g.ID );\n                _packet.Write( g.X );\n                _packet.Write( g.Y );\n                _packet.Write( (ushort) 0xFFFF );*/\n\n                _packet = new PacketWriter(4096);\n                _buffer[0] = (byte) ' ';\n                _packet.Write((byte) 0xB0);\n                _packet.Write((short) 0);\n                _packet.Write(g.Serial);\n                _packet.Write(g.ID);\n                _packet.Write(g.X);\n                _packet.Write(g.Y);\n                _packet.Write((ushort) 0xFFFF);\n            }\n\n            public PacketWriter GetPacket()\n            {\n                return _packet;\n            }\n\n            public int Switches { get; set; }\n            public int TextEntries { get; set; }\n\n            public void AppendLayout(byte[] buffer)\n            {\n                int length = buffer.Length;\n                _packet.Write(buffer, 0, length);\n                m_LayoutLength += length;\n            }\n\n            public void AppendLayout(string text)\n            {\n                AppendLayout(BeginTextSeparator);\n\n                int length = text.Length;\n                _packet.WriteAsciiFixed(text, length);\n                m_LayoutLength += length;\n\n                AppendLayout(EndTextSeparator);\n            }\n\n            public void AppendLayout(int val)\n            {\n                string toString = val.ToString();\n                int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, _buffer, 1) + 1;\n\n                _packet.Write(_buffer, 0, bytes);\n                m_LayoutLength += bytes;\n            }\n\n            public void AppendLayout(bool val)\n            {\n                AppendLayout(val ? True : False);\n            }\n\n            public void AppendLayoutNS(int val)\n            {\n                string toString = val.ToString();\n                int bytes = Encoding.ASCII.GetBytes(toString, 0, toString.Length, _buffer, 1);\n\n                _packet.Write(_buffer, 1, bytes);\n                m_LayoutLength += bytes;\n            }\n\n            public void Flush()\n            {\n                int length = 23 + m_LayoutLength + m_StringsLength;\n                _packet.Seek(1, SeekOrigin.Begin);\n                _packet.Write((short) length);\n                m_PacketLength = length;\n            }\n\n            public void WriteStrings(List<string> text)\n            {\n                _packet.Seek(19, SeekOrigin.Begin);\n                _packet.Write((ushort) m_LayoutLength);\n                _packet.Seek(0, SeekOrigin.End);\n\n                _packet.Write((ushort) text.Count);\n\n                for (int i = 0; i < text.Count; ++i)\n                {\n                    string v = text[i] ?? string.Empty;\n\n                    int length = (ushort) v.Length;\n                    m_StringsLength += length * 2 + 2;\n\n                    _packet.Write((ushort) length);\n                    _packet.WriteBigUniFixed(v, length);\n                }\n            }\n\n            public byte[] ToArray()\n            {\n                byte[] packet = new byte[m_PacketLength];\n                Buffer.BlockCopy(_packet.ToArray(), 0, packet, 0, m_PacketLength);\n                return packet;\n            }\n\n            #region IDisposable Support\n\n            private bool disposedValue; // To detect redundant calls\n\n            protected virtual void Dispose(bool disposing)\n            {\n                if (disposedValue)\n                {\n                    return;\n                }\n\n                if (disposing)\n                {\n                    //_packet.Dispose();\n                }\n\n                disposedValue = true;\n            }\n\n            public void Dispose()\n            {\n                Dispose(true);\n                GC.SuppressFinalize(this);\n            }\n\n            #endregion\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/GumpButtonType.cs",
    "content": "﻿#region license\n/* Copyright (C) 2009 Matthew Geyer\n * \n * This file is part of UO Machine.\n * \n * UO Machine is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * UO Machine is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with UO Machine.  If not, see <http://www.gnu.org/licenses/>. */\n#endregion\n\nnamespace Assistant.Gumps\n{\n    public enum GumpButtonType\n    {\n        Page = 0,\n        Reply = 1\n    }\n}"
  },
  {
    "path": "Razor/Gumps/GumpCollection.cs",
    "content": "﻿#region license\n/* Copyright (C) 2009 Matthew Geyer\n * \n * This file is part of UO Machine.\n * \n * UO Machine is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * UO Machine is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with UO Machine.  If not, see <http://www.gnu.org/licenses/>. */\n#endregion\n\nusing System.Collections.Concurrent;\nusing System.Linq;\n\nnamespace Assistant.Gumps\n{\n    public sealed class GumpCollection\n    {\n        private readonly ConcurrentDictionary<uint, Gump> _dictionary;\n\n        public GumpCollection()\n        {\n            _dictionary = new ConcurrentDictionary<uint, Gump>();\n        }\n\n        public void Add(Gump gump)\n        {\n            bool result = _dictionary.AddOrUpdate(gump.ID, gump, (k, v) => gump) != null;\n\n            if (result)\n            {\n                OnCollectionChanged();\n            }\n        }\n\n        public bool Remove(uint id, int buttonId = 0, int[] switches = null, GumpTextEntry[] textEntries = null)\n        {\n            bool result = _dictionary.TryRemove(id, out Gump g);\n\n            g?.OnResponse(buttonId, switches, textEntries);\n\n            if (result)\n            {\n                OnCollectionChanged();\n            }\n\n            if (g.Resend)\n                g.SendGump();\n\n            return result;\n        }\n\n        public bool GetGump(uint id, out Gump gump)\n        {\n            return _dictionary.TryGetValue(id, out gump);\n        }\n\n        public bool FindGump(int serial, out Gump gump)\n        {\n            gump = _dictionary.Values.FirstOrDefault(g => g.Serial == serial);\n\n            return gump != null;\n        }\n\n        public bool GetGumps(out Gump[] gumps)\n        {\n            gumps = null;\n\n            if (_dictionary.Values.Count == 0)\n            {\n                return false;\n            }\n\n            gumps = _dictionary.Values.ToArray();\n\n            return gumps.Length > 0;\n        }\n\n        public void Clear()\n        {\n            int previousCount = _dictionary.Count;\n\n            _dictionary.Clear();\n\n            if (previousCount > 0)\n            {\n                OnCollectionChanged();\n            }\n        }\n\n        private void OnCollectionChanged()\n        {\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/GumpElement.cs",
    "content": "﻿#region license\n/* Copyright (C) 2009 Matthew Geyer\n * \n * This file is part of UO Machine.\n * \n * UO Machine is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * UO Machine is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with UO Machine.  If not, see <http://www.gnu.org/licenses/>. */\n#endregion\n\nusing System;\nusing Assistant.Core.Gumps;\n\nnamespace Assistant.Gumps\n{\n    public class GumpElement\n    {\n        private Gump _parentGump;\n        public int ActiveID { get; set; }\n        public string Args { get; set; }\n        public bool Background { get; set; }\n        public int ButtonType { get; set; }\n        public int Cliloc { get; set; }\n        public int ElementID { get; set; }\n        public int Group { get; set; }\n        public int Height { get; set; }\n        public int Hue { get; set; }\n        public int InactiveID { get; set; }\n        public bool InitialState { get; set; }\n        public int ItemID { get; set; }\n        public int PageNumber { get; set; }\n        public int Param { get; set; }\n\n        public Gump ParentGump\n        {\n            get => _parentGump ?? ParentPage?.ParentGump;\n            set => _parentGump = value;\n        }\n\n        public GumpPage ParentPage { get; set; }\n        public bool ScrollBar { get; set; }\n        public int Serial { get; set; }\n        public int Size { get; set; }\n        public string Text { get; set; }\n        public int Tooltip { get; set; }\n        public ElementType Type { get; set; }\n        public int Width { get; set; }\n        public int X { get; set; }\n        public int Y { get; set; }\n\n        /// <summary>\n        ///     Get nearest GumpElement.\n        /// </summary>\n        /// <returns>True on success.</returns>\n        public bool GetNearestElement(out GumpElement element)\n        {\n            if (ParentPage != null)\n            {\n                return ParentPage.GetNearestElement(this, out element);\n            }\n\n            element = null;\n            return false;\n        }\n\n        /// <summary>\n        ///     Get nearest GumpElement, but only if it's ElementType is contained in the include list.\n        /// </summary>\n        /// <param name=\"includeTypes\">Array of ElementTypes which specifies valid GumpElements to search.</param>\n        /// <param name=\"element\">GumpElement (out).</param>\n        /// <returns>True on success.</returns>\n        public bool GetNearestElement(ElementType[] includeTypes, out GumpElement element)\n        {\n            if (ParentPage != null)\n            {\n                return ParentPage.GetNearestElement(this, includeTypes, out element);\n            }\n\n            element = null;\n            return false;\n        }\n\n        public void Click()\n        {\n            Gump g = ParentGump;\n\n            if (g != null && g.ID != 461 && Type == ElementType.button)\n            {\n                //TODO\n                //Macros.MacroEx.CloseClientGump( g.Client, g.ID );\n                //Macros.MacroEx.GumpButtonClick( g.Client, g.ID, g.Serial, this.ElementID );\n            }\n        }\n\n        internal void AppendTo(Gump.IGumpWriter disp)\n        {\n            switch (Type)\n            {\n                case ElementType.textentrylimited:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"textentrylimited\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(Hue);\n                    disp.AppendLayout(ElementID);\n                    disp.AppendLayout(ParentGump.Intern(Text));\n                    disp.AppendLayout(Size);\n                    disp.TextEntries++;\n                    break;\n                }\n                case ElementType.textentry:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"textentry\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(Hue);\n                    disp.AppendLayout(ElementID);\n                    disp.AppendLayout(ParentGump.Intern(Text));\n                    disp.TextEntries++;\n                    break;\n                }\n                case ElementType.radio:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"radio\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(InactiveID);\n                    disp.AppendLayout(ActiveID);\n                    disp.AppendLayout(InitialState);\n                    disp.AppendLayout(ElementID);\n                    disp.Switches++;\n                    break;\n                }\n                case ElementType.croppedtext:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"croppedtext\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(Hue);\n                    disp.AppendLayout(ParentGump.Intern(Text));\n                    break;\n                }\n                case ElementType.buttontileart:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"buttontileart\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(InactiveID);\n                    disp.AppendLayout(ActiveID);\n                    disp.AppendLayout(ButtonType);\n                    disp.AppendLayout(Param);\n                    disp.AppendLayout(ElementID);\n                    disp.AppendLayout(ItemID);\n                    disp.AppendLayout(Hue);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n\n                    if (Cliloc != -1)\n                    {\n                        disp.AppendLayout(Gump.StringToBuffer(\" }{ tooltip\"));\n                        disp.AppendLayout(Cliloc);\n                    }\n\n                    break;\n                }\n                case ElementType.tilepic:\n                case ElementType.tilepichue:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(Hue == 0 ? \"tilepic\" : \"tilepichue\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(ItemID);\n\n                    if (Hue != 0)\n                    {\n                        disp.AppendLayout(Hue);\n                    }\n\n                    break;\n                }\n                case ElementType.itemproperty:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"itemproperty\"));\n                    disp.AppendLayout(Serial);\n                    break;\n                }\n                case ElementType.gumppictiled:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"gumppictiled\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(ElementID);\n                    break;\n                }\n                case ElementType.gumppic:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"gumppic\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(ElementID);\n\n                    if (Hue != 0)\n                    {\n                        disp.AppendLayout(Gump.StringToBuffer(\" hue=\"));\n                        disp.AppendLayoutNS(Hue);\n                    }\n\n                    break;\n                }\n                case ElementType.xmfhtmlgump:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"xmfhtmlgump\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(Cliloc);\n                    disp.AppendLayout(Background);\n                    disp.AppendLayout(ScrollBar);\n                    break;\n                }\n                case ElementType.xmfhtmlgumpcolor:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"xmfhtmlgumpcolor\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(Cliloc);\n                    disp.AppendLayout(Background);\n                    disp.AppendLayout(ScrollBar);\n                    disp.AppendLayout(Hue);\n                    break;\n                }\n                case ElementType.xmfhtmltok:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"xmfhtmltok\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(Background);\n                    disp.AppendLayout(ScrollBar);\n                    disp.AppendLayout(Hue);\n                    disp.AppendLayout(Cliloc);\n                    disp.AppendLayout(Args);\n                    break;\n                }\n                case ElementType.htmlgump:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"htmlgump\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    disp.AppendLayout(ParentGump.Intern(Text));\n                    disp.AppendLayout(Background);\n                    disp.AppendLayout(ScrollBar);\n                    break;\n                }\n                case ElementType.tooltip:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"tooltip\"));\n                    disp.AppendLayout(Cliloc);\n                    break;\n                }\n                case ElementType.group:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"group\"));\n                    disp.AppendLayout(Group);\n                    break;\n                }\n                case ElementType.resizepic:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"resizepic\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(ElementID);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    break;\n                }\n                case ElementType.checkertrans:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"checkertrans\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Width);\n                    disp.AppendLayout(Height);\n                    break;\n                }\n                case ElementType.page:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"page\"));\n                    disp.AppendLayout(PageNumber);\n                    break;\n                }\n                case ElementType.button:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"button\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(InactiveID);\n                    disp.AppendLayout(ActiveID);\n                    disp.AppendLayout(ButtonType);\n                    disp.AppendLayout(Param);\n                    disp.AppendLayout(ElementID);\n                    break;\n                }\n                case ElementType.text:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"text\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(Hue);\n                    disp.AppendLayout(ParentGump.Intern(Text));\n                    break;\n                }\n                case ElementType.invalid:\n                    break;\n                case ElementType.checkbox:\n                {\n                    disp.AppendLayout(Gump.StringToBuffer(\"checkbox\"));\n                    disp.AppendLayout(X);\n                    disp.AppendLayout(Y);\n                    disp.AppendLayout(InactiveID);\n                    disp.AppendLayout(ActiveID);\n                    disp.AppendLayout(InitialState);\n                    disp.AppendLayout(ElementID);\n\n                    disp.Switches++;\n                    break;\n                }\n                case ElementType.kr_xmfhtmlgump:\n                    break;\n                case ElementType.mastergump:\n                    break;\n                default:\n                    throw new ArgumentOutOfRangeException();\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/GumpPage.cs",
    "content": "﻿#region license\n/* Copyright (C) 2009 Matthew Geyer\n * \n * This file is part of UO Machine.\n * \n * UO Machine is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * UO Machine is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with UO Machine.  If not, see <http://www.gnu.org/licenses/>. */\n#endregion\n\nusing System.Linq;\nusing Assistant.Core.Gumps;\n\nnamespace Assistant.Gumps\n{\n    public sealed class GumpPage\n    {\n        public GumpElement[] GumpElements { get; internal set; }\n        public int Page { get; internal set; }\n        public Gump ParentGump { get; internal set; }\n\n        /// <summary>\n        ///     Get array of GumpElements which match the specified ElementType.\n        /// </summary>\n        public GumpElement[] GetElementsByType(ElementType type)\n        {\n            return GumpElements.Where(ge => ge.Type == type).ToArray();\n        }\n\n        /// <summary>\n        ///     Get nearest GumpElement to source, but only if it's ElementType is contained in the include list.\n        /// </summary>\n        /// <param name=\"source\">Source element.</param>\n        /// <param name=\"includeTypes\">Array of ElementTypes which specifies valid GumpElements to search.</param>\n        /// <param name=\"element\">GumpElement (out).</param>\n        /// <returns>True on success.</returns>\n        public bool GetNearestElement(GumpElement source, ElementType[] includeTypes, out GumpElement element)\n        {\n            GumpElement nearest = null;\n            double closest = 0;\n\n            foreach (GumpElement ge in GumpElements)\n            {\n                if (ge == source)\n                {\n                    continue;\n                }\n\n                bool found = includeTypes.Any(et => ge.Type == et);\n\n                if (!found)\n                {\n                    continue;\n                }\n\n                double distance = Utility.Distance(source.X, source.Y, ge.X, ge.Y);\n\n                if (nearest == null)\n                {\n                    closest = distance;\n                    nearest = ge;\n                }\n                else\n                {\n                    if (!(distance < closest))\n                    {\n                        continue;\n                    }\n\n                    closest = distance;\n                    nearest = ge;\n                }\n            }\n\n            element = nearest;\n            return nearest != null;\n        }\n\n        /// <summary>\n        ///     Get nearest GumpElement from source.\n        /// </summary>\n        /// <returns>True on success.</returns>\n        public bool GetNearestElement(GumpElement source, out GumpElement element)\n        {\n            GumpElement nearest = null;\n            double closest = 0;\n\n            foreach (GumpElement ge in GumpElements)\n            {\n                if (ge == source)\n                {\n                    continue;\n                }\n\n                double distance = Utility.Distance(source.X, source.Y, ge.X, ge.Y);\n\n                if (nearest == null)\n                {\n                    closest = distance;\n                    nearest = ge;\n                }\n                else\n                {\n                    if (!(distance < closest))\n                    {\n                        continue;\n                    }\n\n                    closest = distance;\n                    nearest = ge;\n                }\n            }\n\n            element = nearest;\n            return nearest != null;\n        }\n\n        public bool GetElementByXY(int x, int y, out GumpElement gumpElement)\n        {\n            gumpElement = null;\n\n            if (GumpElements == null)\n            {\n                return false;\n            }\n\n            GumpElement element = GumpElements.FirstOrDefault(m => m.X == x && m.Y == y);\n\n            if (element != null)\n            {\n                gumpElement = element;\n            }\n\n            return gumpElement != null;\n        }\n\n        public GumpElement GetElementByXY(int x, int y)\n        {\n            if (GetElementByXY(x, y, out GumpElement element))\n            {\n                return element;\n            }\n\n            return null;\n        }\n\n        public bool GetElementByCliloc(int cliloc, out GumpElement gumpElement)\n        {\n            gumpElement = null;\n\n            if (GumpElements == null)\n            {\n                return false;\n            }\n\n            GumpElement element = GumpElements.FirstOrDefault(m => m.Cliloc == cliloc);\n\n            if (element != null)\n            {\n                gumpElement = element;\n            }\n\n            return gumpElement != null;\n        }\n\n        public GumpElement GetElementByCliloc(int cliloc)\n        {\n            return GetElementByCliloc(cliloc, out GumpElement element) ? element : null;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/GumpType.cs",
    "content": "﻿#region license\n/* Copyright (C) 2009 Matthew Geyer\n * \n * This file is part of UO Machine.\n * \n * UO Machine is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * UO Machine is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with UO Machine.  If not, see <http://www.gnu.org/licenses/>. */\n#endregion\n\nnamespace Assistant.Core.Gumps\n{\n    public enum ElementType : byte\n    {\n        invalid,\n        button,\n        buttontileart,\n        checkbox,\n        checkertrans,\n        croppedtext,\n        gumppic,\n        gumppictiled,\n        htmlgump,\n        kr_xmfhtmlgump,\n        mastergump,\n        radio,\n        resizepic,\n        text,\n        textentry,\n        textentrylimited,\n        tilepic,\n        tilepichue,\n        xmfhtmlgump,\n        xmfhtmlgumpcolor,\n        xmfhtmltok,\n        itemproperty,\n        page,\n        group,\n        tooltip\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/AgentsGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Windows.Forms.VisualStyles;\nusing Assistant.Agents;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class AgentsGump : Gump\n    {\n        private Agent Agent { get; set; }\n\n        public AgentsGump(Agent agent) : base(500, 250, 5000)\n        {\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n            Resend = false;\n\n            int pageCount = 1;\n            Agent = agent;\n\n            AddPage(pageCount);\n\n            AddPage(0);\n\n            if (agent is RestockAgent restockAgent)\n            {\n                AddBackground(1, 0, 453, 397, 3600);\n\n                AddButton(21, 355, 4029, 4031, (int)Buttons.AddTarget, GumpButtonType.Reply, 0);\n                AddLabel(58, 357, 990, Language.GetString(LocString.AddTarg));\n                AddLabel(300, 25, 990, \"Set Amount  Remove\");\n                \n                AddButton(152, 355, 4014, 4016, (int)Buttons.AgentAction, GumpButtonType.Reply, 0);\n                AddLabel(191, 357, 990, \"Restock Now\");\n\n                string title = !string.IsNullOrEmpty(agent.Alias)\n                    ? $\"Restock Agent {agent.Number} ({agent.Alias})\"\n                    : $\"Restock Agent {agent.Number}\";\n\n                AddLabel(27, 23, 252, title);\n\n                int count = 0;\n                int labelY = 66;\n\n                if (restockAgent.Items.Count > 0)\n                {\n                    foreach (RestockAgent.RestockItem item in restockAgent.Items)\n                    {\n                        //AddItem(5, labelY, item.ItemID.Value);\n                        AddImage(25, labelY + 4, 2224);\n                        AddLabel(50, labelY, 342, $\"{item.ItemID}\");\n                        AddLabel(250, labelY, 372, $\"{item.Amount:N0}\");\n\n                        AddButton(390, labelY - 2, 4017, 4019, GetButtonId(0, item.ItemID.Value), GumpButtonType.Reply, 0); //remove\n                        AddButton(324, labelY - 2, 4008, 4010, GetButtonId(1, item.ItemID.Value), GumpButtonType.Reply, 0); //set amount\n\n                        count++;\n                        labelY += 20;\n\n                        if (count == 14)\n                        {\n                            AddButton(410, 356, 9904, 9905, pageCount + 2, GumpButtonType.Page, pageCount + 1);\n\n                            pageCount++;\n                            count = 0;\n                            labelY = 66;\n\n                            AddPage(pageCount);\n\n                            AddBackground(1, 0, 453, 397, 3600);\n\n                            AddLabel(27, 23, 252, title);\n\n                            AddButton(21, 355, 4029, 4031, (int)Buttons.AddTarget, GumpButtonType.Reply, 0);\n                            AddLabel(58, 357, 990, Language.GetString(LocString.AddTarg));\n                            AddLabel(300, 25, 990, \"Set Amount  Remove\");\n\n                            AddButton(152, 355, 4014, 4016, (int)Buttons.AgentAction, GumpButtonType.Reply, 0);\n                            AddLabel(191, 357, 990, \"Restock Now\");\n\n                            AddButton(388, 356, 9910, 9911, pageCount + 1, GumpButtonType.Page, pageCount - 1);\n\n                            AddLabel(312, 357, 900, $\"Page {pageCount}\");\n                        }\n                    }\n                }\n                else\n                {\n                    AddImage(25, labelY + 4, 2224);\n                    AddLabel(50, labelY, 342, \"No items on this agent\");\n                }\n            }\n            else if (agent is OrganizerAgent orgAgent)\n            {\n                AddBackground(1, 0, 453, 397, 3600);\n\n                AddButton(21, 355, 4029, 4031, (int)Buttons.AddTarget, GumpButtonType.Reply, 0);\n                AddLabel(58, 357, 990, Language.GetString(LocString.AddTarg));\n                AddLabel(380, 25, 990, \"Remove\");\n\n                AddButton(152, 355, 4014, 4016, (int)Buttons.AgentAction, GumpButtonType.Reply, 0);\n                AddLabel(191, 357, 990, \"Organize Now\");\n\n                string title = !string.IsNullOrEmpty(agent.Alias)\n                    ? $\"Organizer Agent {agent.Number} ({agent.Alias})\"\n                    : $\"Organizer Agent {agent.Number}\";\n\n                AddLabel(27, 23, 252, title);\n\n                int count = 0;\n                int labelY = 66;\n\n                if (orgAgent.Items.Count > 0)\n                {\n                    foreach (ItemID item in orgAgent.Items)\n                    {\n                        //AddItem(5, labelY, item.Value);\n                        AddImage(25, labelY + 4, 2224);\n                        AddLabel(50, labelY, 342, $\"{item}\");\n\n                        AddButton(390, labelY - 2, 4017, 4019, GetButtonId(0, item.Value), GumpButtonType.Reply, 0); //remove\n\n                        count++;\n                        labelY += 20;\n\n                        if (count == 14)\n                        {\n                            AddButton(410, 356, 9904, 9905, pageCount + 2, GumpButtonType.Page, pageCount + 1);\n\n                            pageCount++;\n                            count = 0;\n                            labelY = 66;\n\n                            AddPage(pageCount);\n\n                            AddBackground(1, 0, 453, 397, 3600);\n\n                            AddLabel(27, 23, 252, title);\n\n                            AddButton(21, 355, 4029, 4031, (int)Buttons.AddTarget, GumpButtonType.Reply, 0);\n                            AddLabel(58, 357, 990, Language.GetString(LocString.AddTarg));\n                            AddLabel(380, 25, 990, \"Remove\");\n\n                            AddButton(152, 355, 4014, 4016, (int)Buttons.AgentAction, GumpButtonType.Reply, 0);\n                            AddLabel(191, 357, 990, \"Organize Now\");\n\n                            AddButton(388, 356, 9910, 9911, pageCount + 1, GumpButtonType.Page, pageCount - 1);\n\n                            AddLabel(312, 357, 900, $\"Page {pageCount}\");\n                        }\n                    }\n                }\n                else\n                {\n                    AddImage(25, labelY + 4, 2224);\n                    AddLabel(50, labelY, 342, \"No items on this agent\");\n                }\n            }\n            else if (agent is BuyAgent buyAgent)\n            {\n                AddBackground(1, 0, 453, 397, 3600);\n\n                AddButton(21, 355, 4029, 4031, (int)Buttons.AddTarget, GumpButtonType.Reply, 0);\n                AddLabel(58, 357, 990, Language.GetString(LocString.AddTarg));\n                AddLabel(300, 25, 990, \"Set Amount  Remove\");\n\n                string title = !string.IsNullOrEmpty(agent.Alias)\n                    ? $\"Buy Agent {agent.Number} ({agent.Alias})\"\n                    : $\"Buy Agent {agent.Number}\";\n\n                AddLabel(27, 23, 252, title);\n\n                int count = 0;\n                int labelY = 66;\n\n                if (buyAgent.Items.Count > 0)\n                {\n                    foreach (BuyAgent.BuyEntry item in buyAgent.Items)\n                    {\n                        //AddItem(5, labelY, item.Id);\n                        AddImage(25, labelY + 4, 2224);\n                        AddLabel(50, labelY, 342, $\"{item.Id}\");\n                        AddLabel(250, labelY, 372, $\"{item.Amount}\");\n\n                        AddButton(390, labelY - 2, 4017, 4019, GetButtonId(0, item.Id), GumpButtonType.Reply, 0); //remove\n                        AddButton(324, labelY - 2, 4008, 4010, GetButtonId(1, item.Id), GumpButtonType.Reply, 0); //set amount\n\n                        count++;\n                        labelY += 20;\n\n                        if (count == 14)\n                        {\n                            AddButton(410, 356, 9904, 9905, pageCount + 2, GumpButtonType.Page, pageCount + 1);\n\n                            pageCount++;\n                            count = 0;\n                            labelY = 66;\n\n                            AddPage(pageCount);\n\n                            AddBackground(1, 0, 453, 397, 3600);\n\n                            AddLabel(27, 23, 252, title);\n\n                            AddButton(21, 355, 4029, 4031, (int)Buttons.AddTarget, GumpButtonType.Reply, 0);\n                            AddLabel(58, 357, 990, Language.GetString(LocString.AddTarg));\n                            AddLabel(300, 25, 990, \"Set Amount  Remove\");\n\n                            AddButton(388, 356, 9910, 9911, pageCount + 1, GumpButtonType.Page, pageCount - 1);\n\n                            AddLabel(312, 357, 900, $\"Page {pageCount}\");\n                        }\n                    }\n                }\n                else\n                {\n                    AddImage(25, labelY + 4, 2224);\n                    AddLabel(50, labelY, 342, \"No items on this agent\");\n                }\n            }\n        }\n\n        public enum Buttons\n        {\n            AddTarget = 1,\n            Remove,\n            SetAmount,\n            NextPage,\n            PrevPage,\n            AgentAction\n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            if (buttonId > 0)\n            {\n                var type = buttonId % 11;\n                var index = buttonId / 11;\n\n                if (Agent is RestockAgent restockAgent)\n                {\n                    switch (buttonId)\n                    {\n                        case (int)Buttons.AddTarget:\n                            restockAgent.AddItemTarget(true);\n                            break;\n                        case (int) Buttons.AgentAction:\n                            restockAgent.OnHotKey();\n                            break;\n                        default:\n                        {\n                            switch (type)\n                            {\n                                // remove\n                                case 1:\n                                    restockAgent.RemoveItem(index);\n                                    break;\n                                // set amount\n                                case 2:\n                                    restockAgent.SetItemAmount(index);\n                                    break;\n                            }\n\n                            break;\n                        }\n                    }\n\n                    AgentsGump gump = new AgentsGump(Agent);\n                    gump.SendGump();\n                }\n                else if (Agent is OrganizerAgent orgAgent)\n                {\n                    switch (buttonId)\n                    {\n                        case (int)Buttons.AddTarget:\n                            orgAgent.AddItemTarget(true);\n                            break;\n                        case (int)Buttons.AgentAction:\n                            orgAgent.Organize();\n                            break;\n                        default:\n                        {\n                            if (type == 1) // remove\n                            {\n                                orgAgent.RemoveItem(index);\n                            }\n\n                            break;\n                        }\n                    }\n\n                    AgentsGump gump = new AgentsGump(Agent);\n                    gump.SendGump();\n                }\n                else if (Agent is BuyAgent buyAgent)\n                {\n                    switch (buttonId)\n                    {\n                        case (int)Buttons.AddTarget:\n                            buyAgent.AddItemTarget(true);\n                            break;\n                        default:\n                            switch (type)\n                            {\n                                // remove\n                                case 1:\n                                    buyAgent.RemoveItem(index);\n                                    break;\n                                // set amount\n                                case 2:\n                                    buyAgent.SetItemAmount(index, true);\n                                    break;\n                            }\n\n                            break;\n                    }\n\n                    AgentsGump gump = new AgentsGump(Agent);\n                    gump.SendGump();\n                }\n            }\n\n            base.OnResponse(buttonId, switches, textEntries);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/BoatControlGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class BoatControlGump : Gump\n    {\n        public BoatControlGump(int speed) : base(0, 0)\n        {\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n\n            AddPage(0);\n            AddBackground(48, 28, 182, 195, 9270);\n\n            AddButton(130, 69, 5600, 5604, (int) Buttons.OneForward, GumpButtonType.Reply, 0);\n            AddButton(130, 109, 5602, 5606, (int) Buttons.OneBackwards, GumpButtonType.Reply, 0);\n            AddButton(108, 89, 5603, 5607, (int) Buttons.OneLeft, GumpButtonType.Reply, 0);\n            AddButton(150, 89, 5601, 5605, (int) Buttons.OneRight, GumpButtonType.Reply, 0);\n            AddButton(173, 86, 9903, 9905, (int) Buttons.Right, GumpButtonType.Reply, 0);\n            AddButton(81, 86, 9909, 9911, (int) Buttons.Left, GumpButtonType.Reply, 0);\n            AddButton(128, 47, 9900, 9902, (int) Buttons.Forward, GumpButtonType.Reply, 0);\n            AddButton(128, 129, 9906, 9908, (int) Buttons.Back, GumpButtonType.Reply, 0);\n            AddButton(130, 90, 2117, 2118, (int) Buttons.Stop, GumpButtonType.Reply, 0);\n            AddButton(69, 118, 22406, 22407, (int) Buttons.TurnLeft, GumpButtonType.Reply, 0);\n            AddButton(189, 118, 22400, 22401, (int) Buttons.TurnRight, GumpButtonType.Reply, 0);\n            AddButton(162, 66, 5106, 5106, (int) Buttons.ForwardRight, GumpButtonType.Reply, 0);\n            AddButton(162, 120, 5100, 5100, (int) Buttons.BackRight, GumpButtonType.Reply, 0);\n            AddButton(106, 120, 5102, 5102, (int) Buttons.BackLeft, GumpButtonType.Reply, 0);\n            AddButton(106, 66, 5108, 5108, (int) Buttons.ForwardLeft, GumpButtonType.Reply, 0);\n\n            AddCheck(64, 188, 210, 211, speed == 0, (int) Buttons.Reg);\n            AddLabel(87, 189, 990, \"Reg\");\n            AddCheck(115, 189, 210, 211, speed == 1, (int) Buttons.Slow);\n            AddLabel(135, 189, 990, \"Slow\");\n            AddCheck(169, 189, 210, 211, speed == 2, (int) Buttons.One);\n            AddLabel(189, 189, 990, \"One\");\n\n            AddButton(66, 157, 5600, 5604, (int) Buttons.AnchorUp, GumpButtonType.Reply, 0);\n            AddButton(83, 157, 5602, 5606, (int) Buttons.AnchorDown, GumpButtonType.Reply, 0);\n        }\n\n        public override void OnResponse(int buttonID, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            int speed = 0;\n\n            foreach (int check in switches)\n            {\n                if (check == (int) Buttons.Reg)\n                {\n                    speed = 0;\n                    break;\n                }\n\n                if (check == (int)Buttons.Slow)\n                {\n                    speed = 1;\n                    break;\n                }\n\n                if (check == (int)Buttons.One)\n                {\n                    speed = 2;\n                    break;\n                }\n            }\n\n            switch (buttonID)\n            {\n                case (int) Buttons.AnchorDown:\n                    SendBoatCommand(\"Lower Anchor\");\n                    break;\n                case (int) Buttons.AnchorUp:\n                    SendBoatCommand(\"Raise Anchor\");\n                    break;\n                case (int) Buttons.Back:\n                    SendBoatCommand(\"Back\", speed);\n                    break;\n                case (int) Buttons.BackLeft:\n                    SendBoatCommand(\"Back Left\", speed);\n                    break;\n                case (int) Buttons.BackRight:\n                    SendBoatCommand(\"Back Right\", speed);\n                    break;\n                case (int) Buttons.Forward:\n                    SendBoatCommand(\"Forward\", speed);\n                    break;\n                case (int) Buttons.ForwardLeft:\n                    SendBoatCommand(\"Forward Left\", speed);\n                    break;\n                case (int) Buttons.ForwardRight:\n                    SendBoatCommand(\"Forward Right\", speed);\n                    break;\n                case (int) Buttons.Left:\n                    SendBoatCommand(\"Left\", speed);\n                    break;\n                case (int) Buttons.OneBackwards:\n                    SendBoatCommand(\"Back\", 2);\n                    break;\n                case (int) Buttons.OneForward:\n                    SendBoatCommand(\"Forward\", 2);\n                    break;\n                case (int) Buttons.OneLeft:\n                    SendBoatCommand(\"Left\", 2);\n                    break;\n                case (int) Buttons.OneRight:\n                    SendBoatCommand(\"Right\", 2);\n                    break;\n                case (int) Buttons.Right:\n                    SendBoatCommand(\"Right\", speed);\n                    break;\n                case (int) Buttons.TurnLeft:\n                    SendBoatCommand(\"Turn Left\");\n                    break;\n                case (int) Buttons.TurnRight:\n                    SendBoatCommand(\"Turn Right\");\n                    break;\n                case (int) Buttons.Stop:\n                    SendBoatCommand(\"Stop\");\n                    break;\n            }\n\n            if (buttonID != 0)\n            {\n                CloseGump();\n\n                BoatControlGump gump = new BoatControlGump(speed);\n                gump.SendGump();\n            }\n        }\n\n        /// <summary>\n        /// Handles basic logic on sending boat commands\n        /// </summary>\n        /// <param name=\"command\"></param>\n        /// <param name=\"speed\">0 = reg, 1 = slow, 2 = one</param>\n        /// <param name=\"directionCommand\"></param>\n        private void SendBoatCommand(string command, int speed = 0, bool directionCommand = true)\n        {\n            string boatCommand = command;\n\n            if (speed == 2 && directionCommand)\n            {\n                boatCommand = $\"{command} One\";\n            }\n            else if (speed == 1 && directionCommand)\n            {\n                boatCommand = $\"Slow {command}\";\n            }\n\n            if (World.Player != null)\n            {\n                World.Player.Say(boatCommand);\n            }\n        }\n\n        public enum Buttons\n        {\n            OneForward = 1,\n            OneBackwards,\n            OneLeft,\n            OneRight,\n            Right,\n            Left,\n            Forward,\n            Back,\n            Stop,\n            TurnLeft,\n            TurnRight,\n            ForwardRight,\n            BackRight,\n            BackLeft,\n            ForwardLeft,\n            Reg,\n            Slow,\n            One,\n            AnchorUp,\n            AnchorDown,\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/BuffGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing Assistant.Core;\nusing Ultima;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class BuffGump : Gump\n    {\n        public BuffGump() : base(50, 50, -1)\n        {\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n            \n            AddPage(0);\n            \n            int currentY = 100;\n\n            int barHeight = Config.GetInt(\"ShowBuffDebuffHeight\");\n            int barWidth = Config.GetInt(\"ShowBuffDebuffWidth\");\n            bool showIcons = Config.GetBool(\"ShowBuffDebuffIcons\");\n\n            IOrderedEnumerable<BuffDebuff> buffDebuffs;\n\n            switch (Config.GetInt(\"ShowBuffDebuffSort\"))\n            {\n                case 0:\n                    buffDebuffs = World.Player.BuffsDebuffs.OrderBy(buff => buff.ClilocMessage1).ThenBy(buff => BuffDebuffManager.IsBuff(buff.IconId) ? 1 : 0);\n                    break;\n                case 1:\n                    buffDebuffs = World.Player.BuffsDebuffs.OrderBy(buff => (buff.Duration - (DateTime.UtcNow - buff.Timestamp).TotalSeconds)).ThenBy(buff => BuffDebuffManager.IsBuff(buff.IconId) ? 1 : 0);\n                    break;\n                case 2:\n                    buffDebuffs = World.Player.BuffsDebuffs.OrderByDescending(buff => (buff.Duration - (DateTime.UtcNow - buff.Timestamp).TotalSeconds)).ThenBy(buff => BuffDebuffManager.IsBuff(buff.IconId) ? 1 : 0);\n                    break;\n                default:\n                    buffDebuffs = World.Player.BuffsDebuffs.OrderByDescending(buff => (buff.Duration - (DateTime.UtcNow - buff.Timestamp).TotalSeconds)).ThenBy(buff => BuffDebuffManager.IsBuff(buff.IconId) ? 1 : 0);\n                    break;\n            }\n\n            foreach (BuffDebuff buff in buffDebuffs)\n            {\n                TimeSpan diff = DateTime.UtcNow - buff.Timestamp;\n                var timeLeft = buff.Duration - (int)diff.TotalSeconds;\n\n                string timeLeftDisplay;\n\n                if (timeLeft < 0)\n                {\n                    timeLeft = 0; \n                    timeLeftDisplay = \"-\";\n                }\n                else\n                {\n                    timeLeftDisplay = $\"{timeLeft}s\";\n                }\n\n                Color barColor;\n                Color bgColor;\n                int labelHue;\n\n                if (BuffDebuffManager.IsBuff(buff.IconId))\n                {\n                    barColor = Color.Green;\n                    bgColor = Config.GetBool(\"UseBlackBuffDebuffBg\") ? Color.Black : Color.DarkGreen; \n\n                    labelHue = 62;\n                }\n                else if (BuffDebuffManager.IsDebuff(buff.IconId))\n                {\n                    barColor = Color.Red;\n                    bgColor = Config.GetBool(\"UseBlackBuffDebuffBg\") ? Color.Black : Color.DarkRed;\n\n                    labelHue = 32;\n                } \n                else if (BuffDebuffManager.IsState(buff.IconId))\n                {\n                    barColor = Color.Blue;\n                    bgColor = Config.GetBool(\"UseBlackBuffDebuffBg\") ? Color.Black : Color.DarkBlue;\n\n                    labelHue = 102;\n                }\n                else\n                {\n                    barColor = Color.Gray;\n                    bgColor = Config.GetBool(\"UseBlackBuffDebuffBg\") ? Color.Black : Color.DarkGray;\n\n                    labelHue = 922;\n                }\n\n                if (showIcons)\n                {\n                    AddImage(80, currentY, buff.IconId);\n                }\n\n                AddProgressBar(110, currentY, barWidth, barHeight, timeLeft, buff.Duration == 0 ? 100 : buff.Duration,\n                    Color.Black, bgColor, barColor);\n\n                switch (Config.GetInt(\"ShowBuffDebuffTimeType\"))\n                {\n                    case 0: //next to name\n                        AddLabelCropped(114, currentY, barWidth, barHeight, labelHue, $\"{buff} ({timeLeftDisplay})\");\n                        break;\n                    case 1: // outside of bar (left)\n                        AddLabelCropped(114, currentY, barWidth, barHeight, labelHue, $\"{buff}\");\n                        AddHtml(114 + barWidth, currentY, 50, barHeight, $\"<BIG><BASEFONT COLOR=#FFFFFF>{timeLeftDisplay}</BASEFONT></BIG>\", false, false);\n                        break;\n                    case 2: // right side of bar (inside)\n                        AddLabelCropped(114, currentY, barWidth, barHeight, labelHue, $\"{buff}\");\n                        AddHtml(114, currentY, barWidth, barHeight, $\"<DIV ALIGN=\\\"RIGHT\\\"><BIG><BASEFONT COLOR=#FFFFFF>{timeLeftDisplay}</BASEFONT></BIG></DIV>\", false, false);\n                        break;\n                    case 3: // under icon (28x28 icon)\n                        AddLabelCropped(114, currentY, barWidth, barHeight, labelHue, $\"{buff}\");\n                        AddHtml(80, currentY + 32, 50, barHeight, $\"<BIG><BASEFONT COLOR=#FFFFFF>{timeLeftDisplay}</BASEFONT></BIG>\", false, false);\n                        break;\n                    case 4: //none\n                        AddLabelCropped(114, currentY, barWidth, barHeight, labelHue, $\"{buff}\");\n                        break;\n                    default:\n                        AddLabelCropped(114, currentY, barWidth, barHeight, labelHue, $\"{buff} ({timeLeftDisplay})\");\n                        break;\n                }\n\n                if (barHeight > 28)\n                {\n                    currentY += barHeight + 4;\n                }\n                else\n                {\n                    currentY += 32;\n                }\n            }\n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            /*if (buttonId == 0)\n            {\n                World.Player?.SendMessage(\"All cooldowns have been stopped\");\n                CooldownManager.Stop();\n            }*/\n            \n            base.OnResponse(buttonId, switches, textEntries);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/CooldownGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing Assistant.Core;\nusing Ultima;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class CooldownGump : Gump\n    {\n        public CooldownGump() : base(100, 100, -1)\n        {\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n            \n            AddPage(0);\n            AddHtml(110, 77, 106, 24, \"<CENTER><BIG><BASEFONT COLOR=#E0E70B>Cooldowns</BASEFONT></BIG></CENTER>\", false, false);\n\n            int currentY = 100;\n            \n            foreach (KeyValuePair<string, Cooldown> cooldown in CooldownManager.Cooldowns.OrderByDescending(c => (c.Value.EndTime - DateTime.UtcNow).TotalSeconds))\n            {\n                //get the number of seconds left\n                TimeSpan diff = cooldown.Value.EndTime - DateTime.UtcNow;\n                int timeLeft = (int)diff.TotalSeconds;\n\n                if (timeLeft < 0)\n                {\n                    timeLeft = 0;\n                }\n                \n                Color backColor = cooldown.Value.BackgroundColor == Color.Empty ? Color.Black : cooldown.Value.BackgroundColor;\n                Color foreColor;\n\n                int labelHue;\n                \n                if (timeLeft > 10) //green\n                {\n                    foreColor = cooldown.Value.ForegroundColor == Color.Empty ? Color.Green : cooldown.Value.ForegroundColor;\n                    labelHue = 62;\n                }\n                else if (timeLeft > 5) //yellow\n                {\n                    foreColor = cooldown.Value.ForegroundColor == Color.Empty ? Color.FromArgb(253, 216, 53) : cooldown.Value.ForegroundColor;\n                    labelHue = 52;\n                }\n                else //red\n                {\n                    foreColor = cooldown.Value.ForegroundColor == Color.Empty ? Color.DarkRed : cooldown.Value.ForegroundColor;\n                    labelHue = 32;\n                }\n\n                if (cooldown.Value.Hue > 0)\n                {\n                    labelHue = cooldown.Value.Hue;\n                }\n\n                if (cooldown.Value.Icon > 0)\n                {\n                    AddImage(80, currentY, cooldown.Value.Icon);\n                }\n\n                AddProgressBar(110, currentY, Config.GetInt(\"CooldownWidth\"), Config.GetInt(\"CooldownHeight\"), timeLeft, cooldown.Value.Seconds, Color.Black, backColor, foreColor);\n                AddLabelCropped(114, currentY, Config.GetInt(\"CooldownWidth\") - 10, Config.GetInt(\"CooldownHeight\"), labelHue, $\"{cooldown.Key} ({timeLeft}s)\");\n\n                if (timeLeft == 0)\n                {\n                    AddImage(224, currentY + 4, 9009);\n                }\n\n                currentY += 2 + Config.GetInt(\"CooldownHeight\");\n            }\n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            if (buttonId == 0)\n            {\n                World.Player?.SendMessage(\"All cooldowns have been stopped\");\n                CooldownManager.Stop();\n            }\n            \n            base.OnResponse(buttonId, switches, textEntries);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/DamageTrackerGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\nusing System.Text;\nusing Assistant.Core;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class DamageTrackerGump : Gump\n    {\n        public DamageTrackerGump(string message) : base(100, 100)\n        {\n            Movable = true;\n            Closable = false;\n            Disposable = false;\n\n            AddPage(0);\n            AddBackground(0, 0, 253, 203, 9270);\n\n            AddLabel(20, 20, 2954, \"DPS:\");\n            AddLabel(60, 20, 67, $\"{DamageTracker.DamagePerSecond:N2}\");\n\n            AddLabel(120, 20, 2954, \"Max DPS:\");\n            AddLabel(190, 20, 67, $\"{DamageTracker.MaxDamagePerSecond:N2}\");\n\n            AddHtml(20, 50, 213, 100, message, true, true);\n\n            AddButton(20, 160, 4008, 4010, 1, GumpButtonType.Reply, 0);\n            \n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            if (buttonId == 1)\n            {\n                StringBuilder sb = new StringBuilder();\n\n                int x = 1;\n                foreach (KeyValuePair<string, int> dmg in DamageTracker.GetTotalDamageList())\n                {\n                    sb.AppendLine($\"{x}) {dmg.Key} [{dmg.Value:N2}]\");\n                    x++;\n                }\n\n                DamageTrackerListGump dmgList = new DamageTrackerListGump(sb.ToString());\n                dmgList.SendGump();\n            }\n\n            base.OnResponse(buttonId, switches, textEntries);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/DamageTrackerListGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class DamageTrackerListGump : Gump\n    {\n        public DamageTrackerListGump(string message) : base(100, 100)\n        {\n            Movable = true;\n            Closable = true;\n            Disposable = false;\n\n            AddPage(0);\n            AddBackground(0, 0, 273, 318, 9380);\n            AddLabel(69, 5, 2954, \"Damage Dealt (by name)\");\n\t\t\tAddHtml(30, 40, 213, 239, message, true, true);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/HotKeyGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Linq;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class HotKeyGump : Gump\n    {\n        private bool _showAlt { get; }\n        private bool _showCtrl { get; }\n        private bool _showShift { get; }\n\n        public HotKeyGump(bool alt, bool ctrl, bool shift) : base(100, 100)\n        {\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n\n            _showAlt = alt;\n            _showCtrl = ctrl;\n            _showShift = shift;\n\n            int pageCount = 1;\n\n            AddPage(pageCount);\n\n            AddBackground(0, 0, 326, 474, 9270);\n            AddHtml(16, 16, 450, 20, $\"<BASEFONT COLOR=#EC760D>Assigned Hot Keys</BASEFONT> <BASEFONT COLOR=#0DB6EC>({Config.CurrentProfile.Name})</BASEFONT>\", false, false);\n\n            AddFilterElements();\n\n            int labelY = 64;\n            int count = 0;\n\n            foreach (KeyData data in HotKey.List.Where(hk => hk.Key != 0).OrderBy(hk => hk.DisplayName))\n            {\n                if (!_showAlt && (data.Mod & ModKeys.Alt) != 0 || !_showCtrl && (data.Mod & ModKeys.Control) != 0 ||\n                    !_showShift && (data.Mod & ModKeys.Shift) != 0)\n                    continue;\n\n                AddHtml(20, labelY, 500, 20, $\"<BASEFONT COLOR=#FFFFFF>{data.DisplayName}</BASEFONT> <BASEFONT COLOR=#E0E70B>({data.KeyString()})</BASEFONT>\", false, false);\n\n                labelY += 20;\n                count++;\n\n                if (count % 20 == 0)\n                {\n                    AddButton(292, 17, 9903, 9905, pageCount + 2, GumpButtonType.Page, pageCount + 1);\n\n                    pageCount++;\n                    labelY = 64;\n\n                    AddPage(pageCount);\n\n                    AddBackground(0, 0, 326, 480, 9270);\n                    AddHtml(16, 16, 450, 20, $\"<BASEFONT COLOR=#EC760D>Assigned Hot Keys</BASEFONT> <BASEFONT COLOR=#0DB6EC>({Config.CurrentProfile.Name})</BASEFONT>\", false, false);\n                    AddButton(270, 18, 9909, 9911, pageCount + 1, GumpButtonType.Page, pageCount - 1);\n                }\n            }\n        }\n\n        public void AddFilterElements()\n        {\n            AddCheck(16, 38, 210, 211, _showAlt, 1);\n            AddLabel(40, 38, 67, \"Alt\");\n            AddCheck(68, 38, 210, 211, _showCtrl, 2);\n            AddLabel(92, 38, 67, \"Ctrl\");\n            AddCheck(127, 38, 210, 211, _showShift, 3);\n            AddLabel(151, 38, 67, \"Shift\");\n            AddButton(197, 38, 4011, 4012, 1, GumpButtonType.Reply, 0);\n        }\n\n        public override void OnResponse(int buttonID, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            if (buttonID == 1)\n            {\n                bool alt = false;\n                bool ctrl = false;\n                bool shift = false;\n\n                foreach (int check in switches)\n                {\n                    switch (check)\n                    {\n                        case 1:\n                            alt = true;\n                            break;\n                        case 2:\n                            ctrl = true;\n                            break;\n                        case 3:\n                            shift = true;\n                            break;\n                    }\n                }\n\n                CloseGump();\n                HotKeyGump gump = new HotKeyGump(alt, ctrl, shift);\n                gump.SendGump();\n\n            }\n\n            base.OnResponse(buttonID, switches, textEntries);\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Gumps/Internal/InputDialogGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing Assistant.Agents;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class InputDialogGump : Gump\n    {\n        private enum Controls\n        {\n            Okay,\n            InputEntry,\n        }\n        \n        private int _inputReference { get; set; }\n        //private InputDialogTypes _type { get; set; }\n        private readonly Func<int, string, bool> _inputCallback;\n\n        /// <summary>\n        /// Simple input dialog to replace UI based input boxes\n        /// </summary>\n        /// <param name=\"inputCallback\">Method to execute when Okay is pressed</param>\n        /// <param name=\"inputReference\">Optional int to be used as a reference on the callback</param>\n        /// <param name=\"inputRequest\">The text in the gump asking the user to enter something specific</param>\n        /// <param name=\"defaultInput\">Optional string to pre-populate the gump textbox input with</param>\n        public InputDialogGump(Func<int, string, bool> inputCallback, int inputReference, string inputRequest, string defaultInput = \"\") : base(100, 100)\n        {\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n            Resend = false;\n\n            _inputReference = inputReference;\n            _inputCallback = inputCallback;\n\n            AddBackground(105, 70, 253, 121, 3600);\n            AddBackground(129, 115, 209, 22, 9200);\n            AddLabel(125, 90, 2954, inputRequest);\n            AddButton(273, 145, 247, 248, (int)Controls.Okay, GumpButtonType.Reply, 0);\n            AddTextEntry(133, 117, 204, 20, 2954, (int)Controls.InputEntry, defaultInput);\n\n        }\n\n        public override void OnResponse(int buttonID, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            if (buttonID == (int)Controls.Okay)\n            {\n                if (!string.IsNullOrEmpty(textEntries?[0]?.Text))\n                {\n                    _inputCallback(_inputReference, textEntries[0].Text);\n\n                    CloseGump();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Gumps/Internal/ItemInfoGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Windows.Forms;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class ItemInfoGump : Gump\n    {\n        private enum ItemInfoButtons\n        {\n            Okay,\n            CopyItemName,\n            CopySerial,\n            CopyId,\n            CopyHue,\n            ItemName,\n            Serial,\n            Id,\n            Hue\n        }\n\n        private Item _item { get; }\n\n        public ItemInfoGump(Item item) : base(271, 130, -1)\n        {\n            _item = item;\n\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n            Resend = true;\n\n            AddPage(0);\n            \n            AddBackground(106, 70, 253, 189, 3600);\n\n            AddLabel(197, 87, 154, \"Item Data\");\n            AddItem(290, 98, item.ItemID);\n\n            AddLabel(143, 115, 900, \"Item Name:\");\n            AddLabel(142, 140, 900, \"Serial:\");\n            AddLabel(142, 164, 900, \"Id:\");\n            AddLabel(142, 188, 900, \"Hue:\");\n\n            AddButton(274, 217, 247, 248, (int)ItemInfoButtons.Okay, GumpButtonType.Reply, 0);\n            AddButton(124, 120, 2103, 2104, (int)ItemInfoButtons.CopyItemName, GumpButtonType.Reply, 0);\n            AddButton(124, 143, 2103, 2104, (int)ItemInfoButtons.CopySerial, GumpButtonType.Reply, 0);\n            AddButton(124, 168, 2103, 2104, (int)ItemInfoButtons.CopyId, GumpButtonType.Reply, 0);\n            AddButton(124, 191, 2103, 2104, (int)ItemInfoButtons.CopyHue, GumpButtonType.Reply, 0);\n            \n            AddTextEntry(219, 115, 116, 20, 62, (int)ItemInfoButtons.ItemName, $\"{item.ItemID.ItemData.Name}\");\n            AddTextEntry(219, 141, 116, 20, 62, (int)ItemInfoButtons.Serial, $\"{item.Serial}\");\n            AddTextEntry(219, 165, 116, 20, 62, (int)ItemInfoButtons.Id, $\"{item.ItemID.Value}\");\n\n            if (item.Hue == 0)\n                AddTextEntry(219, 188, 116, 20, 62, (int)ItemInfoButtons.Hue, \"Default (0)\");\n            else\n                AddTextEntry(219, 188, 116, 20, item.Hue - 1, (int)ItemInfoButtons.Hue, $\"{item.Hue}\");\n\n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            switch (buttonId)\n            {\n                case (int)ItemInfoButtons.CopyItemName:\n                    Clipboard.SetText(_item.ItemID.ItemData.Name);\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _item.ItemID.ItemData.Name), false);\n                    break;\n                case (int)ItemInfoButtons.CopySerial:\n                    Clipboard.SetText(_item.Serial.ToString());\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _item.Serial.ToString()), false);\n                    break;\n                case (int)ItemInfoButtons.CopyId:\n                    Clipboard.SetText(_item.ItemID.Value.ToString());\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _item.ItemID.Value.ToString()), false);\n                    break;\n                case (int)ItemInfoButtons.CopyHue:\n                    Clipboard.SetText(_item.Hue.ToString());\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _item.Hue.ToString()), false);\n                    break;\n                case (int)ItemInfoButtons.Okay:\n                    Resend = false;\n                    break;\n            }\n\n            base.OnResponse(buttonId, switches, textEntries);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/MobileInfoGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class MobileInfoGump : Gump\n    {\n        private enum MobileInfoButtons\n        {\n            Okay,\n            CopyName,\n            CopySerial,\n            CopyHue,\n            CopyBody,\n            Name,\n            Serial,\n            Hue,\n            Body\n        }\n\n        private Mobile _mobile { get; }\n\n        public MobileInfoGump(Mobile mobile) : base(500, 250, -1)\n        {\n            _mobile = mobile;\n\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n            Resend = true;\n\n            AddPage(0);\n\n            AddBackground(106, 72, 253, 289, 3600);\n\n            AddLabel(143, 115, 900, \"Name:\");\n            AddLabel(142, 140, 900, \"Serial:\");\n            AddLabel(142, 164, 900, \"Hue:\");\n            AddLabel(142, 188, 900, \"Body:\");\n            AddLabel(197, 87, 154, \"Mobile Data\");\n\n            AddButton(276, 318, 247, 248, (int)MobileInfoButtons.Okay, GumpButtonType.Reply, 0);\n\n            AddButton(124, 121, 2103, 2104, (int)MobileInfoButtons.CopyName, GumpButtonType.Reply, 0);\n            AddButton(124, 144, 2103, 2104, (int)MobileInfoButtons.CopySerial, GumpButtonType.Reply, 0);\n            AddButton(124, 169, 2103, 2104, (int)MobileInfoButtons.CopyHue, GumpButtonType.Reply, 0);\n            AddButton(124, 194, 2103, 2104, (int)MobileInfoButtons.CopyBody, GumpButtonType.Reply, 0);\n\n            AddTextEntry(219, 118, 116, 20, 62, (int)MobileInfoButtons.Name, $\"{mobile.Name}\");\n            AddTextEntry(219, 142, 116, 20, 62, (int)MobileInfoButtons.Serial, $\"{mobile.Serial}\");\n            AddTextEntry(219, 166, 116, 20, 62, (int)MobileInfoButtons.Hue, $\"{mobile.Hue}\");\n\n            AddTextEntry(219, 190, 116, 20, 62, (int) MobileInfoButtons.Body, $\"{mobile.Body}\");\n\n            StringBuilder sb = new StringBuilder();\n            sb.AppendLine($\"Position: {_mobile.Position}\");\n            sb.AppendLine($\"Notoriety: {_mobile.Notoriety}\");\n            sb.AppendLine($\"IsGhost: {mobile.IsGhost}\");\n            sb.AppendLine($\"IsHuman: {mobile.IsHuman}\");\n            sb.AppendLine($\"IsMonster: {mobile.IsMonster}\");\n            sb.AppendLine($\"Blessed: {mobile.Blessed}\");\n\n            AddHtml(124, 223, 211, 88, sb.ToString(), true, true);\n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            switch (buttonId)\n            {\n                case (int)MobileInfoButtons.CopyName:\n                    Clipboard.SetText(_mobile.Name);\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _mobile.Name), false);\n                    break;\n                case (int)MobileInfoButtons.CopySerial:\n                    Clipboard.SetText(_mobile.Serial.ToString());\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _mobile.Serial.ToString()), false);\n                    break;\n                case (int)MobileInfoButtons.CopyHue:\n                    Clipboard.SetText(_mobile.Hue.ToString());\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _mobile.Hue.ToString()), false);\n                    break;\n                case (int)MobileInfoButtons.CopyBody:\n                    Clipboard.SetText(_mobile.Body.ToString());\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, _mobile.Body.ToString()), false);\n                    break;\n                case (int)MobileInfoButtons.Okay:\n                    Resend = false;\n                    break;\n            }\n\n            base.OnResponse(buttonId, switches, textEntries);\n        }\n    }\n}"
  },
  {
    "path": "Razor/Gumps/Internal/SystemMessagesGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Linq;\nusing System.Windows.Forms;\nusing Assistant.Core;\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class SystemMessagesGump : Gump\n    {\n        public SystemMessagesGump() : base(0, 0)\n        {\n            Closable = true;\n            Disposable = true;\n            Movable = true;\n            Resizable = false;\n            Resend = true;\n\n            int pageCount = 1;\n\n            AddPage(pageCount);\n            AddBackground(0, 0, 527, 201, 9270);\n            AddLabel(18, 13, 252, $\"System Messages ({SystemMessages.Messages.Count})\");\n            AddButton(460, 15, 9909, 9911, 1234, GumpButtonType.Page, pageCount);\n            AddButton(483, 14, 9903, 9905, 1235, GumpButtonType.Page, pageCount + 1);\n\n            int textY = 40;\n            int buttonY = 42;\n            int id = 0;\n            int count = 0;\n\n            foreach (string message in SystemMessages.Messages.ToArray().Reverse())\n            {\n                AddButton(18, buttonY, 1209, 1210, id, GumpButtonType.Reply, 0);\n                AddTextEntry(44, textY, 463, 20, 2954, id, SystemMessages.Messages[count]);\n\n                id++;\n                count++;\n                buttonY += 30;\n                textY += 30;\n\n                if (count % 5 == 0)\n                {\n                    AddButton(483, 14, 9903, 9905, pageCount + 2, GumpButtonType.Page, pageCount + 1);\n\n                    pageCount++;\n                    textY = 40;\n                    buttonY = 42;\n\n                    AddPage(pageCount);\n                    AddBackground(0, 0, 527, 201, 9270);\n                    AddLabel(18, 13, 252, $\"System Messages ({SystemMessages.Messages.Count})\");\n                    AddButton(460, 15, 9909, 9911, pageCount + 1, GumpButtonType.Page, pageCount - 1);\n                }\n            }\n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            if (buttonId == 0)\n            {\n                Resend = false;\n                CloseGump();\n\n                return;\n            }\n\n            if (buttonId > SystemMessages.Messages.Count)\n                return;\n\n            Clipboard.SetText(SystemMessages.Messages[buttonId]);\n            World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, SystemMessages.Messages[buttonId]), false);\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Gumps/Internal/TestMessageGump.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Assistant.Gumps.Internal\n{\n    public sealed class TestMessageGump : Gump\n    {\n        public TestMessageGump(string message) : base(500, 250, -1)\n        {\n            X = 300;\n            Y = 200;\n\n            Movable = true;\n            Closable = true;\n            Disposable = false;\n\n            AddPage(0);\n            AddBackground(0, 0, 500, 400, 9270);\n            AddHtml(20, 20, 460, 330, message, true, true);\n            AddButton(200, 360, 247, 248, 0, GumpButtonType.Reply, 0);\n            AddButton(420, 360, 247, 248, 1, GumpButtonType.Reply, 0);\n        }\n\n        public override void OnResponse(int buttonId, int[] switches, GumpTextEntry[] textEntries = null)\n        {\n            World.Player.OverheadMessage($\"Button {buttonId}\");\n            base.OnResponse(buttonId, switches, textEntries);\n        }\n    }\n}"
  },
  {
    "path": "Razor/HotKeys/Counters.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nnamespace Assistant.HotKeys\r\n{\r\n    public class CounterHotKeys\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            HotKey.Add(HKCategory.Misc, LocString.DispCounters, new HotKeyCallback(DispCounters));\r\n            HotKey.Add(HKCategory.Misc, LocString.RecountCounters, new HotKeyCallback(Recount));\r\n        }\r\n\r\n        private static void Recount()\r\n        {\r\n            Counter.FullRecount();\r\n        }\r\n\r\n        private static void DispCounters()\r\n        {\r\n            for (int i = 0; i < Counter.List.Count; i++)\r\n            {\r\n                Counter c = (Counter) Counter.List[i];\r\n\r\n                if (c.Enabled)\r\n                    World.Player.SendMessage(MsgLevel.Force, \"{0}: {1}\", c.Name, c.Amount);\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/HotKeys/HotKeys.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Windows.Forms;\r\nusing System.Text;\r\nusing System.Xml;\r\nusing Assistant.Scripts;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant\r\n{\r\n    [Flags]\r\n    public enum ModKeys : int\r\n    {\r\n        None = 0,\r\n        Alt = 0x0001,\r\n        Control = 0x0002,\r\n        Shift = 0x0004\r\n    }\r\n\r\n    public delegate void HotKeyCallback();\r\n\r\n    public delegate void HotKeyCallbackState(ref object state);\r\n\r\n    public enum HKCategory\r\n    {\r\n        None = 0,\r\n        Items,\r\n        Targets,\r\n        Agents,\r\n        Dress,\r\n        Macros,\r\n        Spells,\r\n        Skills,\r\n        Misc,\r\n        Friends,\r\n        Scripts\r\n    }\r\n\r\n    public enum HKSubCat\r\n    {\r\n        None = 0,\r\n\r\n        // spells: (these all are # oriented, so be careful)\r\n        SpellOffset,\r\n        FirstC,\r\n        SecondC,\r\n        ThirdC,\r\n        FourthC,\r\n        FifthC,\r\n        SixthC,\r\n        SeventhC,\r\n        EighthC,\r\n        NecroC = SpellOffset + 10,\r\n        PaladinC = SpellOffset + 20,\r\n\r\n        //items\r\n        Potions,\r\n\r\n        // misc:\r\n        SpecialMoves,\r\n\r\n        // more # oriented, CAUTION!\r\n        BushidoC = SpellOffset + 40,\r\n        NinjisuC = SpellOffset + 50,\r\n        SpellWeaveC = SpellOffset + 60,\r\n        MystC = SpellOffset + 65,\r\n        MasteriesC = SpellOffset + 70,\r\n\r\n        // pet commands\r\n        PetCommands = 780, //1749\r\n\r\n        SubTargetCriminal = 796,\r\n        SubTargetEnemy,\r\n        SubTargetFriendly,\r\n        SubTargetGrey,\r\n        SubTargetInnocent,\r\n        SubTargetMurderer,\r\n        SubTargetNonFriendly,\r\n    }\r\n\r\n    public class KeyData\r\n    {\r\n        private int _name;\r\n        private string _sName;\r\n        private HotKeyCallback _callback;\r\n        private HotKeyCallbackState _callbackState;\r\n        private bool _sendToUO;\r\n        private int _key;\r\n        private ModKeys _mod;\r\n        private TreeNode _node;\r\n        private object _state;\r\n        private string _command;\r\n\r\n        public object pState => _state;\r\n\r\n        private DateTime _lastTriggerTime = DateTime.MinValue;\r\n\r\n        public string DisplayName => _name != 0 ? Language.GetString(_name) : _sName;\r\n\r\n        public int LocName => _name;\r\n\r\n        public string StrName => _sName;\r\n\r\n        public string Command\r\n        {\r\n            get => _command;\r\n            set => _command = value;\r\n        }\r\n\r\n        public KeyData(int name, HKCategory cat, HKSubCat sub, HotKeyCallback call)\r\n        {\r\n            _name = name;\r\n            _sName = null;\r\n            _callback = call;\r\n            _callbackState = null;\r\n            _node = HotKey.MakeNode(HotKey.FindParent(cat, sub), ToString(), this);\r\n        }\r\n\r\n        public KeyData(int name, HKCategory cat, HKSubCat sub, HotKeyCallbackState call, object state)\r\n        {\r\n            _name = name;\r\n            _sName = null;\r\n            _callback = null;\r\n            _callbackState = call;\r\n            _state = state;\r\n            _node = HotKey.MakeNode(HotKey.FindParent(cat, sub), ToString(), this);\r\n        }\r\n\r\n        public KeyData(string name, HKCategory cat, HKSubCat sub, HotKeyCallback call)\r\n        {\r\n            _name = 0;\r\n            _sName = name;\r\n            _callback = call;\r\n            _callbackState = null;\r\n            _node = HotKey.MakeNode(HotKey.FindParent(cat, sub), ToString(), this);\r\n        }\r\n\r\n        public KeyData(string name, HKCategory cat, HKSubCat sub, HotKeyCallbackState call, object state)\r\n        {\r\n            _name = 0;\r\n            _sName = name;\r\n            _callback = null;\r\n            _callbackState = call;\r\n            _state = state;\r\n            _node = HotKey.MakeNode(HotKey.FindParent(cat, sub), ToString(), this);\r\n        }\r\n\r\n        public void Callback()\r\n        {\r\n            // protect again weird keyboard oddities which \"double press\" the keys when the user only wanted to do an action once\r\n            if (_lastTriggerTime + TimeSpan.FromMilliseconds(20) <= DateTime.UtcNow)\r\n            {\r\n                _lastTriggerTime = DateTime.UtcNow;\r\n\r\n                if (_callback != null)\r\n                    _callback();\r\n                else if (_callbackState != null)\r\n                    _callbackState(ref _state);\r\n            }\r\n        }\r\n\r\n        public void Remove()\r\n        {\r\n            _node.Remove();\r\n            _node.Text = \"removed\";\r\n        }\r\n\r\n        public bool SendToUO\r\n        {\r\n            get => _sendToUO;\r\n            set => _sendToUO = value;\r\n        }\r\n\r\n        public int Key\r\n        {\r\n            get => _key;\r\n            set\r\n            {\r\n                if (_key != value)\r\n                {\r\n                    _key = value;\r\n                    _node.Text = ToString();\r\n                }\r\n            }\r\n        }\r\n\r\n        public ModKeys Mod\r\n        {\r\n            get => _mod;\r\n            set\r\n            {\r\n                if (_mod != value)\r\n                {\r\n                    _mod = value;\r\n                    _node.Text = ToString();\r\n                }\r\n            }\r\n        }\r\n\r\n        public string KeyString(bool smallNames = false)\r\n        {\r\n            if (Key != 0)\r\n            {\r\n                StringBuilder sb = new StringBuilder();\r\n                bool np = false;\r\n\r\n                if ((Mod & ModKeys.Control) != 0)\r\n                {\r\n                    sb.Append(smallNames ? \"Ctrl\" : \"Control\");\r\n\r\n                    np = true;\r\n                }\r\n\r\n                if ((Mod & ModKeys.Alt) != 0)\r\n                {\r\n                    if (np)\r\n                        sb.Append(\"+\");\r\n                    sb.Append(\"Alt\");\r\n                    np = true;\r\n                }\r\n\r\n                if ((Mod & ModKeys.Shift) != 0)\r\n                {\r\n                    if (np)\r\n                        sb.Append(\"+\");\r\n                    sb.Append(smallNames ? \"Sft\" : \"Shift\");\r\n                    np = true;\r\n                }\r\n\r\n                if (np)\r\n                    sb.Append(\"+\");\r\n\r\n                switch (Key)\r\n                {\r\n                    case -1:\r\n                        sb.Append(\"Wheel UP\");\r\n                        break;\r\n                    case -2:\r\n                        sb.Append(\"Wheel DOWN\");\r\n                        break;\r\n                    case -3:\r\n                        sb.Append(\"Middle Button\");\r\n                        break;\r\n                    case -4:\r\n                        sb.Append(\"XButton 1\");\r\n                        break;\r\n                    case -5:\r\n                        sb.Append(\"XButton 2\");\r\n                        break;\r\n                    default:\r\n                        sb.Append(((Keys) Key).ToString());\r\n                        break;\r\n                }\r\n\r\n                return sb.ToString();\r\n            }\r\n            else\r\n            {\r\n                return null;\r\n            }\r\n        }\r\n\r\n\r\n        public override string ToString()\r\n        {\r\n            if (Key != 0)\r\n                return $\"{this.DisplayName} ({KeyString()})\";\r\n            \r\n            return $\"{this.DisplayName} ({Language.GetString(LocString.NotAssigned)})\";\r\n        }\r\n    }\r\n\r\n    public class HotKey\r\n    {\r\n        private static List<KeyData> m_List = new List<KeyData>();\r\n        private static TreeNode m_Root = new TreeNode(\"Hot Keys\");\r\n        private static bool m_Enabled;\r\n        private static System.Windows.Forms.Label m_Status;\r\n        private static KeyData m_HK_En;\r\n\r\n        private static KeyData _hotKeyEnableToggle;\r\n        private static KeyData _hotKeyDisableToggle;\r\n\r\n        public static List<KeyData> List\r\n        {\r\n            get { return m_List; }\r\n        }\r\n\r\n        public static TreeNode RootNode\r\n        {\r\n            get { return m_Root; }\r\n        }\r\n\r\n        public static System.Windows.Forms.Label Status\r\n        {\r\n            get { return m_Status; }\r\n            set\r\n            {\r\n                m_Status = value;\r\n                UpdateStatus();\r\n            }\r\n        }\r\n\r\n\r\n        public static bool KeyDown(Keys k)\r\n        {\r\n            return (Platform.GetAsyncKeyState((int) k) & 0xFF00) != 0; //|| Client.IsKeyDown( (int)k );\r\n        }\r\n\r\n        public static void Initialize()\r\n        {\r\n            m_HK_En = Add(HKCategory.None, LocString.ToggleHKEnable, new HotKeyCallback(OnToggleEnableDisable));\r\n\r\n            _hotKeyEnableToggle = Add(HKCategory.None, LocString.EnableHotkeys, OnToggleEnable);\r\n            _hotKeyDisableToggle = Add(HKCategory.None, LocString.DisableHotkeys, OnToggleDisable);\r\n        }\r\n\r\n        private static void OnToggleEnableDisable()\r\n        {\r\n            m_Enabled = !m_Enabled;\r\n\r\n            MsgLevel type = MsgLevel.Warning;\r\n\r\n            if (m_Enabled)\r\n            {\r\n                type = MsgLevel.Info;\r\n            }\r\n\r\n            if (World.Player != null)\r\n                World.Player.SendMessage(type, UpdateStatus());\r\n        }\r\n\r\n        private static void OnToggleEnable()\r\n        {\r\n            if (m_Enabled)\r\n            {\r\n                if (World.Player != null)\r\n                    World.Player.SendMessage(MsgLevel.Warning, \"HotKeys are already enabled\");\r\n            }\r\n            else\r\n            {\r\n                m_Enabled = !m_Enabled;\r\n                if (World.Player != null)\r\n                    World.Player.SendMessage(MsgLevel.Info, UpdateStatus());\r\n            }\r\n        }\r\n\r\n        private static void OnToggleDisable()\r\n        {\r\n            if (!m_Enabled)\r\n            {\r\n                if (World.Player != null)\r\n                    World.Player.SendMessage(MsgLevel.Warning, \"HotKeys are already disabled\");\r\n            }\r\n            else\r\n            {\r\n                m_Enabled = !m_Enabled;\r\n                if (World.Player != null)\r\n                    World.Player.SendMessage(MsgLevel.Warning, UpdateStatus());\r\n            }\r\n        }\r\n\r\n\r\n        public static string UpdateStatus()\r\n        {\r\n            KeyData kd = Get((int) LocString.ToggleHKEnable);\r\n            string ks = null;\r\n            if (kd != null)\r\n                ks = kd.KeyString();\r\n\r\n            string msg;\r\n            if (ks != null)\r\n            {\r\n                if (m_Enabled)\r\n                    msg = Language.Format(LocString.HKEnabledPress, ks);\r\n                else\r\n                    msg = Language.Format(LocString.HKDisabledPress, ks);\r\n            }\r\n            else\r\n            {\r\n                if (m_Enabled)\r\n                    msg = Language.GetString(LocString.HKEnabled);\r\n                else\r\n                    msg = Language.GetString(LocString.HKDisabled);\r\n            }\r\n\r\n            m_Status?.SafeAction(s => { s.Text = msg; });\r\n\r\n            return msg;\r\n        }\r\n\r\n        public static bool ValidateCommand(string command)\r\n        {\r\n            if (string.IsNullOrEmpty(command))\r\n            {\r\n                return false;\r\n            }\r\n\r\n            foreach (KeyData keyData in List)\r\n            {\r\n                if (!string.IsNullOrEmpty(keyData.Command) && keyData.Command.Equals(command, StringComparison.OrdinalIgnoreCase))\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            foreach (string cmd in Command.GetCommands)\r\n            {\r\n                if (!string.IsNullOrEmpty(cmd) && cmd.Equals(command, StringComparison.OrdinalIgnoreCase))\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public static bool ExecuteCommand(string command)\r\n        {\r\n            foreach (KeyData keyData in List)\r\n            {\r\n                if (!string.IsNullOrEmpty(keyData.Command) && keyData.Command.Equals(command, StringComparison.OrdinalIgnoreCase))\r\n                {\r\n                    keyData.Callback();\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        static HotKey()\r\n        {\r\n            m_Enabled = true;\r\n\r\n            m_Root.Tag = (int) LocString.HotKeys;\r\n\r\n            TreeNode items = MakeNode(\"Items\", HKCategory.Items);\r\n\r\n            MakeNode(items, \"Potions\", HKSubCat.Potions);\r\n\r\n            TreeNode targets = MakeNode(\"Targets\", HKCategory.Targets);\r\n\r\n            MakeNode(targets, \"Criminal Targets\", HKSubCat.SubTargetCriminal);\r\n            MakeNode(targets, \"Enemy Targets\", HKSubCat.SubTargetEnemy);\r\n            MakeNode(targets, \"Friendly Targets\", HKSubCat.SubTargetFriendly);\r\n            MakeNode(targets, \"Grey Targets\", HKSubCat.SubTargetGrey);\r\n            MakeNode(targets, \"Innocent Targets\", HKSubCat.SubTargetInnocent);\r\n            MakeNode(targets, \"Murderer Targets\", HKSubCat.SubTargetMurderer);\r\n            MakeNode(targets, \"Non-Friendly Targets\", HKSubCat.SubTargetNonFriendly);\r\n\r\n            MakeNode(\"Agents\", HKCategory.Agents);\r\n\r\n            MakeNode(\"Dress\", HKCategory.Dress);\r\n\r\n            MakeNode(\"Macros\", HKCategory.Macros);\r\n\r\n            TreeNode spells = MakeNode(\"Spells\", HKCategory.Spells);\r\n            MakeNode(spells, \"1st\", HKSubCat.FirstC);\r\n            MakeNode(spells, \"2nd\", HKSubCat.SecondC);\r\n            MakeNode(spells, \"3rd\", HKSubCat.ThirdC);\r\n            MakeNode(spells, \"4th\", HKSubCat.FourthC);\r\n            MakeNode(spells, \"5th\", HKSubCat.FifthC);\r\n            MakeNode(spells, \"6th\", HKSubCat.SixthC);\r\n            MakeNode(spells, \"7th\", HKSubCat.SeventhC);\r\n            MakeNode(spells, \"8th\", HKSubCat.EighthC);\r\n            MakeNode(spells, \"Necro\", HKSubCat.NecroC);\r\n            MakeNode(spells, \"Paladin\", HKSubCat.PaladinC);\r\n            MakeNode(spells, \"Bushido\", HKSubCat.BushidoC);\r\n            MakeNode(spells, \"Ninjisu\", HKSubCat.NinjisuC);\r\n            MakeNode(spells, \"Spellweaving\", HKSubCat.SpellWeaveC);\r\n            MakeNode(spells, \"Mysticism\", HKSubCat.MystC);\r\n            MakeNode(spells, \"Masteries\", HKSubCat.MasteriesC);\r\n\r\n            MakeNode(\"Skills\", HKCategory.Skills);\r\n\r\n            TreeNode misc = MakeNode(\"Misc\", HKCategory.Misc);\r\n            MakeNode(misc, \"Special Moves\", HKSubCat.SpecialMoves);\r\n            MakeNode(misc, \"Pet Commands\", HKSubCat.PetCommands);\r\n\r\n            MakeNode(\"Friends\", HKCategory.Friends);\r\n            MakeNode(\"Scripts\", HKCategory.Scripts);\r\n        }\r\n\r\n        public static void RebuildList(TreeView tree)\r\n        {\r\n            tree.BeginUpdate();\r\n            UpdateNode(m_Root);\r\n\r\n            tree.Nodes.Clear();\r\n            tree.Nodes.Add(m_Root);\r\n            m_Root.Expand();\r\n            tree.EndUpdate();\r\n        }\r\n\r\n        private static void UpdateNode(TreeNode node)\r\n        {\r\n            if (node != null)\r\n            {\r\n                if (node.Tag is KeyData)\r\n                    node.Text = ((KeyData) node.Tag).ToString();\r\n                else if (node.Tag is HKCategory)\r\n                    node.Text = Language.GetString((int) LocString.HotKeys + (int) ((HKCategory) node.Tag));\r\n                else if (node.Tag is HKSubCat)\r\n                    node.Text = Language.GetString(GetHKSubCatLangKey((HKSubCat) node.Tag));\r\n                else if (node.Tag is Int32)\r\n                    node.Text = Language.GetString((int) node.Tag);\r\n\r\n                if (node != m_Root && node.NextNode != null)\r\n                    UpdateNode(node.NextNode);\r\n                if (node.GetNodeCount(true) > 0)\r\n                    UpdateNode(node.FirstNode);\r\n            }\r\n        }\r\n\r\n        private static int GetHKSubCatLangKey(HKSubCat tag)\r\n        {\r\n            switch (tag)\r\n            {\r\n                case HKSubCat.MystC:\r\n                    return 2103;\r\n                case HKSubCat.MasteriesC:\r\n                    return 2104;\r\n                default:\r\n                    return (int)LocString.HKSubOffset + (int) tag;\r\n            }\r\n        }\r\n\r\n        public static void ClearAll()\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                KeyData kd = m_List[i];\r\n                kd.Key = 0;\r\n                kd.Mod = ModKeys.None;\r\n                kd.SendToUO = false;\r\n            }\r\n        }\r\n\r\n        public static KeyData GetFromObj(object other)\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                if (m_List[i].pState == other)\r\n                    return m_List[i];\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        public static KeyData Get(int name)\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                if (((KeyData) m_List[i]).LocName == name)\r\n                    return (KeyData) m_List[i];\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        public static KeyData Get(string name)\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                if (((KeyData) m_List[i]).StrName == name)\r\n                    return (KeyData) m_List[i];\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        public static KeyData GetByNameOrId(string query)\r\n        {\r\n            foreach (KeyData key in m_List)\r\n            {\r\n                if (key.DisplayName.ToLower().Equals(query.ToLower()))\r\n                    return key;\r\n            }\r\n\r\n            int hkIndex = Utility.ToInt32(query, -1);\r\n\r\n            return hkIndex != -1 ? m_List[hkIndex] : null;\r\n        }\r\n\r\n        public static KeyData Get(int key, ModKeys mod)\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                KeyData hk = (KeyData) m_List[i];\r\n                if (hk.Key == key && hk.Mod == mod && hk.Key != 0)\r\n                    return hk;\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        public static TreeNode FindParent(TreeNode root, HKCategory cat, HKSubCat sub)\r\n        {\r\n            TreeNode parent = root;\r\n            if (cat != HKCategory.None)\r\n            {\r\n                parent = FindNode(root, cat);\r\n                if (sub != HKSubCat.None && parent != null)\r\n                {\r\n                    TreeNode subNode = FindNode(parent, sub);\r\n                    if (subNode != null)\r\n                        parent = subNode;\r\n                }\r\n            }\r\n\r\n            return parent;\r\n        }\r\n\r\n        public static TreeNode FindParent(HKCategory cat, HKSubCat sub)\r\n        {\r\n            return FindParent(m_Root, cat, sub);\r\n        }\r\n\r\n        public static TreeNode MakeNode(TreeNode parent, string text, object tag)\r\n        {\r\n            TreeNode n = new TreeNode(text);\r\n            n.Tag = tag;\r\n            parent.Nodes.Add(n);\r\n            return n;\r\n        }\r\n\r\n        public static TreeNode MakeNode(string text, object tag)\r\n        {\r\n            return MakeNode(m_Root, text, tag);\r\n        }\r\n\r\n        public static TreeNode FindNode(TreeNode parent, object tag, bool recurse)\r\n        {\r\n            if (tag == null)\r\n                return null;\r\n\r\n            TreeNode n = parent.FirstNode;\r\n            while (n != null)\r\n            {\r\n                if (tag.ToString() == n.Tag.ToString())\r\n                    break;\r\n\r\n                if (recurse)\r\n                {\r\n                    TreeNode r = FindNode(n, tag, true);\r\n                    if (r != null)\r\n                        return r;\r\n                }\r\n\r\n                n = n.NextNode;\r\n            }\r\n\r\n            return n;\r\n        }\r\n\r\n        public static TreeNode FindNode(TreeNode parent, object tag)\r\n        {\r\n            return FindNode(parent, tag, false);\r\n        }\r\n\r\n        public static bool OnKeyDown(int key, ModKeys mod)\r\n        {\r\n            if (World.Player == null)\r\n                return true;\r\n            ModKeys cur = mod;\r\n            if (KeyDown(Keys.ControlKey))\r\n                cur |= ModKeys.Control;\r\n            if (KeyDown(Keys.Menu))\r\n                cur |= ModKeys.Alt;\r\n            if (KeyDown(Keys.ShiftKey))\r\n                cur |= ModKeys.Shift;\r\n\r\n            if (m_HK_En != null && m_HK_En.Key > 0 && m_HK_En.Mod == cur &&\r\n                (m_HK_En.Key == key || KeyDown((Keys) m_HK_En.Key)))\r\n            {\r\n                m_HK_En.Callback();\r\n                return m_HK_En.SendToUO;\r\n            }\r\n\r\n            if (_hotKeyEnableToggle != null && _hotKeyEnableToggle.Key > 0 && _hotKeyEnableToggle.Mod == cur &&\r\n                (_hotKeyEnableToggle.Key == key || KeyDown((Keys) _hotKeyEnableToggle.Key)))\r\n            {\r\n                _hotKeyEnableToggle.Callback();\r\n                return _hotKeyEnableToggle.SendToUO;\r\n            }\r\n\r\n            if (_hotKeyDisableToggle != null && _hotKeyDisableToggle.Key > 0 && _hotKeyDisableToggle.Mod == cur &&\r\n                (_hotKeyDisableToggle.Key == key || KeyDown((Keys) _hotKeyDisableToggle.Key)))\r\n            {\r\n                _hotKeyDisableToggle.Callback();\r\n                return _hotKeyDisableToggle.SendToUO;\r\n            }\r\n\r\n            if (m_Enabled)\r\n            {\r\n                for (int i = 0; i < m_List.Count; i++)\r\n                {\r\n                    KeyData hk = (KeyData) m_List[i];\r\n                    if (hk.Mod == cur && hk.Key > 0)\r\n                    {\r\n                        if (hk.Key == key)\r\n                        {\r\n                            if (Macros.MacroManager.AcceptActions)\r\n                                Macros.MacroManager.Action(new Macros.HotKeyAction(hk));\r\n\r\n                            ScriptManager.AddToScript($\"hotkey '{hk.DisplayName}'\");\r\n\r\n                            hk.Callback();\r\n                            return hk.SendToUO;\r\n                        }\r\n                    }\r\n                }\r\n\r\n                // if pressed key didn't match a hotkey, check for any key currently down\r\n                for (int i = 0; i < m_List.Count; i++)\r\n                {\r\n                    KeyData hk = (KeyData) m_List[i];\r\n                    if (hk.Mod == cur && hk.Key > 0)\r\n                    {\r\n                        if (KeyDown((Keys) hk.Key))\r\n                        {\r\n                            if (Macros.MacroManager.AcceptActions)\r\n                                Macros.MacroManager.Action(new Macros.HotKeyAction(hk));\r\n\r\n                            ScriptManager.AddToScript($\"hotkey '{hk.DisplayName}'\");\r\n\r\n                            hk.Callback();\r\n                            return hk.SendToUO;\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public static void OnMouse(int button, int wheel)\r\n        {\r\n            if (World.Player == null || !m_Enabled)\r\n                return;\r\n\r\n            ModKeys cur = ModKeys.None;\r\n            int key = 0;\r\n            switch (button)\r\n            {\r\n                case 0:\r\n                    key = wheel > 0 ? -1 : -2;\r\n                    break;\r\n                case 1:\r\n                    key = -3;\r\n                    break;\r\n                case 2:\r\n                    key = -4;\r\n                    break;\r\n                case 3:\r\n                    key = -5;\r\n                    break;\r\n            }\r\n\r\n            if (KeyDown(Keys.ControlKey))\r\n                cur |= ModKeys.Control;\r\n            if (KeyDown(Keys.Menu))\r\n                cur |= ModKeys.Alt;\r\n            if (KeyDown(Keys.ShiftKey))\r\n                cur |= ModKeys.Shift;\r\n\r\n            KeyData hk = Get(key, cur);\r\n            if (hk != null)\r\n                hk.Callback();\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, int name, HotKeyCallback callback)\r\n        {\r\n            return Add(cat, HKSubCat.None, name, callback);\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, LocString name, HotKeyCallback callback)\r\n        {\r\n            return Add(cat, HKSubCat.None, (int) name, callback);\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, HKSubCat sub, int name, HotKeyCallback callback)\r\n        {\r\n            KeyData kd = new KeyData(name, cat, sub, callback);\r\n            m_List.Add(kd);\r\n            return kd;\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, HKSubCat sub, LocString name, HotKeyCallback callback)\r\n        {\r\n            KeyData kd = new KeyData((int) name, cat, sub, callback);\r\n            m_List.Add(kd);\r\n            return kd;\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, HKSubCat sub, string name, HotKeyCallback callback)\r\n        {\r\n            KeyData kd = new KeyData(name, cat, sub, callback);\r\n            m_List.Add(kd);\r\n            return kd;\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, int name, HotKeyCallbackState callback, object state)\r\n        {\r\n            return Add(cat, HKSubCat.None, name, callback, state);\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, LocString name, HotKeyCallbackState callback, object state)\r\n        {\r\n            return Add(cat, HKSubCat.None, (int) name, callback, state);\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, HKSubCat sub, int name, HotKeyCallbackState callback, object state)\r\n        {\r\n            KeyData kd = new KeyData(name, cat, sub, callback, state);\r\n            m_List.Add(kd);\r\n            return kd;\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, HKSubCat sub, LocString name, HotKeyCallbackState callback,\r\n            object state)\r\n        {\r\n            KeyData kd = new KeyData((int) name, cat, sub, callback, state);\r\n            m_List.Add(kd);\r\n            return kd;\r\n        }\r\n\r\n        public static KeyData Add(HKCategory cat, HKSubCat sub, string name, HotKeyCallbackState callback, object state)\r\n        {\r\n            KeyData kd = new KeyData(name, cat, sub, callback, state);\r\n            m_List.Add(kd);\r\n            return kd;\r\n        }\r\n\r\n        public static bool Remove(int name)\r\n        {\r\n            if (name == 0)\r\n                return false;\r\n\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                KeyData hk = (KeyData) m_List[i];\r\n                if (hk.LocName == name)\r\n                {\r\n                    hk.Remove();\r\n                    m_List.RemoveAt(i);\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public static bool Remove(string name)\r\n        {\r\n            if (name == null)\r\n                return false;\r\n\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                KeyData hk = (KeyData) m_List[i];\r\n                if (hk.StrName == name)\r\n                {\r\n                    hk.Remove();\r\n                    m_List.RemoveAt(i);\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public static void Load(XmlElement xml)\r\n        {\r\n            if (xml == null)\r\n                return;\r\n\r\n            ClearAll();\r\n\r\n            foreach (XmlElement el in xml.GetElementsByTagName(\"key\"))\r\n            {\r\n                try\r\n                {\r\n                    string name = el.GetAttribute(\"name\");\r\n                    string loc = el.GetAttribute(\"loc\");\r\n                    string mod = el.GetAttribute(\"mod\");\r\n                    string key = el.GetAttribute(\"key\");\r\n                    string send = el.GetAttribute(\"send\");\r\n                    string command = el.GetAttribute(\"command\");\r\n\r\n                    if (!ValidateCommand(command))\r\n                    {\r\n                        command = string.Empty;\r\n                    }\r\n\r\n                    KeyData k = null;\r\n\r\n                    if (loc != null && loc.Length > 0)\r\n                    {\r\n                        k = Get(Convert.ToInt32(loc));\r\n                    }\r\n                    else if (name != null && name.Length > 0)\r\n                    {\r\n                        k = Get(name);\r\n                    }\r\n                    else if (el.InnerText != null && el.InnerText.Length > 1)\r\n                    {\r\n                        if (el.InnerText[0] == 'L' && el.InnerText[1] == ':')\r\n                        {\r\n                            try\r\n                            {\r\n                                k = Get(Convert.ToInt32(el.InnerText.Substring(2)));\r\n                            }\r\n                            catch\r\n                            {\r\n                                // ignored\r\n                            }\r\n                        }\r\n                        else\r\n                        {\r\n                            k = Get(el.InnerText);\r\n                        }\r\n                    }\r\n\r\n                    if (k != null)\r\n                    {\r\n                        k.Mod = (ModKeys) Convert.ToInt32(mod);\r\n                        k.Key = Convert.ToInt32(key);\r\n                        k.SendToUO = Convert.ToBoolean(send);\r\n                        k.Command = command;\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                    // ignored\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Save(XmlTextWriter xml)\r\n        {\r\n            for (int i = 0; i < m_List.Count; i++)\r\n            {\r\n                KeyData k = (KeyData) m_List[i];\r\n\r\n                if (k.Key != 0)\r\n                {\r\n                    xml.WriteStartElement(\"key\");\r\n                    xml.WriteAttributeString(\"mod\", ((int) k.Mod).ToString());\r\n                    xml.WriteAttributeString(\"key\", k.Key.ToString());\r\n                    xml.WriteAttributeString(\"send\", k.SendToUO.ToString());\r\n                    xml.WriteAttributeString(\"command\", string.IsNullOrEmpty(k.Command) ? string.Empty : k.Command);\r\n\r\n                    //xml.WriteAttributeString( \"name\", ((int)k.LocName).ToString() );\r\n                    if (k.LocName != 0)\r\n                        xml.WriteString(\"L:\" + k.LocName.ToString());\r\n                    else\r\n                        xml.WriteString(k.StrName); //xml.WriteAttributeString( \"name\", k.StrName );\r\n\r\n                    xml.WriteEndElement();\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Razor/HotKeys/Misc.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing Assistant.Core;\nusing Assistant.Gumps.Internal;\n\nnamespace Assistant.HotKeys\n{\n    public class UseHotKeys\n    {\n        private static Serial _grabHotBag = Serial.Zero;\n\n        public static void Initialize()\n        {\n            HotKey.Add(HKCategory.Misc, LocString.Resync, new HotKeyCallback(Resync));\n\n            HotKey.Add(HKCategory.Misc, LocString.GoldPerHotkey, new HotKeyCallback(ToggleGoldPer));\n            HotKey.Add(HKCategory.Misc, LocString.DamageTracker, new HotKeyCallback(ToggleDamage));\n\n            HotKey.Add(HKCategory.Misc, LocString.CaptureBod, new HotKeyCallback(CaptureBod));\n\n            HotKey.Add(HKCategory.Misc, LocString.ClearDragDropQueue, new HotKeyCallback(DragDropManager.GracefulStop));\n\n            HotKey.Add(HKCategory.Misc, LocString.LastSpell, new HotKeyCallback(LastSpell));\n            HotKey.Add(HKCategory.Misc, LocString.LastSkill, new HotKeyCallback(LastSkill));\n            HotKey.Add(HKCategory.Misc, LocString.LastObj, new HotKeyCallback(LastObj));\n            HotKey.Add(HKCategory.Misc, LocString.AllNames, new HotKeyCallback(AllNames));\n            HotKey.Add(HKCategory.Misc, LocString.AllCorpses, new HotKeyCallback(AllCorpses));\n            HotKey.Add(HKCategory.Misc, LocString.AllMobiles, new HotKeyCallback(AllMobiles));\n            HotKey.Add(HKCategory.Misc, LocString.Dismount, new HotKeyCallback(Dismount));\n\n            HotKey.Add(HKCategory.Items, LocString.BandageSelf, new HotKeyCallback(BandageSelf));\n            HotKey.Add(HKCategory.Items, LocString.BandageLT, new HotKeyCallback(BandageLastTarg));\n            HotKey.Add(HKCategory.Items, LocString.UseHand, new HotKeyCallback(UseItemInHand));\n            HotKey.Add(HKCategory.Items, LocString.UseRightHand, new HotKeyCallback(UseItemInRightHand));\n            HotKey.Add(HKCategory.Items, LocString.UseLeftHand, new HotKeyCallback(UseItemInLeftHand));\n\n            HotKey.Add(HKCategory.Misc, LocString.PartyAccept, new HotKeyCallback(PartyAccept));\n            HotKey.Add(HKCategory.Misc, LocString.PartyDecline, new HotKeyCallback(PartyDecline));\n            HotKey.Add(HKCategory.Misc, LocString.PartyAdd, new HotKeyCallback(PartyAdd));\n\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllCome, new HotKeyCallback(PetAllCome));\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllFollowMe,\n                new HotKeyCallback(PetAllFollowMe));\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllFollow, new HotKeyCallback(PetAllFollow));\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllGuardMe, new HotKeyCallback(PetAllGuardMe));\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllGuard, new HotKeyCallback(PetAllGuard));\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllKill, new HotKeyCallback(PetAllKill));\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllStay, new HotKeyCallback(PetAllStay));\n            HotKey.Add(HKCategory.Misc, HKSubCat.PetCommands, LocString.AllStop, new HotKeyCallback(PetAllStop));\n\n            HotKeyCallbackState call = new HotKeyCallbackState(OnUseItem);\n            HotKey.Add(HKCategory.Items, LocString.UseBandage, call, (ushort) 3617);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkHeal, call, (ushort) 3852);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkCure, call, (ushort) 3847);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkRef, call, (ushort) 3851);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkNS, call, (ushort) 3846);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkExp, call, (ushort) 3853);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkStr, call, (ushort) 3849);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkAg, call, (ushort) 3848);\n            HotKey.Add(HKCategory.Items, HKSubCat.Potions, LocString.DrinkApple, new HotKeyCallback(OnDrinkApple));\n\n\n            // Set the packet handler for single click and establish hotkeys for grab item\n            PacketHandler.RegisterClientToServerViewer(0x09, new PacketViewerCallback(OnGrabItemSingleClick));\n            HotKey.Add(HKCategory.Misc, LocString.GrabItem, new HotKeyCallback(GrabItem));\n            HotKey.Add(HKCategory.Misc, LocString.SetGrabItemHotBag, new HotKeyCallback(SetGrabItemHotBag));\n\n            _grabHotBag = Convert.ToUInt32(Config.GetString(\"GrabHotBag\"));\n\n            HotKey.Add(HKCategory.Misc, LocString.GumpInfo, GetInfoGump);\n            HotKey.Add(HKCategory.Misc, LocString.GumpSysMsg, GetSysMsgGump);\n            HotKey.Add(HKCategory.Misc, LocString.GumpHotKeys, GetHotKeysGump);\n            HotKey.Add(HKCategory.Misc, LocString.GumpBoatControl, GetBoatControlGump);\n        }\n\n        private static void ToggleGoldPer()\n        {\n            if (GoldPerHourTimer.Running)\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"Stopping 'GoldPer Timer'\");\n                GoldPerHourTimer.Stop();\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"Starting 'GoldPer Timer' when you loot your first gold\");\n                GoldPerHourTimer.Start();\n            }\n        }\n\n        private static void ToggleDamage()\n        {\n            Engine.MainWindow.ToggleDamageTracker(!DamageTracker.Running);\n        }\n\n        private enum PetCommands\n        {\n            AllCome,\n            AllFollowMe,\n            AllFollow,\n            AllGuardMe,\n            AllGuard,\n            AllKill,\n            AllStay,\n            AllStop\n        }\n\n        private static void PetAllCome()\n        {\n            World.Player.Say(Language.GetString(LocString.AllCome));\n        }\n\n        private static void PetAllFollowMe()\n        {\n            World.Player.Say(Language.GetString(LocString.AllFollowMe));\n        }\n\n        private static void PetAllFollow()\n        {\n            World.Player.Say(Language.GetString(LocString.AllFollow));\n        }\n\n        private static void PetAllGuardMe()\n        {\n            World.Player.Say(Language.GetString(LocString.AllGuardMe));\n        }\n\n        private static void PetAllGuard()\n        {\n            World.Player.Say(Language.GetString(LocString.AllGuard));\n        }\n\n        private static void PetAllKill()\n        {\n            World.Player.Say(Language.GetString(LocString.AllKill));\n        }\n\n        private static void PetAllStay()\n        {\n            World.Player.Say(Language.GetString(LocString.AllStay));\n        }\n\n        private static void PetAllStop()\n        {\n            World.Player.Say(Language.GetString(LocString.AllStop));\n        }\n\n        private static void CaptureBod()\n        {\n            try\n            {\n                if (BodCapture.IsBodGump(World.Player.CurrentGumpI))\n                {\n                    BodCapture.CaptureBod(World.Player.CurrentGumpStrings);\n\n                    World.Player.SendMessage(MsgLevel.Force, \"BOD has been captured and saved to BODs.csv\");\n                }\n                else\n                {\n                    World.Player.SendMessage(MsgLevel.Force, \"The last gump you had open doesn't appear to be a BOD\");\n                }\n            }\n            catch\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"Unable to capture BOD, probably unknown format\");\n            }\n        }\n\n\n        private static void PartyAccept()\n        {\n            if (PacketHandlers.PartyLeader != Serial.Zero)\n            {\n                Client.Instance.SendToServer(new AcceptParty(PacketHandlers.PartyLeader));\n                PacketHandlers.PartyLeader = Serial.Zero;\n            }\n        }\n\n        private static void PartyDecline()\n        {\n            if (PacketHandlers.PartyLeader != Serial.Zero)\n            {\n                Client.Instance.SendToServer(new DeclineParty(PacketHandlers.PartyLeader));\n                PacketHandlers.PartyLeader = Serial.Zero;\n            }\n        }\n\n        private static void PartyAdd()\n        {\n            Client.Instance.SendToServer(new AddParty());\n        }\n\n        private static void Dismount()\n        {\n            if (World.Player.GetItemOnLayer(Layer.Mount) != null)\n                ActionQueue.DoubleClick(true, World.Player.Serial);\n            else\n                World.Player.SendMessage(\"You are not mounted.\");\n        }\n\n        private static void AllNames()\n        {\n            bool textFlags = Config.GetBool(\"LastTargTextFlags\");\n\n            foreach (Mobile m in World.MobilesInRange())\n            {\n                if (m != World.Player)\n                    Client.Instance.SendToServer(new SingleClick(m));\n\n                if (textFlags)\n                    Targeting.CheckTextFlags(m);\n\n                FriendsManager.ShowOverhead(m);\n            }\n\n            foreach (Item i in World.Items.Values)\n            {\n                if (i.IsCorpse)\n                    Client.Instance.SendToServer(new SingleClick(i));\n            }\n        }\n\n        private static void AllCorpses()\n        {\n            foreach (Item i in World.Items.Values)\n            {\n                if (i.IsCorpse)\n                    Client.Instance.SendToServer(new SingleClick(i));\n            }\n        }\n\n        private static void AllMobiles()\n        {\n            bool textFlags = Config.GetBool(\"LastTargTextFlags\");\n\n            foreach (Mobile m in World.MobilesInRange())\n            {\n                if (m != World.Player)\n                    Client.Instance.SendToServer(new SingleClick(m));\n\n                if (textFlags)\n                    Targeting.CheckTextFlags(m);\n\n                FriendsManager.ShowOverhead(m);\n            }\n        }\n\n        private static void LastSkill()\n        {\n            if (World.Player != null && World.Player.LastSkill != -1)\n                Client.Instance.SendToServer(new UseSkill(World.Player.LastSkill));\n        }\n\n        private static void LastObj()\n        {\n            if (World.Player != null && World.Player.LastObject != Serial.Zero)\n                PlayerData.DoubleClick(World.Player.LastObject);\n        }\n\n        private static void LastSpell()\n        {\n            if (World.Player != null && World.Player.LastSpell != -1)\n            {\n                ushort id = (ushort) World.Player.LastSpell;\n                object o = id;\n                Spell.OnHotKey(ref o);\n            }\n        }\n\n        private static DateTime m_LastSync;\n\n        private static void Resync()\n        {\n            if (DateTime.UtcNow - m_LastSync > TimeSpan.FromSeconds(1.0))\n            {\n                m_LastSync = DateTime.UtcNow;\n\n                Client.Instance.SendToServer(new ResyncReq());\n            }\n        }\n\n        public static void BandageLastTarg()\n        {\n            Item pack = World.Player.Backpack;\n            if (pack != null)\n            {\n                if (!World.Player.UseItem(pack, 3617))\n                {\n                    World.Player.SendMessage(MsgLevel.Warning, LocString.NoBandages);\n                }\n                else\n                {\n                    Targeting.LastTarget(true); //force a targetself to be queued\n                    //BandageTimer.Start(); // Bandage timer will be started automatically after the \"You begin applying the bandages.\" message\n                }\n            }\n        }\n\n        public static void BandageSelf()\n        {\n            Item pack = World.Player.Backpack;\n            if (pack != null)\n            {\n                if (!World.Player.UseItem(pack, 3617))\n                {\n                    World.Player.SendMessage(MsgLevel.Warning, LocString.NoBandages);\n                }\n                else\n                {\n                    Targeting.ClearQueue();\n                    Targeting.TargetSelf(true); //force a targetself to be queued\n                    //BandageTimer.Start(); // Bandage timer will be started automatically after the \"You begin applying the bandages.\" message\n                }\n            }\n        }\n\n        private static bool DrinkApple(Item cont)\n        {\n            for (int i = 0; i < cont.Contains.Count; i++)\n            {\n                Item item = (Item) cont.Contains[i];\n\n                if (item.ItemID == 12248 && item.Hue == 1160)\n                {\n                    PlayerData.DoubleClick(item);\n                    return true;\n                }\n                else if (item.Contains != null && item.Contains.Count > 0)\n                {\n                    if (DrinkApple(item))\n                        return true;\n                }\n            }\n\n            return false;\n        }\n\n        private static void OnDrinkApple()\n        {\n            if (World.Player.Backpack == null)\n                return;\n\n            if (!DrinkApple(World.Player.Backpack))\n                World.Player.SendMessage(LocString.NoItemOfType, (ItemID) 12248);\n        }\n\n        private static void OnUseItem(ref object state)\n        {\n            Item pack = World.Player.Backpack;\n            if (pack == null)\n                return;\n\n            ushort id = (ushort) state;\n            if (id == 3852 && World.Player.Poisoned && Config.GetBool(\"BlockHealPoison\") &&\n                Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.HealPoisonBlocked);\n                return;\n            }\n\n            if (!World.Player.UseItem(pack, id))\n                World.Player.SendMessage(LocString.NoItemOfType, (ItemID) id);\n        }\n\n        private static void UseItemInHand()\n        {\n            Item item = World.Player.GetItemOnLayer(Layer.RightHand);\n            if (item == null)\n                item = World.Player.GetItemOnLayer(Layer.LeftHand);\n\n            if (item != null)\n                PlayerData.DoubleClick(item);\n        }\n\n        private static void UseItemInRightHand()\n        {\n            Item item = World.Player.GetItemOnLayer(Layer.RightHand);\n\n            if (item != null)\n                PlayerData.DoubleClick(item);\n        }\n\n        private static void UseItemInLeftHand()\n        {\n            Item item = World.Player.GetItemOnLayer(Layer.LeftHand);\n\n            if (item != null)\n                PlayerData.DoubleClick(item);\n        }\n\n        private static void GrabItem()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.GrabItemTarget);\n            Targeting.OneTimeTarget(OnGrabItem, true);\n        }\n\n        private static void OnGrabItem(bool loc, Serial serial, Point3D pt, ushort itemId)\n        {\n            Item item = World.FindItem(serial);\n\n            if (item != null && item.Serial.IsItem && item.Movable && item.Visible)\n            {\n                Item hotbag = World.FindItem(_grabHotBag) ?? World.Player.Backpack;\n\n                DragDropManager.DragDrop(item, item.Amount, hotbag);\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Error, \"Invalid or inaccessible item.\", false);\n            }\n        }\n\n        private static void SetGrabItemHotBag()\n        {\n            World.Player.SendMessage(MsgLevel.Force, LocString.SetGrabItemHotBag);\n            Targeting.OneTimeTarget(OnSetGrabItemHotBag);\n        }\n\n        private static void OnSetGrabItemHotBag(bool loc, Serial serial, Point3D pt, ushort itemId)\n        {\n            if (!loc && serial.IsItem)\n            {\n                Item hb = World.FindItem(serial);\n\n                if (hb != null)\n                {\n                    _grabHotBag = serial;\n                    Config.SetProperty(\"GrabHotBag\", serial.Value.ToString());\n\n                    hb.ObjPropList.Add(Language.GetString(LocString.GrabHB));\n                    hb.OPLChanged();\n\n                    World.Player.SendMessage(MsgLevel.Force, \"Grab Item HotBag Set\");\n                }\n                else\n                {\n                    _grabHotBag = Serial.Zero;\n                    Config.SetProperty(\"GrabHotBag\", \"0\");\n                }\n            }\n        }\n\n        private static void OnGrabItemSingleClick(PacketReader pvSrc, PacketHandlerEventArgs args)\n        {\n            Serial serial = pvSrc.ReadUInt32();\n            if (_grabHotBag == serial)\n            {\n                ushort gfx = 0;\n                Item c = World.FindItem(_grabHotBag);\n                if (c != null)\n                {\n                    gfx = c.ItemID.Value;\n                }\n\n                Client.Instance.SendToClient(new UnicodeMessage(_grabHotBag, gfx, MessageType.Label, 0x3B2, 3,\n                    Language.CliLocName, \"\", Language.GetString(LocString.GrabHB)));\n            }\n        }\n\n        private static void GetInfoGump()\n        {\n            World.Player.SendMessage(MsgLevel.Force, \"Select an item or mobile to view/inspect\");\n            Targeting.OneTimeTarget(OnGetItemInfoTarget);\n        }\n\n        private static void OnGetItemInfoTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\n        {\n            Item item = World.FindItem(serial);\n\n            if (item == null)\n            {\n                Mobile mobile = World.FindMobile(serial);\n\n                if (mobile == null)\n                    return;\n\n                MobileInfoGump gump = new MobileInfoGump(mobile);\n                gump.SendGump();\n            }\n            else\n            {\n                ItemInfoGump gump = new ItemInfoGump(item);\n                gump.SendGump();\n            }\n        }\n\n        private static void GetSysMsgGump()\n        {\n            World.Player.SendMessage(MsgLevel.Force, \"Displaying current System Message buffer\");\n            SystemMessagesGump gump = new SystemMessagesGump();\n            gump.SendGump();\n        }\n\n        private static void GetHotKeysGump()\n        {\n            World.Player.SendMessage(MsgLevel.Force, \"Displaying currently assigned hotkeys\");\n            HotKeyGump gump = new HotKeyGump(true, true, true);\n            gump.SendGump();\n        }\n        private static void GetBoatControlGump()\n        {\n            World.Player.SendMessage(MsgLevel.Force, \"Displaying boat control gump\");\n            BoatControlGump gump = new BoatControlGump(0);\n            gump.SendGump();\n        }\n    }\n}"
  },
  {
    "path": "Razor/HotKeys/SkillHotKeys.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System.Collections.Generic;\r\nusing Ultima;\r\n\r\nnamespace Assistant.HotKeys\r\n{\r\n    public class SkillHotKeys\r\n    {\r\n        private static HotKeyCallbackState _callback;\r\n        \r\n        public static void Initialize()\r\n        {\r\n            _callback = new HotKeyCallbackState(OnHotKey);\r\n            //1044060 = Alchemy in UO cliloc\r\n            \r\n            foreach (int t in Skills.GetUsableSkillIndexes())\r\n            {\r\n                HotKey.Add(HKCategory.Skills, (1044060 + t), _callback, t);\r\n            }\r\n        }\r\n\r\n        private static void OnHotKey(ref object state)\r\n        {\r\n            int sk = (int) state;\r\n            Client.Instance.SendToServer(new UseSkill(sk));\r\n            if (World.Player != null)\r\n            {\r\n                World.Player.LastSkill = sk;\r\n            }\r\n\r\n            if (sk == Skills.StealthIndex && !World.Player.Visible)\r\n            {\r\n                StealthSteps.Hide();\r\n            }\r\n\r\n            SkillTimer.Start();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/HotKeys/SpecialMoves.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\n\r\n\r\nnamespace Assistant\r\n{\r\n    public enum AOSAbility\r\n    {\r\n        Clear,\r\n        ArmorIgnore,\r\n        BleedAttack,\r\n        ConcussionBlow,\r\n        CrushingBlow,\r\n        Disarm,\r\n        Dismount,\r\n        DoubleStrike,\r\n        InfectiousStrike,\r\n        MortalStrike,\r\n        MovingShot,\r\n        ParalyzingBlow,\r\n        ShadowStrike,\r\n        WhirlwindAttack,\r\n        Invalid\r\n    }\r\n\r\n    public class SpecialMoves\r\n    {\r\n        private class AbilityInfo\r\n        {\r\n            private AOSAbility m_Ability;\r\n            private int[][] m_Items;\r\n\r\n            public AbilityInfo(AOSAbility ab, params int[][] items)\r\n            {\r\n                m_Ability = (AOSAbility) ab;\r\n                m_Items = items;\r\n            }\r\n\r\n            public AOSAbility Ability\r\n            {\r\n                get { return m_Ability; }\r\n            }\r\n\r\n            public bool HasItem(int item)\r\n            {\r\n                for (int a = 0; a < m_Items.Length; a++)\r\n                {\r\n                    for (int b = 0; b < m_Items[a].Length; b++)\r\n                    {\r\n                        if (m_Items[a][b] == item)\r\n                            return true;\r\n                    }\r\n                }\r\n\r\n                return false;\r\n            }\r\n        }\r\n\r\n        private static DateTime m_LastToggle = DateTime.MinValue;\r\n\r\n        private static int[] HatchetID = new int[] {0xF43, 0xF44};\r\n        private static int[] LongSwordID = new int[] {0xF60, 0xF61};\r\n        private static int[] BroadswordID = new int[] {0xF5E, 0xF5F};\r\n        private static int[] KatanaID = new int[] {0x13FE, 0x13FF};\r\n        private static int[] BladedStaffID = new int[] {0x26BD, 0x26C7};\r\n        private static int[] HammerPickID = new int[] {0x143C, 0x143D};\r\n        private static int[] WarAxeID = new int[] {0x13AF, 0x13B0};\r\n        private static int[] KryssID = new int[] {0x1400, 0x1401};\r\n        private static int[] SpearID = new int[] {0xF62, 0xF63};\r\n        private static int[] CompositeBowID = new int[] {0x26C2, 0x26CC};\r\n        private static int[] CleaverID = new int[] {0xEC2, 0xEC3};\r\n        private static int[] LargeBattleAxeID = new int[] {0x13FA, 0x13FB};\r\n        private static int[] BattleAxeID = new int[] {0xF47, 0xF48};\r\n        private static int[] ExecAxeID = new int[] {0xF45, 0xF46};\r\n        private static int[] CutlassID = new int[] {0x1440, 0x1441};\r\n        private static int[] ScytheID = new int[] {0x26BA, 0x26C4};\r\n        private static int[] WarMaceID = new int[] {0x1406, 0x1407};\r\n        private static int[] PitchforkID = new int[] {0xE87, 0xE88};\r\n        private static int[] WarForkID = new int[] {0x1404, 0x1405};\r\n        private static int[] HalberdID = new int[] {0x143E, 0x143F};\r\n        private static int[] MaulID = new int[] {0x143A, 0x143B};\r\n        private static int[] MaceID = new int[] {0xF5C, 0x45D};\r\n        private static int[] GnarledStaffID = new int[] {0x13F8, 0x13F9};\r\n        private static int[] QuarterStaffID = new int[] {0xE89, 0xE8A};\r\n        private static int[] LanceID = new int[] {0x26C0, 0x26CA};\r\n        private static int[] CrossbowID = new int[] {0xF4F, 0xF50};\r\n        private static int[] VikingSwordID = new int[] {0x13B9, 0x13BA};\r\n        private static int[] AxeID = new int[] {0xF49, 0xF4A};\r\n        private static int[] ShepherdsCrookID = new int[] {0xE81, 0xE82};\r\n        private static int[] SmithsHammerID = new int[] {0x13EC, 0x13E4};\r\n        private static int[] WarHammerID = new int[] {0x1438, 0x1439};\r\n        private static int[] ScepterID = new int[] {0x26BC, 0x26C6};\r\n        private static int[] SledgeHammerID = new int[] {0xFB4, 0xFB5};\r\n        private static int[] ButcherKnifeID = new int[] {0x13F6, 0x13F7};\r\n        private static int[] PickaxeID = new int[] {0xE85, 0xE86};\r\n        private static int[] SkinningKnifeID = new int[] {0xEC4, 0xEC5};\r\n        private static int[] WandID = new int[] {0xDF2, 0xDF3, 0xDF4, 0xDF5};\r\n        private static int[] BardicheID = new int[] {0xF4D, 0xF4E};\r\n        private static int[] ClubID = new int[] {0x13B3, 0x13B4};\r\n        private static int[] ScimitarID = new int[] {0x13B5, 0x13B6};\r\n        private static int[] HeavyCrossbowID = new int[] {0x13FC, 0x13FD};\r\n        private static int[] TwoHandedAxeID = new int[] {0x1442, 0x1443};\r\n        private static int[] DoubleAxeID = new int[] {0xF4B, 0xF4C};\r\n        private static int[] CrescentBladeID = new int[] {0x26C1, 0x26C2};\r\n        private static int[] DoubleBladedStaffID = new int[] {0x26BF, 0x26C9};\r\n        private static int[] RepeatingCrossbowID = new int[] {0x26C3, 0x26CD};\r\n        private static int[] DaggerID = new int[] {0xF51, 0xF52};\r\n        private static int[] PikeID = new int[] {0x26BE, 0x26C8};\r\n        private static int[] BoneHarvesterID = new int[] {0x26BB, 0x26C5};\r\n        private static int[] ShortSpearID = new int[] {0x1402, 0x1403};\r\n        private static int[] BowID = new int[] {0x13B1, 0x13B2};\r\n        private static int[] BlackStaffID = new int[] {0xDF0, 0xDF1};\r\n        private static int[] FistsID = new int[] {0};\r\n\r\n        private static AbilityInfo[] m_Primary = new AbilityInfo[]\r\n        {\r\n            new AbilityInfo(AOSAbility.ArmorIgnore, HatchetID, LongSwordID, BladedStaffID, HammerPickID, WarAxeID,\r\n                KryssID, SpearID, CompositeBowID),\r\n            new AbilityInfo(AOSAbility.BleedAttack, CleaverID, BattleAxeID, ExecAxeID, CutlassID, ScytheID, PitchforkID,\r\n                WarForkID),\r\n            new AbilityInfo(AOSAbility.ConcussionBlow, MaceID, GnarledStaffID, CrossbowID),\r\n            new AbilityInfo(AOSAbility.CrushingBlow, VikingSwordID, AxeID, BroadswordID, ShepherdsCrookID,\r\n                SmithsHammerID, MaulID, WarMaceID, ScepterID, SledgeHammerID),\r\n            new AbilityInfo(AOSAbility.Disarm, FistsID),\r\n            new AbilityInfo(AOSAbility.Dismount, WandID, LanceID),\r\n            new AbilityInfo(AOSAbility.DoubleStrike, PickaxeID, TwoHandedAxeID, DoubleAxeID, ScimitarID, KatanaID,\r\n                CrescentBladeID, QuarterStaffID, DoubleBladedStaffID, RepeatingCrossbowID),\r\n            new AbilityInfo(AOSAbility.InfectiousStrike, ButcherKnifeID, DaggerID),\r\n            //new AbilityInfo( AOSAbility.MortalStrike ), // not primary for anything\r\n            new AbilityInfo(AOSAbility.MovingShot, HeavyCrossbowID),\r\n            new AbilityInfo(AOSAbility.ParalyzingBlow, BardicheID, BoneHarvesterID, PikeID, BowID),\r\n            new AbilityInfo(AOSAbility.ShadowStrike, SkinningKnifeID, ClubID, ShortSpearID),\r\n            new AbilityInfo(AOSAbility.WhirlwindAttack, LargeBattleAxeID, HalberdID, WarHammerID, BlackStaffID)\r\n        };\r\n\r\n        private static AbilityInfo[] m_Secondary = new AbilityInfo[]\r\n        {\r\n            new AbilityInfo(AOSAbility.ArmorIgnore, LargeBattleAxeID, BroadswordID, KatanaID),\r\n            new AbilityInfo(AOSAbility.BleedAttack, WarMaceID, WarAxeID),\r\n            new AbilityInfo(AOSAbility.ConcussionBlow, LongSwordID, BattleAxeID, HalberdID, MaulID, QuarterStaffID,\r\n                LanceID),\r\n            new AbilityInfo(AOSAbility.CrushingBlow, WarHammerID),\r\n            new AbilityInfo(AOSAbility.Disarm, ButcherKnifeID, PickaxeID, SkinningKnifeID, HatchetID, WandID,\r\n                ShepherdsCrookID, MaceID, WarForkID),\r\n            new AbilityInfo(AOSAbility.Dismount, BardicheID, AxeID, BladedStaffID, ClubID, PitchforkID,\r\n                HeavyCrossbowID),\r\n            //new AbilityInfo( AOSAbility.DoubleStrike ), // secondary on none\r\n            new AbilityInfo(AOSAbility.InfectiousStrike, CleaverID, PikeID, KryssID, DoubleBladedStaffID),\r\n            new AbilityInfo(AOSAbility.MortalStrike, ExecAxeID, BoneHarvesterID, CrescentBladeID, HammerPickID,\r\n                ScepterID, ShortSpearID, CrossbowID, BowID),\r\n            new AbilityInfo(AOSAbility.MovingShot, CompositeBowID, RepeatingCrossbowID),\r\n            new AbilityInfo(AOSAbility.ParalyzingBlow, VikingSwordID, ScimitarID, ScytheID, GnarledStaffID,\r\n                BlackStaffID, SpearID, FistsID),\r\n            new AbilityInfo(AOSAbility.ShadowStrike, TwoHandedAxeID, CutlassID, SmithsHammerID, DaggerID,\r\n                SledgeHammerID),\r\n            new AbilityInfo(AOSAbility.WhirlwindAttack, DoubleAxeID)\r\n        };\r\n\r\n        public static void Initialize()\r\n        {\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.None, LocString.ToggleWarPeace, new HotKeyCallback(ToggleWarPeace));\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.None, LocString.ToggleWar, new HotKeyCallback(ToggleWar));\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.None, LocString.TogglePeace, new HotKeyCallback(TogglePeace));\r\n\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.SpecialMoves, LocString.ClearAbility,\r\n                new HotKeyCallback(ClearAbilities));\r\n\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.SpecialMoves, LocString.SetPrimAb,\r\n                new HotKeyCallback(SetPrimaryAbility));\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.SpecialMoves, LocString.SetSecAb,\r\n                new HotKeyCallback(SetSecondaryAbility));\r\n\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.SpecialMoves, LocString.ToggleStun, new HotKeyCallback(OnStun));\r\n            HotKey.Add(HKCategory.Misc, HKSubCat.SpecialMoves, LocString.ToggleDisarm, new HotKeyCallback(OnDisarm));\r\n        }\r\n\r\n        private static void ToggleWarPeace()\r\n        {\r\n            Client.Instance.SendToServer(new SetWarMode(!World.Player.Warmode));\r\n        }\r\n\r\n        private static void ToggleWar()\r\n        {\r\n            Client.Instance.ForceSendToClient(new SetWarMode(true));\r\n            Client.Instance.SendToServer(new SetWarMode(true));\r\n        }\r\n\r\n        private static void TogglePeace()\r\n        {\r\n            Client.Instance.ForceSendToClient(new SetWarMode(false));\r\n            Client.Instance.SendToServer(new SetWarMode(false));\r\n        }\r\n\r\n        private static void OnStun()\r\n        {\r\n            if (m_LastToggle + TimeSpan.FromSeconds(0.5) < DateTime.UtcNow)\r\n            {\r\n                m_LastToggle = DateTime.UtcNow;\r\n                Client.Instance.SendToServer(new StunRequest());\r\n            }\r\n        }\r\n\r\n        private static void OnDisarm()\r\n        {\r\n            if (m_LastToggle + TimeSpan.FromSeconds(0.5) < DateTime.UtcNow)\r\n            {\r\n                m_LastToggle = DateTime.UtcNow;\r\n                Client.Instance.SendToServer(new DisarmRequest());\r\n            }\r\n        }\r\n\r\n        private static AOSAbility GetAbility(int item, AbilityInfo[] list)\r\n        {\r\n            for (int a = 0; a < list.Length; a++)\r\n            {\r\n                if (list[a].HasItem(item))\r\n                    return list[a].Ability;\r\n            }\r\n\r\n            return AOSAbility.Invalid;\r\n        }\r\n\r\n        public static void SetPrimaryAbility()\r\n        {\r\n            Item right = World.Player.GetItemOnLayer(Layer.RightHand);\r\n            Item left = World.Player.GetItemOnLayer(Layer.LeftHand);\r\n\r\n            AOSAbility a = AOSAbility.Invalid;\r\n            if (right != null)\r\n                a = GetAbility(right.ItemID.Value, m_Primary);\r\n\r\n            if (a == AOSAbility.Invalid && left != null)\r\n                a = GetAbility(left.ItemID.Value, m_Primary);\r\n\r\n            if (a == AOSAbility.Invalid)\r\n                a = GetAbility(FistsID[0], m_Primary);\r\n\r\n            if (a != AOSAbility.Invalid)\r\n            {\r\n                Client.Instance.SendToServer(new UseAbility(a));\r\n                Client.Instance.SendToClient(ClearAbility.Instance);\r\n                World.Player.SendMessage(LocString.SettingAOSAb, a);\r\n            }\r\n        }\r\n\r\n        public static void SetSecondaryAbility()\r\n        {\r\n            Item right = World.Player.GetItemOnLayer(Layer.RightHand);\r\n            Item left = World.Player.GetItemOnLayer(Layer.LeftHand);\r\n\r\n            AOSAbility a = AOSAbility.Invalid;\r\n            if (right != null)\r\n                a = GetAbility(right.ItemID.Value, m_Secondary);\r\n\r\n            if (a == AOSAbility.Invalid && left != null)\r\n                a = GetAbility(left.ItemID.Value, m_Secondary);\r\n\r\n            if (a == AOSAbility.Invalid)\r\n                a = GetAbility(FistsID[0], m_Secondary);\r\n\r\n            if (a != AOSAbility.Invalid)\r\n            {\r\n                Client.Instance.SendToServer(new UseAbility(a));\r\n                Client.Instance.SendToClient(ClearAbility.Instance);\r\n                World.Player.SendMessage(LocString.SettingAOSAb, a);\r\n            }\r\n        }\r\n\r\n        public static void ClearAbilities()\r\n        {\r\n            Client.Instance.SendToServer(new UseAbility(AOSAbility.Clear));\r\n            Client.Instance.SendToClient(ClearAbility.Instance);\r\n            World.Player.SendMessage(LocString.AOSAbCleared);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/HotKeys/Undress.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing Assistant.Core;\r\n\r\nnamespace Assistant.HotKeys\r\n{\r\n    public class UndressHotKeys\r\n    {\r\n        public static void Initialize()\r\n        {\r\n            HotKey.Add(HKCategory.Dress, LocString.ArmDisarmRight, new HotKeyCallback(Dress.ToggleRight));\r\n            HotKey.Add(HKCategory.Dress, LocString.ArmDisarmLeft, new HotKeyCallback(Dress.ToggleLeft));\r\n\r\n            HotKey.Add(HKCategory.Dress, LocString.UndressAll, new HotKeyCallback(OnUndressAll));\r\n            HotKey.Add(HKCategory.Dress, LocString.UndressHands, new HotKeyCallback(OnUnequipBothHands));\r\n            HotKey.Add(HKCategory.Dress, LocString.UndressLeft, new HotKeyCallback(OnUnequipLeft));\r\n            HotKey.Add(HKCategory.Dress, LocString.UndressRight, new HotKeyCallback(OnUnequipRight));\r\n            HotKey.Add(HKCategory.Dress, LocString.UndressHat, new HotKeyCallback(OnUnequipHat));\r\n            HotKey.Add(HKCategory.Dress, LocString.UndressJewels, new HotKeyCallback(OnUnequipJewelry));\r\n        }\r\n\r\n        public static void OnUndressAll()\r\n        {\r\n            for (int i = 0; i < World.Player.Contains.Count; i++)\r\n            {\r\n                Item item = (Item) World.Player.Contains[i];\r\n                if (item.Layer <= Layer.LastUserValid && item.Layer != Layer.Backpack && item.Layer != Layer.Hair &&\r\n                    item.Layer != Layer.FacialHair)\r\n                {\r\n                    Item pack = DressList.FindUndressBag(item);\r\n                    if (pack != null)\r\n                        DragDropManager.DragDrop(item, pack);\r\n                }\r\n            }\r\n\r\n            //if ( Macros.MacroManager.AcceptActions )\r\n            //\tMacroManager.Action( new Macros.UnDressAction( (byte)0 ) );\r\n        }\r\n\r\n        public static void OnUnequipJewelry()\r\n        {\r\n            Dress.Unequip(Layer.Ring); // ring\r\n            Dress.Unequip(Layer.Bracelet); // bracelet\r\n            Dress.Unequip(Layer.Earrings); // earrings\r\n        }\r\n\r\n        public static void OnUnequipHat()\r\n        {\r\n            Dress.Unequip(Layer.Head);\r\n        }\r\n\r\n        public static void OnUnequipBothHands()\r\n        {\r\n            Dress.Unequip(Layer.RightHand);\r\n            Dress.Unequip(Layer.LeftHand);\r\n        }\r\n\r\n        public static void OnUnequipRight()\r\n        {\r\n            Dress.Unequip(Layer.RightHand);\r\n        }\r\n\r\n        public static void OnUnequipLeft()\r\n        {\r\n            Dress.Unequip(Layer.LeftHand);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Macros/Actions.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.Windows.Forms;\r\nusing Assistant.Core;\r\nusing Assistant.UI;\r\nusing Ultima;\r\n\r\nnamespace Assistant.Macros\r\n{\r\n    public delegate void MacroMenuCallback(object[] Args);\r\n\r\n    public class MacroMenuItem : ToolStripMenuItem\r\n    {\r\n        private MacroMenuCallback m_Call;\r\n        private object[] m_Args;\r\n\r\n        public MacroMenuItem(LocString name, MacroMenuCallback call, params object[] args) : base(\r\n            Language.GetString(name))\r\n        {\r\n            base.Click += new EventHandler(OnMenuClick);\r\n            m_Call = call;\r\n            m_Args = args;\r\n        }\r\n\r\n        private void OnMenuClick(object sender, System.EventArgs e)\r\n        {\r\n            m_Call(m_Args);\r\n        }\r\n    }\r\n\r\n    public abstract class MacroAction\r\n    {\r\n        protected Macro m_Parent;\r\n\r\n        public MacroAction()\r\n        {\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"?{GetType().Name}?\";\r\n        }\r\n\r\n        public abstract string ToScript();\r\n\r\n        public virtual string Serialize()\r\n        {\r\n            return GetType().FullName;\r\n        }\r\n\r\n        protected string DoSerialize(params object[] args)\r\n        {\r\n            StringBuilder sb = new StringBuilder(GetType().FullName);\r\n            for (int i = 0; i < args.Length; i++)\r\n                sb.AppendFormat(\"|{0}\", args[i]);\r\n            return sb.ToString();\r\n        }\r\n\r\n        public virtual ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            return null;\r\n        }\r\n\r\n        public Macro Parent\r\n        {\r\n            get { return m_Parent; }\r\n            set { m_Parent = value; }\r\n        }\r\n\r\n        public abstract bool Perform();\r\n    }\r\n\r\n    public abstract class MacroWaitAction : MacroAction\r\n    {\r\n        protected TimeSpan m_Timeout = TimeSpan.FromMinutes(5);\r\n        private DateTime m_Start;\r\n        private MacroMenuItem m_MenuItem = null;\r\n\r\n        public MacroWaitAction()\r\n        {\r\n        }\r\n\r\n        public abstract bool PerformWait();\r\n\r\n        public TimeSpan Timeout\r\n        {\r\n            get { return m_Timeout; }\r\n        }\r\n\r\n        public DateTime StartTime\r\n        {\r\n            get { return m_Start; }\r\n            set { m_Start = value; }\r\n        }\r\n\r\n        public MacroMenuItem EditTimeoutMenuItem\r\n        {\r\n            get\r\n            {\r\n                if (m_MenuItem == null)\r\n                    m_MenuItem = new MacroMenuItem(LocString.EditTimeout, new MacroMenuCallback(EditTimeout));\r\n                return m_MenuItem;\r\n            }\r\n        }\r\n\r\n        private void EditTimeout(object[] args)\r\n        {\r\n            if (InputBox.Show(Language.GetString(LocString.NewTimeout), Language.GetString(LocString.ChangeTimeout),\r\n                ((int) (m_Timeout.TotalSeconds)).ToString()))\r\n                m_Timeout = TimeSpan.FromSeconds(InputBox.GetInt(60));\r\n        }\r\n\r\n        public virtual bool CheckMatch(MacroAction a)\r\n        {\r\n            return false; // a.GetType() == this.GetType();\r\n        }\r\n    }\r\n\r\n    public class MacroComment : MacroAction\r\n    {\r\n        private string m_Comment;\r\n\r\n        public MacroComment(string comment)\r\n        {\r\n            if (comment == null)\r\n                comment = \"\";\r\n\r\n            m_Comment = comment.Trim();\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"# {m_Comment}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return ToString();\r\n        }\r\n\r\n        public string Comment\r\n        {\r\n            get { return m_Comment; }\r\n            set { m_Comment = value; }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (m_Comment == null)\r\n                m_Comment = \"\";\r\n\r\n            return $\"// {m_Comment}\";\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            if (InputBox.Show(Language.GetString(LocString.InsComment), Language.GetString(LocString.InputReq),\r\n                m_Comment))\r\n            {\r\n                if (m_Comment == null)\r\n                    m_Comment = \"\";\r\n\r\n                m_Comment = InputBox.GetString();\r\n\r\n                if (m_Comment == null)\r\n                    m_Comment = \"\";\r\n\r\n                if (m_Parent != null)\r\n                    m_Parent.Update();\r\n            }\r\n        }\r\n    }\r\n\r\n    public class ClearSysMessages : MacroAction\r\n    {\r\n        public ClearSysMessages()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            SystemMessages.Messages.Clear();\r\n\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"clearsysmsg\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize();\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.GetString(LocString.ClearSysMsg);\r\n        }\r\n    }\r\n\r\n\r\n    public class DoubleClickAction : MacroAction\r\n    {\r\n        private Serial m_Serial;\r\n        private ushort m_Gfx;\r\n\r\n        public DoubleClickAction(Serial obj, ushort gfx)\r\n        {\r\n            m_Serial = obj;\r\n            m_Gfx = gfx;\r\n        }\r\n\r\n        public DoubleClickAction(string[] args)\r\n        {\r\n            m_Serial = Serial.Parse(args[1]);\r\n            m_Gfx = Convert.ToUInt16(args[2]);\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            PlayerData.DoubleClick(m_Serial);\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"dclick '{m_Serial.ToString()}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Serial.Value, m_Gfx);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.DClickA1, m_Serial);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.ReTarget, new MacroMenuCallback(ReTarget)),\r\n                    new MacroMenuItem(LocString.Conv2DCT, new MacroMenuCallback(ConvertToByType))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ConvertToByType(object[] args)\r\n        {\r\n            if (m_Gfx != 0 && m_Serial.IsItem && m_Parent != null)\r\n                m_Parent.Convert(this, new DoubleClickTypeAction(m_Gfx, m_Serial.IsItem));\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnReTarget));\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void OnReTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            if (serial.IsItem || serial.IsMobile)\r\n            {\r\n                m_Serial = serial;\r\n                m_Gfx = gfx;\r\n            }\r\n\r\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n\r\n            if (m_Parent != null)\r\n                m_Parent.Update();\r\n        }\r\n    }\r\n\r\n    public class DoubleClickTypeAction : MacroAction\r\n    {\r\n        private ushort m_Gfx;\r\n        public bool m_Item;\r\n\r\n        public DoubleClickTypeAction(string[] args)\r\n        {\r\n            m_Gfx = Convert.ToUInt16(args[1]);\r\n            try\r\n            {\r\n                m_Item = Convert.ToBoolean(args[2]);\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public DoubleClickTypeAction(ushort gfx, bool item)\r\n        {\r\n            m_Gfx = gfx;\r\n            m_Item = item;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Serial click = Serial.Zero;\r\n\r\n            if (m_Item)\r\n            {\r\n                Item item = World.Player.Backpack != null ? World.Player.Backpack.FindItemById(m_Gfx) : null;\r\n                ArrayList list = new ArrayList();\r\n                if (item == null)\r\n                {\r\n                    foreach (Item i in World.Items.Values)\r\n                    {\r\n                        if (i.ItemID == m_Gfx && i.RootContainer == null)\r\n                        {\r\n                            if (Config.GetBool(\"RangeCheckDoubleClick\"))\r\n                            {\r\n                                if (Utility.InRange(World.Player.Position, i.Position, 2))\r\n                                {\r\n                                    list.Add(i);\r\n                                }\r\n                            }\r\n                            else\r\n                            {\r\n                                list.Add(i);\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    if (list.Count == 0)\r\n                    {\r\n                        foreach (Item i in World.Items.Values)\r\n                        {\r\n                            if (i.ItemID == m_Gfx && !i.IsInBank)\r\n                            {\r\n                                if (Config.GetBool(\"RangeCheckDoubleClick\"))\r\n                                {\r\n                                    if (Utility.InRange(World.Player.Position, i.Position, 2) || i.RootContainer == World.Player)\r\n                                    {\r\n                                        list.Add(i);\r\n                                    }\r\n                                }\r\n                                else\r\n                                {\r\n                                    list.Add(i);\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    if (list.Count > 0)\r\n                        click = ((Item) list[Utility.Random(list.Count)]).Serial;\r\n                }\r\n                else\r\n                {\r\n                    click = item.Serial;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                ArrayList list = new ArrayList();\r\n                foreach (Mobile m in World.MobilesInRange())\r\n                {\r\n                    if (m.Body == m_Gfx)\r\n                    {\r\n                        if (Config.GetBool(\"RangeCheckDoubleClick\"))\r\n                        {\r\n                            if (Utility.InRange(World.Player.Position, m.Position, 2))\r\n                            {\r\n                                list.Add(m);\r\n                            }\r\n                        }\r\n                        else\r\n                        {\r\n                            list.Add(m);\r\n                        }\r\n                    }\r\n                }\r\n\r\n                if (list.Count > 0)\r\n                    click = ((Mobile) list[Utility.Random(list.Count)]).Serial;\r\n            }\r\n\r\n            if (click != Serial.Zero)\r\n                PlayerData.DoubleClick(click);\r\n            else\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.NoItemOfType,\r\n                    m_Item ? ((ItemID) m_Gfx).ToString() : $\"(Character) 0x{m_Gfx:X}\");\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"dclicktype '{m_Gfx}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Gfx, m_Item);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.DClickA1,\r\n                m_Item ? ((ItemID) m_Gfx).ToString() : $\"(Character) 0x{m_Gfx:X}\");\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.ReTarget, new MacroMenuCallback(ReTarget))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnReTarget));\r\n            World.Player.SendMessage(LocString.SelTargAct);\r\n        }\r\n\r\n        private void OnReTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            m_Gfx = gfx;\r\n            m_Item = serial.IsItem;\r\n\r\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n            if (m_Parent != null)\r\n                m_Parent.Update();\r\n        }\r\n    }\r\n\r\n    public class LiftAction : MacroWaitAction\r\n    {\r\n        private ushort m_Amount;\r\n        private Serial m_Serial;\r\n        private ushort m_Gfx;\r\n\r\n        private static Item m_LastLift;\r\n\r\n        public static Item LastLift\r\n        {\r\n            get { return m_LastLift; }\r\n            set { m_LastLift = value; }\r\n        }\r\n\r\n        public LiftAction(string[] args)\r\n        {\r\n            m_Serial = Serial.Parse(args[1]);\r\n            m_Amount = Convert.ToUInt16(args[2]);\r\n            m_Gfx = Convert.ToUInt16(args[3]);\r\n        }\r\n\r\n        public LiftAction(Serial ser, ushort amount, ushort gfx)\r\n        {\r\n            m_Serial = ser;\r\n            m_Amount = amount;\r\n            m_Gfx = gfx;\r\n        }\r\n\r\n        private int m_Id;\r\n\r\n        public override bool Perform()\r\n        {\r\n            Item item = World.FindItem(m_Serial);\r\n            if (item != null)\r\n            {\r\n                //DragDropManager.Holding = item;\r\n                m_LastLift = item;\r\n                m_Id = DragDropManager.Drag(item, m_Amount <= item.Amount ? m_Amount : item.Amount);\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Warning, LocString.MacroItemOutRange);\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return DragDropManager.LastIDLifted < m_Id;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"lift '{m_Serial}' {m_Amount}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Serial.Value, m_Amount, m_Gfx);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.LiftA10, m_Serial, m_Amount);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.ReTarget, new MacroMenuCallback(ReTarget)),\r\n                    new MacroMenuItem(LocString.ConvLiftByType, new MacroMenuCallback(ConvertToByType)),\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(EditAmount))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Targeting.OneTimeTarget(!m_Serial.IsValid, new Targeting.TargetResponseCallback(ReTargetResponse));\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            m_Serial = serial;\r\n            m_Gfx = gfx;\r\n\r\n            Engine.MainWindow.ShowMe();\r\n\r\n            m_Parent?.Update();\r\n        }\r\n\r\n        private void EditAmount(object[] args)\r\n        {\r\n            if (InputBox.Show(Engine.MainWindow, Language.GetString(LocString.EnterAmount),\r\n                Language.GetString(LocString.InputReq), m_Amount.ToString()))\r\n            {\r\n                m_Amount = (ushort) InputBox.GetInt(m_Amount);\r\n\r\n                if (m_Parent != null)\r\n                    m_Parent.Update();\r\n            }\r\n        }\r\n\r\n        private void ConvertToByType(object[] args)\r\n        {\r\n            if (m_Gfx != 0 && m_Parent != null)\r\n                m_Parent.Convert(this, new LiftTypeAction(m_Gfx, m_Amount));\r\n        }\r\n    }\r\n\r\n    public class LiftTypeAction : MacroWaitAction\r\n    {\r\n        private ushort m_Gfx;\r\n        private ushort m_Amount;\r\n\r\n        public LiftTypeAction(string[] args)\r\n        {\r\n            m_Gfx = Convert.ToUInt16(args[1]);\r\n            m_Amount = Convert.ToUInt16(args[2]);\r\n        }\r\n\r\n        public LiftTypeAction(ushort gfx, ushort amount)\r\n        {\r\n            m_Gfx = gfx;\r\n            m_Amount = amount;\r\n        }\r\n\r\n        private int m_Id;\r\n\r\n        public override bool Perform()\r\n        {\r\n            Item item = World.Player.Backpack != null ? World.Player.Backpack.FindItemById(m_Gfx) : null;\r\n            /*if ( item == null )\r\n            {\r\n                 ArrayList list = new ArrayList();\r\n\r\n                 foreach ( Item i in World.Items.Values )\r\n                 {\r\n                      if ( i.ItemID == m_Gfx && ( i.RootContainer == null || i.IsChildOf( World.Player.Quiver ) ) )\r\n                           list.Add( i );\r\n                 }\r\n\r\n                 if ( list.Count > 0 )\r\n                      item = (Item)list[ Utility.Random( list.Count ) ];\r\n            }*/\r\n\r\n            if (item != null)\r\n            {\r\n                //DragDropManager.Holding = item;\r\n                ushort amount = m_Amount;\r\n                if (item.Amount < amount)\r\n                    amount = item.Amount;\r\n                LiftAction.LastLift = item;\r\n                //ActionQueue.Enqueue( new LiftRequest( item, amount ) );\r\n                m_Id = DragDropManager.Drag(item, amount);\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Warning, LocString.NoItemOfType, (ItemID) m_Gfx);\r\n                //MacroManager.Stop();\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return DragDropManager.LastIDLifted < m_Id && !DragDropManager.Empty;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"lifttype '{m_Gfx}' {m_Amount}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Gfx, m_Amount);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.ReTarget, new MacroMenuCallback(ReTarget)),\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(EditAmount))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Targeting.OneTimeTarget(false, new Targeting.TargetResponseCallback(ReTargetResponse));\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            m_Gfx = gfx;\r\n\r\n            Engine.MainWindow.ShowMe();\r\n\r\n            m_Parent?.Update();\r\n        }\r\n\r\n        private void EditAmount(object[] args)\r\n        {\r\n            if (InputBox.Show(Engine.MainWindow, Language.GetString(LocString.EnterAmount),\r\n                Language.GetString(LocString.InputReq), m_Amount.ToString()))\r\n            {\r\n                m_Amount = (ushort) InputBox.GetInt(m_Amount);\r\n\r\n                if (m_Parent != null)\r\n                    m_Parent.Update();\r\n            }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.LiftA10, m_Amount, (ItemID) m_Gfx);\r\n        }\r\n    }\r\n\r\n    public class DropAction : MacroAction\r\n    {\r\n        private Serial m_To;\r\n        private Point3D m_At;\r\n        private Layer m_Layer;\r\n\r\n        public DropAction(string[] args)\r\n        {\r\n            m_To = Serial.Parse(args[1]);\r\n            m_At = Point3D.Parse(args[2]);\r\n            try\r\n            {\r\n                m_Layer = (Layer) Byte.Parse(args[3]);\r\n            }\r\n            catch\r\n            {\r\n                m_Layer = Layer.Invalid;\r\n            }\r\n        }\r\n\r\n        public DropAction(Serial to, Point3D at) : this(to, at, 0)\r\n        {\r\n        }\r\n\r\n        public DropAction(Serial to, Point3D at, Layer layer)\r\n        {\r\n            m_To = to;\r\n            m_At = at;\r\n            m_Layer = layer;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (DragDropManager.Holding != null)\r\n            {\r\n                if (m_Layer > Layer.Invalid && m_Layer <= Layer.LastUserValid)\r\n                {\r\n                    Mobile m = World.FindMobile(m_To);\r\n                    if (m != null)\r\n                        DragDropManager.Drop(DragDropManager.Holding, m, m_Layer);\r\n                }\r\n                else\r\n                {\r\n                    DragDropManager.Drop(DragDropManager.Holding, m_To, m_At);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Warning, LocString.MacroNoHold);\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            if (!m_To.IsValid)\r\n            {\r\n                return $\"droprelloc {m_At.X} {m_At.Y}\";\r\n            }\r\n\r\n            return m_Layer != Layer.Invalid ? $\"drop '{m_To}' {m_Layer}\" : $\"drop '{m_To}' {m_At.X} {m_At.Y} {m_At.Z}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_To, m_At, (byte) m_Layer);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (m_Layer != Layer.Invalid)\r\n                return Language.Format(LocString.EquipTo, m_To, m_Layer);\r\n            else\r\n                return Language.Format(LocString.DropA2, m_To.IsValid ? m_To.ToString() : \"Ground\", m_At);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_To.IsValid)\r\n            {\r\n                return null; // Dont allow conversion(s)\r\n            }\r\n            else\r\n            {\r\n                if (m_MenuItems == null)\r\n                {\r\n                    m_MenuItems = new MacroMenuItem[]\r\n                    {\r\n                        new MacroMenuItem(LocString.ConvRelLoc, new MacroMenuCallback(ConvertToRelLoc))\r\n                    };\r\n                }\r\n\r\n                return m_MenuItems;\r\n            }\r\n        }\r\n\r\n        private void ConvertToRelLoc(object[] args)\r\n        {\r\n            if (!m_To.IsValid && m_Parent != null)\r\n                m_Parent.Convert(this,\r\n                    new DropRelLocAction((sbyte) (m_At.X - World.Player.Position.X),\r\n                        (sbyte) (m_At.Y - World.Player.Position.Y), (sbyte) (m_At.Z - World.Player.Position.Z)));\r\n        }\r\n    }\r\n\r\n    public class DropRelLocAction : MacroAction\r\n    {\r\n        private sbyte[] m_Loc;\r\n\r\n        public DropRelLocAction(string[] args)\r\n        {\r\n            m_Loc = new sbyte[3]\r\n            {\r\n                Convert.ToSByte(args[1]),\r\n                Convert.ToSByte(args[2]),\r\n                Convert.ToSByte(args[3])\r\n            };\r\n        }\r\n\r\n        public DropRelLocAction(sbyte x, sbyte y, sbyte z)\r\n        {\r\n            m_Loc = new sbyte[3] {x, y, z};\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (DragDropManager.Holding != null)\r\n                DragDropManager.Drop(DragDropManager.Holding, null,\r\n                    new Point3D((ushort) (World.Player.Position.X + m_Loc[0]),\r\n                        (ushort) (World.Player.Position.Y + m_Loc[1]), (short) (World.Player.Position.Z + m_Loc[2])));\r\n            else\r\n                World.Player.SendMessage(LocString.MacroNoHold);\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"droprelloc {m_Loc[0]} {m_Loc[1]}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Loc[0], m_Loc[1], m_Loc[2]);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.DropRelA3, m_Loc[0], m_Loc[1], m_Loc[2]);\r\n        }\r\n    }\r\n\r\n    public class GumpResponseAction : MacroAction\r\n    {\r\n        private int m_ButtonID;\r\n        private int[] m_Switches;\r\n        private GumpTextEntry[] m_TextEntries;\r\n\r\n        public GumpResponseAction(string[] args)\r\n        {\r\n            m_ButtonID = Convert.ToInt32(args[1]);\r\n            m_Switches = new int[Convert.ToInt32(args[2])];\r\n            for (int i = 0; i < m_Switches.Length; i++)\r\n                m_Switches[i] = Convert.ToInt32(args[3 + i]);\r\n            m_TextEntries = new GumpTextEntry[Convert.ToInt32(args[3 + m_Switches.Length])];\r\n            for (int i = 0; i < m_TextEntries.Length; i++)\r\n            {\r\n                string[] split = args[4 + m_Switches.Length + i].Split('&');\r\n\r\n                m_TextEntries[i] = new GumpTextEntry(Convert.ToUInt16(split[0]), split[1]);\r\n            }\r\n        }\r\n\r\n        public GumpResponseAction(int button, int[] switches, GumpTextEntry[] entries)\r\n        {\r\n            m_ButtonID = button;\r\n            m_Switches = switches;\r\n            m_TextEntries = entries;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Client.Instance.SendToClient(new CloseGump(World.Player.CurrentGumpI));\r\n            Client.Instance.SendToServer(new GumpResponse(World.Player.CurrentGumpS, World.Player.CurrentGumpI,\r\n                m_ButtonID, m_Switches, m_TextEntries));\r\n            World.Player.HasGump = false;\r\n            World.Player.HasCompressedGump = false;\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return m_ButtonID == 0 ? \"gumpclose\" : $\"gumpresponse {m_ButtonID}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            ArrayList list = new ArrayList(3 + m_Switches.Length + m_TextEntries.Length);\r\n            list.Add(m_ButtonID);\r\n            list.Add(m_Switches.Length);\r\n            list.AddRange(m_Switches);\r\n            list.Add(m_TextEntries.Length);\r\n            for (int i = 0; i < m_TextEntries.Length; i++)\r\n                list.Add($\"{m_TextEntries[i].EntryID}&{m_TextEntries[i].Text}\");\r\n            return DoSerialize((object[]) list.ToArray(typeof(object)));\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (m_ButtonID != 0)\r\n                return Language.Format(LocString.GumpRespB, m_ButtonID);\r\n            else\r\n                return Language.Format(LocString.CloseGump);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (this.m_MenuItems == null)\r\n                this.m_MenuItems = (ToolStripMenuItem[]) new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.UseLastGumpResponse, new MacroMenuCallback(this.UseLastResponse),\r\n                        new object[0]),\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(this.Edit), new object[0])\r\n                };\r\n            return this.m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            if (InputBox.Show(Language.GetString(LocString.EnterNewText), \"Input Box\", this.m_ButtonID.ToString()))\r\n                this.m_ButtonID = InputBox.GetInt();\r\n\r\n            Parent?.Update();\r\n        }\r\n\r\n        private void UseLastResponse(object[] args)\r\n        {\r\n            m_ButtonID = World.Player.LastGumpResponseAction.m_ButtonID;\r\n            m_Switches = World.Player.LastGumpResponseAction.m_Switches;\r\n            m_TextEntries = World.Player.LastGumpResponseAction.m_TextEntries;\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, \"Set GumpResponse to last response\");\r\n\r\n            Parent?.Update();\r\n        }\r\n    }\r\n\r\n    public class MenuResponseAction : MacroAction\r\n    {\r\n        private ushort m_Index, m_ItemID, m_Hue;\r\n\r\n        public MenuResponseAction(string[] args)\r\n        {\r\n            m_Index = Convert.ToUInt16(args[1]);\r\n            m_ItemID = Convert.ToUInt16(args[2]);\r\n            m_Hue = Convert.ToUInt16(args[3]);\r\n        }\r\n\r\n        public MenuResponseAction(ushort idx, ushort iid, ushort hue)\r\n        {\r\n            m_Index = idx;\r\n            m_ItemID = iid;\r\n            m_Hue = hue;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Client.Instance.SendToServer(new MenuResponse(World.Player.CurrentMenuS, World.Player.CurrentMenuI, m_Index,\r\n                m_ItemID, m_Hue));\r\n            World.Player.HasMenu = false;\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"menuresponse {m_Index} {m_ItemID} {m_Hue}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Index, m_ItemID, m_Hue);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.MenuRespA1, m_Index);\r\n        }\r\n    }\r\n\r\n    public class AbsoluteTargetAction : MacroAction\r\n    {\r\n        private TargetInfo m_Info;\r\n\r\n        public AbsoluteTargetAction(string[] args)\r\n        {\r\n            m_Info = new TargetInfo();\r\n\r\n            m_Info.Type = Convert.ToByte(args[1]);\r\n            m_Info.Flags = Convert.ToByte(args[2]);\r\n            m_Info.Serial = Convert.ToUInt32(args[3]);\r\n            m_Info.X = Convert.ToUInt16(args[4]);\r\n            m_Info.Y = Convert.ToUInt16(args[5]);\r\n            m_Info.Z = Convert.ToInt16(args[6]);\r\n            m_Info.Gfx = Convert.ToUInt16(args[7]);\r\n        }\r\n\r\n        public AbsoluteTargetAction(TargetInfo info)\r\n        {\r\n            m_Info = new TargetInfo();\r\n            m_Info.Type = info.Type;\r\n            m_Info.Flags = info.Flags;\r\n            m_Info.Serial = info.Serial;\r\n            m_Info.X = info.X;\r\n            m_Info.Y = info.Y;\r\n            m_Info.Z = info.Z;\r\n            m_Info.Gfx = info.Gfx;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Targeting.Target(m_Info);\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"target {m_Info.Serial}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Info.Type, m_Info.Flags, m_Info.Serial.Value, m_Info.X, m_Info.Y, m_Info.Z,\r\n                m_Info.Gfx);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.GetString(LocString.AbsTarg);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.ReTarget, new MacroMenuCallback(ReTarget)),\r\n                    new MacroMenuItem(LocString.ConvLT, new MacroMenuCallback(ConvertToLastTarget)),\r\n                    new MacroMenuItem(LocString.ConvTargType, new MacroMenuCallback(ConvertToByType)),\r\n                    new MacroMenuItem(LocString.ConvRelLoc, new MacroMenuCallback(ConvertToRelLoc))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Targeting.OneTimeTarget(!m_Info.Serial.IsValid, new Targeting.TargetResponseCallback(ReTargetResponse));\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            m_Info.Gfx = gfx;\r\n            m_Info.Serial = serial;\r\n            m_Info.Type = (byte) (ground ? 1 : 0);\r\n            m_Info.X = pt.X;\r\n            m_Info.Y = pt.Y;\r\n            m_Info.Z = pt.Z;\r\n\r\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n            if (m_Parent != null)\r\n                m_Parent.Update();\r\n        }\r\n\r\n        private void ConvertToLastTarget(object[] args)\r\n        {\r\n            if (m_Parent != null)\r\n                m_Parent.Convert(this, new LastTargetAction());\r\n        }\r\n\r\n        private void ConvertToByType(object[] args)\r\n        {\r\n            if (m_Parent != null)\r\n                m_Parent.Convert(this, new TargetTypeAction(m_Info.Serial.IsMobile, m_Info.Gfx));\r\n        }\r\n\r\n        private void ConvertToRelLoc(object[] args)\r\n        {\r\n            if (m_Parent != null)\r\n                m_Parent.Convert(this,\r\n                    new TargetRelLocAction((sbyte) (m_Info.X - World.Player.Position.X),\r\n                        (sbyte) (m_Info.Y - World.Player.Position\r\n                                     .Y))); //, (sbyte)(m_Info.Z - World.Player.Position.Z) ) );\r\n        }\r\n    }\r\n\r\n    /// <summary>\r\n    /// Action to handle variable macros to alleviate the headache of having multiple macros for the same thing\r\n    ///\r\n    /// This Action does break the pattern that you see in every other action because the data that is stored for this\r\n    /// action exists not in the Macro file, but in a different file that has all the variables in the profile\r\n    /// </summary>\r\n    public class AbsoluteTargetVariableAction : MacroAction\r\n    {\r\n        private TargetInfo _target;\r\n        private readonly string _variableName;\r\n\r\n        public AbsoluteTargetVariableAction(string[] args)\r\n        {\r\n            _variableName = args.Length > 1 ? args[1] : args[0];\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            _target = null;\r\n\r\n            foreach (MacroVariables.MacroVariable mV in MacroVariables.MacroVariableList)\r\n            {\r\n                if (mV.Name.Equals(_variableName))\r\n                {\r\n                    _target = mV.TargetInfo;\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (_target != null)\r\n            {\r\n                Targeting.Target(_target);\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"target '{_variableName}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(_variableName);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"{Language.GetString(LocString.AbsTarg)} (${_variableName})\";\r\n        }\r\n\r\n        /*private MenuItem[] m_MenuItems;\r\n        public override MenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem( LocString.ReTarget, ReTarget )\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Targeting.OneTimeTarget(!_target.Serial.IsValid, new Targeting.TargetResponseCallback(ReTargetResponse));\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            _target.Gfx = gfx;\r\n            _target.Serial = serial;\r\n            _target.Type = (byte)(ground ? 1 : 0);\r\n            _target.X = pt.X;\r\n            _target.Y = pt.Y;\r\n            _target.Z = pt.Z;\r\n\r\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n\r\n            m_Parent?.Update();\r\n        }*/\r\n    }\r\n\r\n    /// <summary>\r\n    /// Action to handle variable macros to alleviate the headache of having multiple macros for the same thing\r\n    ///\r\n    /// This Action does break the pattern that you see in every other action because the data that is stored for this\r\n    /// action exists not in the Macro file, but in a different file that has all the variables in the profile\r\n    /// </summary>\r\n    public class DoubleClickVariableAction : MacroAction\r\n    {\r\n        private Serial _serial;\r\n        private readonly string _variableName;\r\n\r\n        public DoubleClickVariableAction(string[] args)\r\n        {\r\n            _variableName = args.Length > 1 ? args[1] : args[0];\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            _serial = Serial.Zero;\r\n\r\n            foreach (MacroVariables.MacroVariable mV in MacroVariables.MacroVariableList)\r\n            {\r\n                if (mV.Name.Equals(_variableName))\r\n                {\r\n                    _serial = mV.TargetInfo.Serial;\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (_serial != null && _serial != Serial.Zero)\r\n            {\r\n                PlayerData.DoubleClick(_serial);\r\n                return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"dclick '{_variableName}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(_variableName);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"DoubleClick (${_variableName})\";\r\n        }\r\n    }\r\n\r\n    public class TargetTypeAction : MacroAction\r\n    {\r\n        private bool m_Mobile;\r\n        private ushort m_Gfx;\r\n        private object _previousObject;\r\n\r\n        public TargetTypeAction(string[] args)\r\n        {\r\n            m_Mobile = Convert.ToBoolean(args[1]);\r\n            m_Gfx = Convert.ToUInt16(args[2]);\r\n        }\r\n\r\n        public TargetTypeAction(bool mobile, ushort gfx)\r\n        {\r\n            m_Mobile = mobile;\r\n            m_Gfx = gfx;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (Targeting.FromGrabHotKey)\r\n                return false;\r\n\r\n            ArrayList list = new ArrayList();\r\n            if (m_Mobile)\r\n            {\r\n                foreach (Mobile find in World.MobilesInRange())\r\n                {\r\n                    if (find.Body == m_Gfx)\r\n                    {\r\n                        if (Config.GetBool(\"RangeCheckTargetByType\"))\r\n                        {\r\n                            if (Utility.InRange(World.Player.Position, find.Position, 2))\r\n                            {\r\n                                list.Add(find);\r\n                            }\r\n                        }\r\n                        else\r\n                        {\r\n                            list.Add(find);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                foreach (Item i in World.Items.Values)\r\n                {\r\n                    if (i.ItemID == m_Gfx && !i.IsInBank)\r\n                    {\r\n                        if (Config.GetBool(\"RangeCheckTargetByType\"))\r\n                        {\r\n                            if (Utility.InRange(World.Player.Position, i.Position, 2) || i.RootContainer == World.Player)\r\n                            {\r\n                                list.Add(i);\r\n                            }\r\n                        }\r\n                        else\r\n                        {\r\n                            list.Add(i);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (list.Count > 0)\r\n            {\r\n                if (Config.GetBool(\"DiffTargetByType\") && list.Count > 1)\r\n                {\r\n                    object currentObject = list[Utility.Random(list.Count)];\r\n\r\n                    while (_previousObject != null && _previousObject == currentObject)\r\n                    {\r\n                        currentObject = list[Utility.Random(list.Count)];\r\n                    }\r\n\r\n                    Targeting.Target(currentObject);\r\n\r\n                    _previousObject = currentObject;\r\n                }\r\n                else\r\n                {\r\n                    Targeting.Target(list[Utility.Random(list.Count)]);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Warning, LocString.NoItemOfType,\r\n                    m_Mobile ? $\"Character [{m_Gfx}]\" : ((ItemID) m_Gfx).ToString());\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"targettype '{m_Gfx}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Mobile, m_Gfx);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (m_Mobile)\r\n                return Language.Format(LocString.TargByType, m_Gfx);\r\n            else\r\n                return Language.Format(LocString.TargByType, (ItemID) m_Gfx);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.ReTarget, new MacroMenuCallback(ReTarget)),\r\n                    new MacroMenuItem(LocString.ConvLT, new MacroMenuCallback(ConvertToLastTarget))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Targeting.OneTimeTarget(false, new Targeting.TargetResponseCallback(ReTargetResponse));\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            if (!ground && serial.IsValid)\r\n            {\r\n                m_Mobile = serial.IsMobile;\r\n                m_Gfx = gfx;\r\n            }\r\n\r\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n            if (m_Parent != null)\r\n                m_Parent.Update();\r\n        }\r\n\r\n        private void ConvertToLastTarget(object[] args)\r\n        {\r\n            if (m_Parent != null)\r\n                m_Parent.Convert(this, new LastTargetAction());\r\n        }\r\n    }\r\n\r\n    public class TargetRelLocAction : MacroAction\r\n    {\r\n        private sbyte m_X, m_Y;\r\n\r\n        public TargetRelLocAction(string[] args)\r\n        {\r\n            m_X = Convert.ToSByte(args[1]);\r\n            m_Y = Convert.ToSByte(args[2]);\r\n        }\r\n\r\n        public TargetRelLocAction(sbyte x, sbyte y)\r\n        {\r\n            m_X = x;\r\n            m_Y = y;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            ushort x = (ushort) (World.Player.Position.X + m_X);\r\n            ushort y = (ushort) (World.Player.Position.Y + m_Y);\r\n            short z = (short) World.Player.Position.Z;\r\n            try\r\n            {\r\n                Ultima.HuedTile tile = Map.GetTileNear(World.Player.Map, x, y, z);\r\n                Targeting.Target(new Point3D(x, y, tile.Z), (ushort) tile.ID);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Debug, \"Error Executing TargetRelLoc: {0}\", e.Message);\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"targetrelloc {m_X} {m_Y}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_X, m_Y);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.TargRelLocA3, m_X, m_Y, 0);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.ReTarget, new MacroMenuCallback(ReTarget))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void ReTarget(object[] args)\r\n        {\r\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n\r\n            Targeting.OneTimeTarget(true, new Targeting.TargetResponseCallback(ReTargetResponse));\r\n            World.Player.SendMessage(LocString.SelTargAct);\r\n        }\r\n\r\n        private void ReTargetResponse(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            m_X = (sbyte) (pt.X - World.Player.Position.X);\r\n            m_Y = (sbyte) (pt.Y - World.Player.Position.Y);\r\n            // m_Z = (sbyte)(pt.Z - World.Player.Position.Z);\r\n            if (m_Parent != null)\r\n                m_Parent.Update();\r\n        }\r\n    }\r\n\r\n    public class LastTargetAction : MacroAction\r\n    {\r\n        public LastTargetAction()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (Targeting.FromGrabHotKey)\r\n                return false;\r\n\r\n            if (!Targeting.DoLastTarget()) //Targeting.LastTarget( true );\r\n                Targeting.ResendTarget();\r\n            return true;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"Exec: {Language.GetString(LocString.LastTarget)}\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"lasttarget\";\r\n        }\r\n    }\r\n\r\n    public class SetLastTargetAction : MacroWaitAction\r\n    {\r\n        public SetLastTargetAction()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Targeting.TargetSetLastTarget();\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return !Targeting.LastTargetWasSet;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.GetString(LocString.SetLT);\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"setlasttarget\";\r\n        }\r\n    }\r\n\r\n    public class SetMacroVariableTargetAction : MacroWaitAction\r\n    {\r\n        private string m_VarName;\r\n        private MacroVariables.MacroVariable m_MacroVariable;\r\n\r\n        public SetMacroVariableTargetAction(string[] args)\r\n        {\r\n            m_VarName = args.Length > 1 ? args[1] : args[0];\r\n\r\n            FindMacroVariable();\r\n        }\r\n\r\n        public SetMacroVariableTargetAction(string varName)\r\n        {\r\n            m_VarName = varName;\r\n\r\n            FindMacroVariable();\r\n        }\r\n\r\n        private bool FindMacroVariable()\r\n        {\r\n            foreach (MacroVariables.MacroVariable mV in MacroVariables.MacroVariableList)\r\n            {\r\n                if (mV.Name.ToLower().Equals(m_VarName.ToLower()))\r\n                {\r\n                    m_MacroVariable = mV;\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (m_MacroVariable == null)\r\n            {\r\n                m_VarName = $\"?{m_VarName}?\";\r\n                return false;\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (m_MacroVariable == null)\r\n            {\r\n                return false;\r\n            }\r\n\r\n            m_MacroVariable.TargetSetMacroVariable();\r\n\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            if (m_MacroVariable == null)\r\n            {\r\n                return false;\r\n            }\r\n\r\n            return !m_MacroVariable.TargetWasSet;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"Set Macro Variable (${m_VarName})\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"setvar {m_VarName}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_VarName);\r\n        }\r\n    }\r\n\r\n    public class SpeechAction : MacroAction\r\n    {\r\n        private MessageType m_Type;\r\n        private ushort m_Font;\r\n        private ushort m_Hue;\r\n        private string m_Lang;\r\n        private ArrayList m_Keywords;\r\n        private string m_Speech;\r\n\r\n        public SpeechAction(string[] args)\r\n        {\r\n            m_Type = ((MessageType) Convert.ToInt32(args[1])) & ~MessageType.Encoded;\r\n            m_Hue = Convert.ToUInt16(args[2]);\r\n            m_Font = Convert.ToUInt16(args[3]);\r\n            m_Lang = args[4];\r\n\r\n            int count = Convert.ToInt32(args[5]);\r\n            if (count > 0)\r\n            {\r\n                m_Keywords = new ArrayList(count);\r\n                m_Keywords.Add(Convert.ToUInt16(args[6]));\r\n\r\n                for (int i = 1; i < count; i++)\r\n                    m_Keywords.Add(Convert.ToByte(args[6 + i]));\r\n            }\r\n\r\n            m_Speech = args[6 + count];\r\n        }\r\n\r\n        public SpeechAction(MessageType type, ushort hue, ushort font, string lang, ArrayList kw, string speech)\r\n        {\r\n            m_Type = type;\r\n            m_Hue = hue;\r\n            m_Font = font;\r\n            m_Lang = lang;\r\n            m_Keywords = kw;\r\n            m_Speech = speech;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (m_Speech.Length > 1 && m_Speech[0] == '-')\r\n            {\r\n                string text = m_Speech.Substring(1);\r\n                string[] split = text.Split(' ', '\\t');\r\n                CommandCallback call = (CommandCallback) Command.List[split[0]];\r\n                if (call == null && text[0] == '-')\r\n                {\r\n                    call = (CommandCallback) Command.List[\"-\"];\r\n                    if (call != null && split.Length > 1 && split[1] != null && split[1].Length > 1)\r\n                        split[1] = split[1].Substring(1);\r\n                }\r\n\r\n                if (call != null)\r\n                {\r\n                    ArrayList list = new ArrayList();\r\n                    for (int i = 1; i < split.Length; i++)\r\n                    {\r\n                        if (split[i] != null && split[i].Length > 0)\r\n                            list.Add(split[i]);\r\n                    }\r\n\r\n                    call((string[]) list.ToArray(typeof(string)));\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            int hue = m_Hue;\r\n\r\n            if (m_Type != MessageType.Emote)\r\n            {\r\n                if (World.Player.SpeechHue == 0)\r\n                    World.Player.SpeechHue = m_Hue;\r\n                hue = World.Player.SpeechHue;\r\n            }\r\n\r\n            Client.Instance.SendToServer(new ClientUniMessage(m_Type, hue, m_Font, m_Lang, m_Keywords, m_Speech));\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            switch (m_Type)\r\n            {\r\n                case MessageType.Emote:\r\n                    return $\"emote '{m_Speech}'\";\r\n                case MessageType.Whisper:\r\n                    return $\"whisper '{m_Speech}'\";\r\n                case MessageType.Yell:\r\n                    return $\"yell '{m_Speech}'\";\r\n                case MessageType.Alliance:\r\n                    return $\"alliance '{m_Speech}'\";\r\n                case MessageType.Guild:\r\n                    return $\"guild '{m_Speech}'\";\r\n                case MessageType.Regular:\r\n                default:\r\n                    return $\"say '{m_Speech}'\";\r\n            }\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            ArrayList list = new ArrayList(6);\r\n            list.Add((int) m_Type);\r\n            list.Add(m_Hue);\r\n            list.Add(m_Font);\r\n            list.Add(m_Lang);\r\n            if (m_Keywords != null && m_Keywords.Count > 1)\r\n            {\r\n                list.Add((int) m_Keywords.Count);\r\n                for (int i = 0; i < m_Keywords.Count; i++)\r\n                    list.Add(m_Keywords[i]);\r\n            }\r\n            else\r\n            {\r\n                list.Add(\"0\");\r\n            }\r\n\r\n            list.Add(m_Speech);\r\n\r\n            return DoSerialize((object[]) list.ToArray(typeof(object)));\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            //return Language.Format( LocString.SayQA1, m_Speech );\r\n            StringBuilder sb = new StringBuilder();\r\n            switch (m_Type)\r\n            {\r\n                case MessageType.Emote:\r\n                    sb.Append(\"Emote: \");\r\n                    break;\r\n                case MessageType.Whisper:\r\n                    sb.Append(\"Whisper: \");\r\n                    break;\r\n                case MessageType.Yell:\r\n                    sb.Append(\"Yell: \");\r\n                    break;\r\n                case MessageType.Alliance:\r\n                    sb.Append(\"Alliance: \");\r\n                    break;\r\n                case MessageType.Guild:\r\n                    sb.Append(\"Guild: \");\r\n                    break;\r\n                case MessageType.Regular:\r\n                default:\r\n                    sb.Append(\"Say: \");\r\n                    break;\r\n            }\r\n\r\n            sb.Append(m_Speech);\r\n            return sb.ToString();\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (this.m_MenuItems == null)\r\n                this.m_MenuItems = (ToolStripMenuItem[]) new MacroMenuItem[1]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(this.Edit), new object[0])\r\n                };\r\n            return this.m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            if (InputBox.Show(Language.GetString(LocString.EnterNewText), \"Input Box\", this.m_Speech))\r\n                this.m_Speech = InputBox.GetString();\r\n            if (this.Parent == null)\r\n                return;\r\n            this.Parent.Update();\r\n        }\r\n    }\r\n\r\n    public class OverheadMessageAction : MacroAction\r\n    {\r\n        private ushort _hue;\r\n        private string _message;\r\n\r\n        public OverheadMessageAction(string[] args)\r\n        {\r\n            _hue = Convert.ToUInt16(args[1]);\r\n\r\n            List<string> message = new List<string>();\r\n\r\n            for (int i = 2; i < args.Length; i++)\r\n            {\r\n                message.Add(args[i]);\r\n            }\r\n\r\n            _message = string.Join(\" \", message);\r\n        }\r\n\r\n        public OverheadMessageAction(ushort hue, string message)\r\n        {\r\n            _hue = hue;\r\n            _message = message;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (_message.Length > 0)\r\n            {\r\n                World.Player.OverheadMessage(_hue, _message);\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"overhead '{_message}' {_hue}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            ArrayList list = new ArrayList(2) {_hue, _message};\r\n\r\n            return DoSerialize((object[]) list.ToArray(typeof(object)));\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n            sb.Append($\"Overhead ({_hue}): \");\r\n            sb.Append(_message);\r\n            return sb.ToString();\r\n        }\r\n\r\n        private ToolStripMenuItem[] _menuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            return _menuItems ?? (_menuItems = new MacroMenuItem[]\r\n            {\r\n                new MacroMenuItem(LocString.Edit, Edit),\r\n                new MacroMenuItem(LocString.SetHue, SetHue)\r\n            });\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            if (InputBox.Show(Language.GetString(LocString.EnterNewText), \"Input Box\", _message))\r\n                _message = InputBox.GetString();\r\n\r\n            Parent?.Update();\r\n        }\r\n\r\n        private void SetHue(object[] args)\r\n        {\r\n            HueEntry h = new HueEntry(_hue);\r\n\r\n            if (h.ShowDialog(Engine.MainWindow) == DialogResult.OK)\r\n            {\r\n                _hue = (ushort)h.Hue;\r\n            }\r\n\r\n            Parent?.Update();\r\n        }\r\n\r\n    }\r\n\r\n    public class UseSkillAction : MacroAction\r\n    {\r\n        private int m_Skill;\r\n\r\n        public UseSkillAction(string[] args)\r\n        {\r\n            m_Skill = Convert.ToInt32(args[1]);\r\n        }\r\n\r\n        public UseSkillAction(int sk)\r\n        {\r\n            m_Skill = sk;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Client.Instance.SendToServer(new UseSkill(m_Skill));\r\n\r\n            if (m_Skill == Skills.StealthIndex && !World.Player.Visible)\r\n            {\r\n                StealthSteps.Hide();\r\n            }\r\n\r\n            World.Player.LastSkill = m_Skill;\r\n\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"skill '{Skills.GetSkillDisplayName(m_Skill)}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Skill);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.UseSkillA1, Skills.GetSkillDisplayName(m_Skill));\r\n        }\r\n    }\r\n\r\n    public class ExtCastSpellAction : MacroAction\r\n    {\r\n        private Spell m_Spell;\r\n        private Serial m_Book;\r\n\r\n        public ExtCastSpellAction(string[] args)\r\n        {\r\n            m_Spell = Spell.Get(Convert.ToInt32(args[1]));\r\n            m_Book = Serial.Parse(args[2]);\r\n        }\r\n\r\n        public ExtCastSpellAction(int s, Serial book)\r\n        {\r\n            m_Spell = Spell.Get(s);\r\n            m_Book = book;\r\n        }\r\n\r\n        public ExtCastSpellAction(Spell s, Serial book)\r\n        {\r\n            m_Spell = s;\r\n            m_Book = book;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            m_Spell.OnCast(new ExtCastSpell(m_Book, (ushort) m_Spell.GetID()));\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"cast '{m_Spell.GetName()}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Spell.GetID(), m_Book.Value);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.CastSpellA1, m_Spell);\r\n        }\r\n    }\r\n\r\n    public class BookCastSpellAction : MacroAction\r\n    {\r\n        private Spell m_Spell;\r\n        private Serial m_Book;\r\n\r\n        public BookCastSpellAction(string[] args)\r\n        {\r\n            m_Spell = Spell.Get(Convert.ToInt32(args[1]));\r\n            m_Book = Serial.Parse(args[2]);\r\n        }\r\n\r\n        public BookCastSpellAction(int s, Serial book)\r\n        {\r\n            m_Spell = Spell.Get(s);\r\n            m_Book = book;\r\n        }\r\n\r\n        public BookCastSpellAction(Spell s, Serial book)\r\n        {\r\n            m_Spell = s;\r\n            m_Book = book;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            m_Spell.OnCast(new CastSpellFromBook(m_Book, (ushort) m_Spell.GetID()));\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"cast '{m_Spell.GetName()}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Spell.GetID(), m_Book.Value);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.CastSpellA1, m_Spell);\r\n        }\r\n    }\r\n\r\n    public class MacroCastSpellAction : MacroAction\r\n    {\r\n        private Spell m_Spell;\r\n\r\n        public MacroCastSpellAction(string[] args)\r\n        {\r\n            m_Spell = Spell.Get(Convert.ToInt32(args[1]));\r\n        }\r\n\r\n        public MacroCastSpellAction(int s)\r\n        {\r\n            m_Spell = Spell.Get(s);\r\n        }\r\n\r\n        public MacroCastSpellAction(Spell s)\r\n        {\r\n            m_Spell = s;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            m_Spell.OnCast(new CastSpellFromMacro((ushort) m_Spell.GetID()));\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"cast '{m_Spell.GetName()}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Spell.GetID());\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.CastSpellA1, m_Spell);\r\n        }\r\n    }\r\n\r\n    public class SetAbilityAction : MacroAction\r\n    {\r\n        private AOSAbility m_Ability;\r\n\r\n        public SetAbilityAction(string[] args)\r\n        {\r\n            m_Ability = (AOSAbility) Convert.ToInt32(args[1]);\r\n        }\r\n\r\n        public SetAbilityAction(AOSAbility a)\r\n        {\r\n            m_Ability = a;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Client.Instance.SendToServer(new UseAbility(m_Ability));\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"setability '{m_Ability}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize((int) m_Ability);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.SetAbilityA1, m_Ability);\r\n        }\r\n    }\r\n\r\n    public class DressAction : MacroWaitAction\r\n    {\r\n        private string m_Name;\r\n\r\n        public DressAction(string[] args)\r\n        {\r\n            m_Name = args[1];\r\n        }\r\n\r\n        public DressAction(string name)\r\n        {\r\n            m_Name = name;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            DressList list = DressList.Find(m_Name);\r\n            if (list != null)\r\n            {\r\n                list.Dress();\r\n                return false;\r\n            }\r\n            else\r\n            {\r\n                return true;\r\n            }\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return !ActionQueue.Empty;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"dress '{m_Name}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Name);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.DressA1, m_Name);\r\n        }\r\n    }\r\n\r\n    public class UnDressAction : MacroWaitAction\r\n    {\r\n        private string m_Name;\r\n        private byte m_Layer;\r\n\r\n        public UnDressAction(string[] args)\r\n        {\r\n            try\r\n            {\r\n                m_Layer = Convert.ToByte(args[2]);\r\n            }\r\n            catch\r\n            {\r\n                m_Layer = 255;\r\n            }\r\n\r\n            if (m_Layer == 255)\r\n                m_Name = args[1];\r\n            else\r\n                m_Name = \"\";\r\n        }\r\n\r\n        public UnDressAction(string name)\r\n        {\r\n            m_Name = name;\r\n            m_Layer = 255;\r\n        }\r\n\r\n        public UnDressAction(byte layer)\r\n        {\r\n            m_Layer = layer;\r\n            m_Name = \"\";\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (m_Layer == 255)\r\n            {\r\n                DressList list = DressList.Find(m_Name);\r\n                if (list != null)\r\n                {\r\n                    list.Undress();\r\n                    return false;\r\n                }\r\n                else\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n            else if (m_Layer == 0)\r\n            {\r\n                HotKeys.UndressHotKeys.OnUndressAll();\r\n                return false;\r\n            }\r\n            else\r\n            {\r\n                return !Dress.Unequip((Layer) m_Layer);\r\n            }\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return !ActionQueue.Empty;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            if (m_Layer == 255)\r\n            {\r\n                return $\"undress '{m_Name}'\";\r\n            }\r\n\r\n            return m_Layer == 0 ? \"undress\" : $\"undress '{m_Layer}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Name, m_Layer);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (m_Layer == 255)\r\n                return Language.Format(LocString.UndressA1, m_Name);\r\n            else if (m_Layer == 0)\r\n                return Language.GetString(LocString.UndressAll);\r\n            else\r\n                return Language.Format(LocString.UndressLayerA1, (Layer) m_Layer);\r\n        }\r\n    }\r\n\r\n    public class WalkAction : MacroWaitAction\r\n    {\r\n        private Direction m_Dir;\r\n        private static DateTime m_LastWalk = DateTime.MinValue;\r\n\r\n        public static DateTime LastWalkTime\r\n        {\r\n            get { return m_LastWalk; }\r\n            set { m_LastWalk = value; }\r\n        }\r\n\r\n        public WalkAction(string[] args)\r\n        {\r\n            m_Dir = (Direction) (Convert.ToByte(args[1])) & Direction.Mask;\r\n        }\r\n\r\n        public WalkAction(Direction dir)\r\n        {\r\n            m_Dir = dir & Direction.Mask;\r\n        }\r\n\r\n        //private static int m_LastSeq = -1;\r\n        public override bool Perform()\r\n        {\r\n            return !PerformWait();\r\n        }\r\n\r\n        //public static bool IsMacroWalk(byte seq)\r\n        //{\r\n        //    return m_LastSeq != -1 && m_LastSeq == (int)seq && World.Player.HasWalkEntry((byte)m_LastSeq);\r\n        //}\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            if (m_LastWalk + TimeSpan.FromSeconds(0.4) >= DateTime.UtcNow)\r\n            {\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                //m_LastSeq = World.Player.WalkSequence;\r\n                m_LastWalk = DateTime.UtcNow;\r\n\r\n                //Client.Instance.SendToClient(new MobileUpdate(World.Player));\r\n                //Client.Instance.SendToClient(new ForceWalk(m_Dir));\r\n                //Client.Instance.SendToServer(new WalkRequest(m_Dir, World.Player.WalkSequence));\r\n                //World.Player.MoveReq(m_Dir, World.Player.WalkSequence);\r\n\r\n                Client.Instance.RequestMove(m_Dir);\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return m_Dir == Direction.Mask ? $\"walk 'Up'\" : $\"walk '{m_Dir}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize((byte) m_Dir);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.WalkA1, m_Dir != Direction.Mask ? m_Dir.ToString() : \"Up\");\r\n        }\r\n    }\r\n\r\n    public class WaitForMenuAction : MacroWaitAction\r\n    {\r\n        private uint m_MenuID;\r\n\r\n        public WaitForMenuAction(uint gid)\r\n        {\r\n            m_MenuID = gid;\r\n        }\r\n\r\n        public WaitForMenuAction(string[] args)\r\n        {\r\n            if (args.Length > 1)\r\n                m_MenuID = Convert.ToUInt32(args[1]);\r\n\r\n            try\r\n            {\r\n                m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[2]));\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return !(World.Player.HasMenu && (World.Player.CurrentGumpI == m_MenuID || m_MenuID == 0));\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (m_MenuID == 0)\r\n                return Language.GetString(LocString.WaitAnyMenu);\r\n            else\r\n                return Language.Format(LocString.WaitMenuA1, m_MenuID);\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"waitformenu {m_MenuID}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_MenuID, m_Timeout.TotalSeconds);\r\n        }\r\n\r\n        public override bool CheckMatch(MacroAction a)\r\n        {\r\n            if (a is WaitForMenuAction)\r\n            {\r\n                if (m_MenuID == 0 || ((WaitForMenuAction) a).m_MenuID == m_MenuID)\r\n                    return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit)),\r\n                    this.EditTimeoutMenuItem\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertWait(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n    }\r\n\r\n    public class WaitForGumpAction : MacroWaitAction\r\n    {\r\n        private uint m_GumpID;\r\n        private bool m_Strict;\r\n\r\n        public WaitForGumpAction()\r\n        {\r\n            m_GumpID = 0;\r\n            m_Strict = false;\r\n        }\r\n\r\n        public WaitForGumpAction(uint gid)\r\n        {\r\n            m_GumpID = gid;\r\n            m_Strict = false;\r\n        }\r\n\r\n        public WaitForGumpAction(string[] args)\r\n        {\r\n            m_GumpID = Convert.ToUInt32(args[1]);\r\n            try\r\n            {\r\n                m_Strict = Convert.ToBoolean(args[2]);\r\n            }\r\n            catch\r\n            {\r\n                m_Strict = false;\r\n            }\r\n\r\n            try\r\n            {\r\n                m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[3]));\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return !((World.Player.HasGump || World.Player.HasCompressedGump) &&\r\n                     (World.Player.CurrentGumpI == m_GumpID || !m_Strict || m_GumpID == 0));\r\n\r\n            //if (!World.Player.HasGump) // Does the player even have a gump?\r\n            //    return true;\r\n\r\n            //if ((int)World.Player.CurrentGumpI != (int)m_GumpID && m_Strict)\r\n            //    return m_GumpID > 0;\r\n\r\n            //return false;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            if (m_GumpID == 0 || !m_Strict)\r\n                return Language.GetString(LocString.WaitAnyGump);\r\n            else\r\n                return Language.Format(LocString.WaitGumpA1, m_GumpID);\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"waitforgump {m_GumpID}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_GumpID, m_Strict, m_Timeout.TotalSeconds);\r\n        }\r\n\r\n        public override bool CheckMatch(MacroAction a)\r\n        {\r\n            if (a is WaitForGumpAction)\r\n            {\r\n                if (m_GumpID == 0 || ((WaitForGumpAction) a).m_GumpID == m_GumpID)\r\n                    return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit)),\r\n                    new MacroMenuItem(LocString.Null, new MacroMenuCallback(ToggleStrict)),\r\n                    this.EditTimeoutMenuItem\r\n                };\r\n            }\r\n\r\n            if (!m_Strict)\r\n                m_MenuItems[1].Text =\r\n                    $\"Change to \\\"{Language.Format(LocString.WaitGumpA1, m_GumpID)}\\\"\";\r\n            else\r\n                m_MenuItems[1].Text = $\"Change to \\\"{Language.GetString(LocString.WaitAnyGump)}\\\"\";\r\n            m_MenuItems[1].Enabled = m_GumpID != 0 || m_Strict;\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertWait(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n\r\n        private void ToggleStrict(object[] args)\r\n        {\r\n            m_Strict = !m_Strict;\r\n            if (m_Parent != null)\r\n                m_Parent.Update();\r\n        }\r\n    }\r\n\r\n    public class WaitForTargetAction : MacroWaitAction\r\n    {\r\n        public WaitForTargetAction()\r\n        {\r\n            m_Timeout = TimeSpan.FromSeconds(30.0);\r\n        }\r\n\r\n        public WaitForTargetAction(string[] args)\r\n        {\r\n            try\r\n            {\r\n                m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[1]));\r\n            }\r\n            catch\r\n            {\r\n                m_Timeout = TimeSpan.FromSeconds(30.0);\r\n            }\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return !Targeting.HasTarget;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.GetString(LocString.WaitTarg);\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"waitfortarget\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Timeout.TotalSeconds);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit)),\r\n                    this.EditTimeoutMenuItem\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        public override bool CheckMatch(MacroAction a)\r\n        {\r\n            return (a is WaitForTargetAction);\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertWait(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n    }\r\n\r\n    public class PauseAction : MacroWaitAction\r\n    {\r\n        public PauseAction(string[] args)\r\n        {\r\n            m_Timeout = TimeSpan.Parse(args[1]);\r\n        }\r\n\r\n        public PauseAction(int ms)\r\n        {\r\n            m_Timeout = TimeSpan.FromMilliseconds(ms);\r\n        }\r\n\r\n        public PauseAction(TimeSpan time)\r\n        {\r\n            m_Timeout = time;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"wait {m_Timeout.TotalMilliseconds}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Timeout);\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            this.StartTime = DateTime.UtcNow;\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return (StartTime + m_Timeout >= DateTime.UtcNow);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.PauseA1, m_Timeout.TotalSeconds);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertWait(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n    }\r\n\r\n    public class WaitForStatAction : MacroWaitAction\r\n    {\r\n        private byte m_Direction;\r\n        private int m_Value;\r\n        private IfAction.IfVarType m_Stat;\r\n\r\n        public byte Op\r\n        {\r\n            get { return m_Direction; }\r\n        }\r\n\r\n        public int Amount\r\n        {\r\n            get { return m_Value; }\r\n        }\r\n\r\n        public IfAction.IfVarType Stat\r\n        {\r\n            get { return m_Stat; }\r\n        }\r\n\r\n        public WaitForStatAction(string[] args)\r\n        {\r\n            m_Stat = (IfAction.IfVarType) Convert.ToInt32(args[1]);\r\n            m_Direction = Convert.ToByte(args[2]);\r\n            m_Value = Convert.ToInt32(args[3]);\r\n\r\n            try\r\n            {\r\n                m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[4]));\r\n            }\r\n            catch\r\n            {\r\n                m_Timeout = TimeSpan.FromMinutes(60.0);\r\n            }\r\n        }\r\n\r\n        public WaitForStatAction(IfAction.IfVarType stat, byte dir, int val)\r\n        {\r\n            m_Stat = stat;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n\r\n            m_Timeout = TimeSpan.FromMinutes(60.0);\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            string op = m_Direction > 0 ? \">=\" : \"<=\";\r\n            string stat = \"unknown\";\r\n\r\n            switch (m_Stat)\r\n            {\r\n                case IfAction.IfVarType.Hits:\r\n                    stat = \"hits\";\r\n                    break;\r\n                case IfAction.IfVarType.Mana:\r\n                    stat = \"mana\";\r\n                    break;\r\n                case IfAction.IfVarType.Stamina:\r\n                    stat = \"stam\";\r\n                    break;\r\n            }\r\n\r\n            return $\"if {stat} {op} {m_Value}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize((int) m_Stat, m_Direction, m_Value, m_Timeout.TotalSeconds);\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            if (m_Direction > 0)\r\n            {\r\n                // wait for m_Stat >= m_Value\r\n                switch (m_Stat)\r\n                {\r\n                    case IfAction.IfVarType.Hits:\r\n                        return World.Player.Hits < m_Value;\r\n                    case IfAction.IfVarType.Mana:\r\n                        return World.Player.Mana < m_Value;\r\n                    case IfAction.IfVarType.Stamina:\r\n                        return World.Player.Stam < m_Value;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                // wait for m_Stat <= m_Value\r\n                switch (m_Stat)\r\n                {\r\n                    case IfAction.IfVarType.Hits:\r\n                        return World.Player.Hits > m_Value;\r\n                    case IfAction.IfVarType.Mana:\r\n                        return World.Player.Mana > m_Value;\r\n                    case IfAction.IfVarType.Stamina:\r\n                        return World.Player.Stam > m_Value;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return Language.Format(LocString.WaitA3, m_Stat, m_Direction > 0 ? \">=\" : \"<=\", m_Value);\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit)),\r\n                    this.EditTimeoutMenuItem\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertWait(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n    }\r\n\r\n    public class IfAction : MacroAction\r\n    {\r\n        public enum IfVarType : int\r\n        {\r\n            Hits = 0,\r\n            Mana,\r\n            Stamina,\r\n            Poisoned,\r\n            SysMessage,\r\n            Weight,\r\n            Mounted,\r\n            RHandEmpty,\r\n            LHandEmpty,\r\n\r\n            BeginCountersMarker,\r\n\r\n            Counter = 50,\r\n            Skill = 100\r\n        }\r\n\r\n        // 0 <=,1 >=,2 <,3 >\r\n        private sbyte m_Direction;\r\n        private object m_Value;\r\n        private IfVarType m_Var;\r\n        private string m_Counter;\r\n        private int m_SkillId = -1;\r\n        private Assistant.Counter m_CountObj;\r\n\r\n        public sbyte Op\r\n        {\r\n            get { return m_Direction; }\r\n        }\r\n\r\n        public object Value\r\n        {\r\n            get { return m_Value; }\r\n        }\r\n\r\n        public IfVarType Variable\r\n        {\r\n            get { return m_Var; }\r\n        }\r\n\r\n        public string Counter\r\n        {\r\n            get { return m_Counter; }\r\n        }\r\n\r\n        public int SkillId\r\n        {\r\n            get { return m_SkillId; }\r\n        }\r\n\r\n        public IfAction(string[] args)\r\n        {\r\n            m_Var = (IfVarType) Convert.ToInt32(args[1]);\r\n            try\r\n            {\r\n                m_Direction = Convert.ToSByte(args[2]);\r\n                if (m_Direction > 3)\r\n                    m_Direction = 0;\r\n            }\r\n            catch\r\n            {\r\n                m_Direction = -1;\r\n            }\r\n\r\n            if (m_Var == IfVarType.SysMessage)\r\n            {\r\n                m_Value = args[3].ToLower();\r\n            }\r\n            else if (m_Var == IfVarType.Skill)\r\n            {\r\n                if (args[3] is string strVal)\r\n                {\r\n                    m_Value = strVal;\r\n                }\r\n                else\r\n                {\r\n                    m_Value = Convert.ToDouble(args[3]);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                if (args[3] is string strVal)\r\n                {\r\n                    m_Value = strVal;\r\n                }\r\n                else\r\n                {\r\n                    m_Value = Convert.ToInt32(args[3]);\r\n                }\r\n            }\r\n\r\n            if (m_Var == IfVarType.Counter)\r\n                m_Counter = args[4];\r\n\r\n            if (m_Var == IfVarType.Skill)\r\n                m_SkillId = Convert.ToInt32(args[4]);\r\n        }\r\n\r\n        public IfAction(IfVarType var, sbyte dir, int val)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n        }\r\n\r\n        public IfAction(IfVarType var, sbyte dir, string val)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n        }\r\n\r\n        public IfAction(IfVarType var, sbyte dir, int val, string counter)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n            m_Counter = counter;\r\n        }\r\n\r\n        public IfAction(IfVarType var, sbyte dir, double val, int skillId)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n            m_SkillId = skillId;\r\n        }\r\n\r\n        public IfAction(IfVarType var, string text)\r\n        {\r\n            m_Var = var;\r\n            m_Value = text.ToLower();\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            string op = \"??\";\r\n            string expression = \"unknown\";\r\n\r\n            bool useValue = true;\r\n\r\n            switch (m_Direction)\r\n            {\r\n                case 0:\r\n                    // if stat <= m_Value\r\n                    op = \"<=\";\r\n                    break;\r\n                case 1:\r\n                    // if stat >= m_Value\r\n                    op = \">=\";\r\n                    break;\r\n                case 2:\r\n                    // if stat < m_Value\r\n                    op = \"<\";\r\n                    break;\r\n                case 3:\r\n                    // if stat > m_Value\r\n                    op = \">\";\r\n                    break;\r\n            }\r\n\r\n            switch (m_Var)\r\n            {\r\n                case IfAction.IfVarType.Hits:\r\n                    expression = \"hits\";\r\n                    break;\r\n                case IfAction.IfVarType.Mana:\r\n                    expression = \"mana\";\r\n                    break;\r\n                case IfAction.IfVarType.Stamina:\r\n                    expression = \"stam\";\r\n                    break;\r\n                case IfVarType.Poisoned:\r\n                    expression = \"poisoned\";\r\n                    break;\r\n                case IfVarType.SysMessage:\r\n                    expression = $\"insysmsg '{m_Value}'\";\r\n                    useValue = false;\r\n                    break;\r\n                case IfVarType.Weight:\r\n                    expression = \"weight\";\r\n                    break;\r\n                case IfVarType.Mounted:\r\n                    expression = \"mounted\";\r\n                    break;\r\n                case IfVarType.RHandEmpty:\r\n                    expression = \"rhandempty\";\r\n                    break;\r\n                case IfVarType.LHandEmpty:\r\n                    expression = \"lhandempty\";\r\n                    break;\r\n                case IfVarType.Counter:\r\n                    expression = $\"count '{m_Counter}'\";\r\n                    break;\r\n                case IfVarType.Skill:\r\n                    expression = $\"skill '{Skills.GetSkillDisplayName(m_SkillId)}'\";\r\n                    break;\r\n                default:\r\n                    throw new ArgumentOutOfRangeException();\r\n            }\r\n            \r\n            return useValue ? $\"if {expression} {op} {m_Value}\" : $\"if {expression}\";\r\n\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            if (m_Var == IfVarType.Counter && m_Counter != null)\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value, m_Counter);\r\n            else if (m_Var == IfVarType.Skill && m_SkillId != -1)\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value, m_SkillId);\r\n            else\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value);\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public bool Evaluate()\r\n        {\r\n            switch (m_Var)\r\n            {\r\n                case IfVarType.Hits:\r\n                case IfVarType.Mana:\r\n                case IfVarType.Stamina:\r\n                case IfVarType.Weight:\r\n                {\r\n                    bool isNumeric = true;\r\n                    int val;\r\n\r\n                    if (m_Value is string value)\r\n                    {\r\n                        isNumeric = int.TryParse(value, out val);\r\n                    }\r\n                    else\r\n                    {\r\n                        val = Convert.ToInt32(m_Value);\r\n                    }\r\n\r\n                    if (!isNumeric && m_Value is string strVal)\r\n                    {\r\n                        if (strVal.Equals(\"{maxhp}\"))\r\n                        {\r\n                            val = World.Player.HitsMax;\r\n                        }\r\n                        else if (strVal.Equals(\"{maxstam}\"))\r\n                        {\r\n                            val = World.Player.StamMax;\r\n                        }\r\n                        else if (strVal.Equals(\"{maxmana}\"))\r\n                        {\r\n                            val = World.Player.ManaMax;\r\n                        }\r\n                        else\r\n                        {\r\n                            val = 0;\r\n                        }\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            // if stat <= m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case IfVarType.Hits:\r\n                                    return World.Player.Hits <= val;\r\n                                case IfVarType.Mana:\r\n                                    return World.Player.Mana <= val;\r\n                                case IfVarType.Stamina:\r\n                                    return World.Player.Stam <= val;\r\n                                case IfVarType.Weight:\r\n                                    return World.Player.Weight <= val;\r\n                            }\r\n\r\n                            break;\r\n                        case 1:\r\n                            // if stat >= m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case IfVarType.Hits:\r\n                                    return World.Player.Hits >= val;\r\n                                case IfVarType.Mana:\r\n                                    return World.Player.Mana >= val;\r\n                                case IfVarType.Stamina:\r\n                                    return World.Player.Stam >= val;\r\n                                case IfVarType.Weight:\r\n                                    return World.Player.Weight >= val;\r\n                            }\r\n\r\n                            break;\r\n                        case 2:\r\n                            // if stat < m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case IfVarType.Hits:\r\n                                    return World.Player.Hits < val;\r\n                                case IfVarType.Mana:\r\n                                    return World.Player.Mana < val;\r\n                                case IfVarType.Stamina:\r\n                                    return World.Player.Stam < val;\r\n                                case IfVarType.Weight:\r\n                                    return World.Player.Weight < val;\r\n                            }\r\n\r\n                            break;\r\n                        case 3:\r\n                            // if stat > m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case IfVarType.Hits:\r\n                                    return World.Player.Hits > val;\r\n                                case IfVarType.Mana:\r\n                                    return World.Player.Mana > val;\r\n                                case IfVarType.Stamina:\r\n                                    return World.Player.Stam > val;\r\n                                case IfVarType.Weight:\r\n                                    return World.Player.Weight > val;\r\n                            }\r\n\r\n                            break;\r\n                    }\r\n\r\n                    return false;\r\n                }\r\n\r\n                case IfVarType.Poisoned:\r\n                {\r\n                    if (Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n                        return World.Player.Poisoned;\r\n                    else\r\n                        return false;\r\n                }\r\n\r\n                case IfVarType.SysMessage:\r\n                {\r\n                    string text = (string) m_Value;\r\n\r\n                    return SystemMessages.Exists(text);\r\n\r\n                }\r\n\r\n                case IfVarType.Mounted:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.Mount) != null;\r\n                }\r\n\r\n                case IfVarType.RHandEmpty:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.RightHand) == null;\r\n                }\r\n\r\n                case IfVarType.LHandEmpty:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.LeftHand) == null;\r\n                }\r\n\r\n                case IfVarType.Skill:\r\n\r\n                    double skillValToCompare;\r\n\r\n                    if (m_Value is string skillVal)\r\n                    {\r\n                        double.TryParse(skillVal, out skillValToCompare);\r\n                    }\r\n                    else\r\n                    {\r\n                        skillValToCompare = Convert.ToDouble(m_Value);\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            return World.Player.Skills[m_SkillId].Value <= skillValToCompare;\r\n                        case 1:\r\n                            return World.Player.Skills[m_SkillId].Value >= skillValToCompare;\r\n                        case 2:\r\n                            return World.Player.Skills[m_SkillId].Value < skillValToCompare;\r\n                        case 3:\r\n                            return World.Player.Skills[m_SkillId].Value > skillValToCompare;\r\n                        default:\r\n                            return World.Player.Skills[m_SkillId].Value <= skillValToCompare;\r\n                    }\r\n\r\n                case IfVarType.Counter:\r\n                {\r\n                    if (m_CountObj == null)\r\n                    {\r\n                        foreach (Assistant.Counter c in Assistant.Counter.List)\r\n                        {\r\n                            if (c.Name == m_Counter)\r\n                            {\r\n                                m_CountObj = c;\r\n                                break;\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    if (m_CountObj == null || !m_CountObj.Enabled)\r\n                        return false;\r\n\r\n                    int val;\r\n\r\n                    if (m_Value is string value)\r\n                    {\r\n                        int.TryParse(value, out val);\r\n                    }\r\n                    else\r\n                    {\r\n                        val = Convert.ToInt32(m_Value);\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            return m_CountObj.Amount <= val;\r\n                        case 1:\r\n                            return m_CountObj.Amount >= val;\r\n                        case 2:\r\n                            return m_CountObj.Amount < val;\r\n                        case 3:\r\n                            return m_CountObj.Amount > val;\r\n                        default:\r\n                            return m_CountObj.Amount <= val;\r\n                    }\r\n                }\r\n\r\n                default:\r\n                    return false;\r\n            }\r\n        }\r\n\r\n        private string DirectionString()\r\n        {\r\n            switch (m_Direction)\r\n            {\r\n                case 0:\r\n                    return \"<=\";\r\n                case 1:\r\n                    return \">=\";\r\n                case 2:\r\n                    return \"<\";\r\n                case 3:\r\n                    return \">\";\r\n                default:\r\n                    return \"<=\";\r\n            }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            switch (m_Var)\r\n            {\r\n                case IfVarType.Hits:\r\n                case IfVarType.Mana:\r\n                case IfVarType.Stamina:\r\n                case IfVarType.Weight:\r\n                    return $\"If ( {m_Var} {DirectionString()} {m_Value} )\";\r\n                case IfVarType.Poisoned:\r\n                    return \"If ( Poisoned )\";\r\n                case IfVarType.SysMessage:\r\n                {\r\n                    string str = (string) m_Value;\r\n                    if (str.Length > 10)\r\n                        str = str.Substring(0, 7) + \"...\";\r\n                    return $\"If ( SysMessage \\\"{str}\\\" )\";\r\n                }\r\n\r\n                case IfVarType.Skill:\r\n                    return $\"If ( \\\"{Skills.GetSkillDisplayName(m_SkillId)}\\\" {DirectionString()} {m_Value})\";\r\n                case IfVarType.Mounted:\r\n                    return \"If ( Mounted )\";\r\n                case IfVarType.RHandEmpty:\r\n                    return \"If ( R-Hand Empty )\";\r\n                case IfVarType.LHandEmpty:\r\n                    return \"If ( L-Hand Empty )\";\r\n                case IfVarType.Counter:\r\n                    return $\"If ( \\\"{m_Counter} count\\\" {DirectionString()} {m_Value} )\";\r\n                default:\r\n                    return \"If ( ??? )\";\r\n            }\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertIf(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n    }\r\n\r\n    public class ElseAction : MacroAction\r\n    {\r\n        public ElseAction()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return \"Else\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"else\";\r\n        }\r\n    }\r\n\r\n    public class EndIfAction : MacroAction\r\n    {\r\n        public EndIfAction()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return \"End If\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"endif\";\r\n        }\r\n    }\r\n\r\n    public class HotKeyAction : MacroAction\r\n    {\r\n        private KeyData m_Key;\r\n\r\n        public HotKeyAction(KeyData hk)\r\n        {\r\n            m_Key = hk;\r\n        }\r\n\r\n        public HotKeyAction(string[] args)\r\n        {\r\n            try\r\n            {\r\n                int loc = Convert.ToInt32(args[1]);\r\n                if (loc != 0)\r\n                    m_Key = HotKey.Get(loc);\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            if (m_Key == null)\r\n                m_Key = HotKey.Get(args[2]);\r\n\r\n            if (m_Key == null)\r\n                throw new Exception(\"HotKey not found.\");\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (Client.Instance.AllowBit(FeatureBit.LoopingMacros) ||\r\n                m_Key.DisplayName.IndexOf(Language.GetString(LocString.PlayA1).Replace(@\"{0}\", \"\")) == -1)\r\n                m_Key.Callback();\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"hotkey '{m_Key.DisplayName}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Key.LocName, m_Key.StrName == null ? \"\" : m_Key.StrName);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"Exec: {m_Key.DisplayName}\";\r\n        }\r\n    }\r\n\r\n    public class ForAction : MacroAction\r\n    {\r\n        private int m_Max, m_Count;\r\n\r\n        public int Count\r\n        {\r\n            get { return m_Count; }\r\n            set { m_Count = value; }\r\n        }\r\n\r\n        public int Max\r\n        {\r\n            get { return m_Max; }\r\n        }\r\n\r\n        public ForAction(string[] args)\r\n        {\r\n            m_Max = Convert.ToInt32(args[1]);\r\n        }\r\n\r\n        public ForAction(int max)\r\n        {\r\n            m_Max = max;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"for {m_Max}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Max);\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"For ( 1 to {m_Max} )\";\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            if (InputBox.Show(Language.GetString(LocString.NumIter), \"Input Box\", m_Max.ToString()))\r\n                m_Max = InputBox.GetInt(m_Max);\r\n            if (Parent != null)\r\n                Parent.Update();\r\n        }\r\n    }\r\n\r\n    public class EndForAction : MacroAction\r\n    {\r\n        public EndForAction()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return \"End For\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"endfor\";\r\n        }\r\n    }\r\n\r\n    public class WhileAction : MacroAction\r\n    {\r\n        public enum WhileVarType : int\r\n        {\r\n            Hits = 0,\r\n            Mana,\r\n            Stamina,\r\n            Poisoned,\r\n            SysMessage,\r\n            Weight,\r\n            Mounted,\r\n            RHandEmpty,\r\n            LHandEmpty,\r\n\r\n            BeginCountersMarker,\r\n\r\n            Counter = 50,\r\n            Skill = 100\r\n        }\r\n\r\n        // 0 <=,1 >=,2 <,3 >\r\n        private sbyte m_Direction;\r\n        private object m_Value;\r\n        private WhileVarType m_Var;\r\n        private string m_Counter;\r\n        private int m_SkillId = -1;\r\n        private Assistant.Counter m_CountObj;\r\n\r\n        public sbyte Op\r\n        {\r\n            get { return m_Direction; }\r\n        }\r\n\r\n        public object Value\r\n        {\r\n            get { return m_Value; }\r\n        }\r\n\r\n        public WhileVarType Variable\r\n        {\r\n            get { return m_Var; }\r\n        }\r\n\r\n        public string Counter\r\n        {\r\n            get { return m_Counter; }\r\n        }\r\n\r\n        public int SkillId\r\n        {\r\n            get { return m_SkillId; }\r\n        }\r\n\r\n        public WhileAction(string[] args)\r\n        {\r\n            m_Var = (WhileVarType) Convert.ToInt32(args[1]);\r\n            try\r\n            {\r\n                m_Direction = Convert.ToSByte(args[2]);\r\n                if (m_Direction > 3)\r\n                    m_Direction = 0;\r\n            }\r\n            catch\r\n            {\r\n                m_Direction = -1;\r\n            }\r\n\r\n            if (m_Var == WhileVarType.SysMessage)\r\n            {\r\n                m_Value = args[3].ToLower();\r\n            }\r\n            else if (m_Var == WhileVarType.Skill)\r\n            {\r\n                if (args[3] is string strVal)\r\n                {\r\n                    m_Value = strVal;\r\n                }\r\n                else\r\n                {\r\n                    m_Value = Convert.ToDouble(args[3]);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                if (args[3] is string strVal)\r\n                {\r\n                    m_Value = strVal;\r\n                }\r\n                else\r\n                {\r\n                    m_Value = Convert.ToInt32(args[3]);\r\n                }\r\n            }\r\n\r\n            if (m_Var == WhileVarType.Counter)\r\n                m_Counter = args[4];\r\n\r\n            if (m_Var == WhileVarType.Skill)\r\n                m_SkillId = Convert.ToInt32(args[4]);\r\n        }\r\n\r\n        public WhileAction(WhileVarType var, sbyte dir, int val)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n        }\r\n\r\n        public WhileAction(WhileVarType var, sbyte dir, string val)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n        }\r\n\r\n        public WhileAction(WhileVarType var, sbyte dir, int val, string counter)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n            m_Counter = counter;\r\n        }\r\n\r\n        public WhileAction(WhileVarType var, sbyte dir, double val, int skillId)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n            m_SkillId = skillId;\r\n        }\r\n\r\n        public WhileAction(WhileVarType var, string text)\r\n        {\r\n            m_Var = var;\r\n            m_Value = text.ToLower();\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            string op = \"??\";\r\n            string expression = \"unknown\";\r\n\r\n            bool useValue = true;\r\n\r\n            switch (m_Direction)\r\n            {\r\n                case 0:\r\n                    // if stat <= m_Value\r\n                    op = \"<=\";\r\n                    break;\r\n                case 1:\r\n                    // if stat >= m_Value\r\n                    op = \">=\";\r\n                    break;\r\n                case 2:\r\n                    // if stat < m_Value\r\n                    op = \"<\";\r\n                    break;\r\n                case 3:\r\n                    // if stat > m_Value\r\n                    op = \">\";\r\n                    break;\r\n            }\r\n\r\n            switch (m_Var)\r\n            {\r\n                case WhileVarType.Hits:\r\n                    expression = \"hits\";\r\n                    break;\r\n                case WhileVarType.Mana:\r\n                    expression = \"mana\";\r\n                    break;\r\n                case WhileVarType.Stamina:\r\n                    expression = \"stam\";\r\n                    break;\r\n                case WhileVarType.Poisoned:\r\n                    expression = \"poisoned\";\r\n                    break;\r\n                case WhileVarType.SysMessage:\r\n                    expression = $\"insysmsg '{m_Value}'\";\r\n                    useValue = false;\r\n                    break;\r\n                case WhileVarType.Weight:\r\n                    expression = \"weight\";\r\n                    break;\r\n                case WhileVarType.Mounted:\r\n                    expression = \"mounted\";\r\n                    break;\r\n                case WhileVarType.RHandEmpty:\r\n                    expression = \"rhandempty\";\r\n                    break;\r\n                case WhileVarType.LHandEmpty:\r\n                    expression = \"lhandempty\";\r\n                    break;\r\n                case WhileVarType.Counter:\r\n                    expression = $\"count '{m_Counter}'\";\r\n                    break;\r\n                case WhileVarType.Skill:\r\n                    expression = $\"skill '{Skills.GetSkillDisplayName(m_SkillId)}'\";\r\n                    break;\r\n                default:\r\n                    throw new ArgumentOutOfRangeException();\r\n            }\r\n            \r\n            return useValue ? $\"while {expression} {op} {m_Value}\" : $\"while {expression}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            if (m_Var == WhileVarType.Counter && m_Counter != null)\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value, m_Counter);\r\n            else if (m_Var == WhileVarType.Skill && m_SkillId != -1)\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value, m_SkillId);\r\n            else\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value);\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public bool Evaluate()\r\n        {\r\n            switch (m_Var)\r\n            {\r\n                case WhileVarType.Hits:\r\n                case WhileVarType.Mana:\r\n                case WhileVarType.Stamina:\r\n                case WhileVarType.Weight:\r\n                {\r\n                    bool isNumeric = true;\r\n                    int val;\r\n\r\n                    if (m_Value is string value)\r\n                    {\r\n                        isNumeric = int.TryParse(value, out val);\r\n                    }\r\n                    else\r\n                    {\r\n                        val = Convert.ToInt32(m_Value);\r\n                    }\r\n\r\n                    if (!isNumeric && m_Value is string strVal)\r\n                    {\r\n                        if (strVal.Equals(\"{maxhp}\"))\r\n                        {\r\n                            val = World.Player.HitsMax;\r\n                        }\r\n                        else if (strVal.Equals(\"{maxstam}\"))\r\n                        {\r\n                            val = World.Player.StamMax;\r\n                        }\r\n                        else if (strVal.Equals(\"{maxmana}\"))\r\n                        {\r\n                            val = World.Player.ManaMax;\r\n                        }\r\n                        else\r\n                        {\r\n                            val = 0;\r\n                        }\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            // if stat <= m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case WhileVarType.Hits:\r\n                                    return World.Player.Hits <= val;\r\n                                case WhileVarType.Mana:\r\n                                    return World.Player.Mana <= val;\r\n                                case WhileVarType.Stamina:\r\n                                    return World.Player.Stam <= val;\r\n                                case WhileVarType.Weight:\r\n                                    return World.Player.Weight <= val;\r\n                            }\r\n\r\n                            break;\r\n                        case 1:\r\n                            // if stat >= m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case WhileVarType.Hits:\r\n                                    return World.Player.Hits >= val;\r\n                                case WhileVarType.Mana:\r\n                                    return World.Player.Mana >= val;\r\n                                case WhileVarType.Stamina:\r\n                                    return World.Player.Stam >= val;\r\n                                case WhileVarType.Weight:\r\n                                    return World.Player.Weight >= val;\r\n                            }\r\n\r\n                            break;\r\n                        case 2:\r\n                            // if stat < m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case WhileVarType.Hits:\r\n                                    return World.Player.Hits < val;\r\n                                case WhileVarType.Mana:\r\n                                    return World.Player.Mana < val;\r\n                                case WhileVarType.Stamina:\r\n                                    return World.Player.Stam < val;\r\n                                case WhileVarType.Weight:\r\n                                    return World.Player.Weight < val;\r\n                            }\r\n\r\n                            break;\r\n                        case 3:\r\n                            // if stat > m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case WhileVarType.Hits:\r\n                                    return World.Player.Hits > val;\r\n                                case WhileVarType.Mana:\r\n                                    return World.Player.Mana > val;\r\n                                case WhileVarType.Stamina:\r\n                                    return World.Player.Stam > val;\r\n                                case WhileVarType.Weight:\r\n                                    return World.Player.Weight > val;\r\n                            }\r\n\r\n                            break;\r\n                    }\r\n\r\n                    return false;\r\n                }\r\n\r\n                case WhileVarType.Poisoned:\r\n                {\r\n                    if (Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n                        return World.Player.Poisoned;\r\n                    else\r\n                        return false;\r\n                }\r\n\r\n                case WhileVarType.SysMessage:\r\n                {\r\n                    string text = (string) m_Value;\r\n\r\n                    return SystemMessages.Exists(text);\r\n                }\r\n\r\n                case WhileVarType.Mounted:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.Mount) != null;\r\n                }\r\n\r\n                case WhileVarType.RHandEmpty:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.RightHand) == null;\r\n                }\r\n\r\n                case WhileVarType.LHandEmpty:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.LeftHand) == null;\r\n                }\r\n\r\n                case WhileVarType.Skill:\r\n\r\n                    double skillValToCompare;\r\n\r\n                    if (m_Value is string skillVal)\r\n                    {\r\n                        double.TryParse(skillVal, out skillValToCompare);\r\n                    }\r\n                    else\r\n                    {\r\n                        skillValToCompare = Convert.ToDouble(m_Value);\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            return World.Player.Skills[m_SkillId].Value <= skillValToCompare;\r\n                        case 1:\r\n                            return World.Player.Skills[m_SkillId].Value >= skillValToCompare;\r\n                        case 2:\r\n                            return World.Player.Skills[m_SkillId].Value < skillValToCompare;\r\n                        case 3:\r\n                            return World.Player.Skills[m_SkillId].Value > skillValToCompare;\r\n                        default:\r\n                            return World.Player.Skills[m_SkillId].Value <= skillValToCompare;\r\n                    }\r\n\r\n                case WhileVarType.Counter:\r\n                {\r\n                    if (m_CountObj == null)\r\n                    {\r\n                        foreach (Assistant.Counter c in Assistant.Counter.List)\r\n                        {\r\n                            if (c.Name == m_Counter)\r\n                            {\r\n                                m_CountObj = c;\r\n                                break;\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    if (m_CountObj == null || !m_CountObj.Enabled)\r\n                        return false;\r\n\r\n                    int val;\r\n\r\n                    if (m_Value is string value)\r\n                    {\r\n                        int.TryParse(value, out val);\r\n                    }\r\n                    else\r\n                    {\r\n                        val = Convert.ToInt32(m_Value);\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            return m_CountObj.Amount <= val;\r\n                        case 1:\r\n                            return m_CountObj.Amount >= val;\r\n                        case 2:\r\n                            return m_CountObj.Amount < val;\r\n                        case 3:\r\n                            return m_CountObj.Amount > val;\r\n                        default:\r\n                            return m_CountObj.Amount <= val;\r\n                    }\r\n                }\r\n\r\n                default:\r\n                    return false;\r\n            }\r\n        }\r\n\r\n        private string DirectionString()\r\n        {\r\n            switch (m_Direction)\r\n            {\r\n                case 0:\r\n                    return \"<=\";\r\n                case 1:\r\n                    return \">=\";\r\n                case 2:\r\n                    return \"<\";\r\n                case 3:\r\n                    return \">\";\r\n                default:\r\n                    return \"<=\";\r\n            }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            switch (m_Var)\r\n            {\r\n                case WhileVarType.Hits:\r\n                case WhileVarType.Mana:\r\n                case WhileVarType.Stamina:\r\n                case WhileVarType.Weight:\r\n                    return $\"While ( {m_Var} {DirectionString()} {m_Value} )\";\r\n                case WhileVarType.Poisoned:\r\n                    return \"While ( Poisoned )\";\r\n                case WhileVarType.SysMessage:\r\n                {\r\n                    string str = (string) m_Value;\r\n                    if (str.Length > 10)\r\n                        str = str.Substring(0, 7) + \"...\";\r\n                    return $\"While ( SysMessage \\\"{str}\\\" )\";\r\n                }\r\n\r\n                case WhileVarType.Skill:\r\n                    return $\"While ( \\\"{Skills.GetSkillDisplayName(m_SkillId)}\\\" {DirectionString()} {m_Value})\";\r\n                case WhileVarType.Mounted:\r\n                    return \"While ( Mounted )\";\r\n                case WhileVarType.RHandEmpty:\r\n                    return \"While ( R-Hand Empty )\";\r\n                case WhileVarType.LHandEmpty:\r\n                    return \"While ( L-Hand Empty )\";\r\n                case WhileVarType.Counter:\r\n                    return $\"While ( \\\"{m_Counter} count\\\" {DirectionString()} {m_Value} )\";\r\n                default:\r\n                    return \"While ( ??? )\";\r\n            }\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertWhile(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n    }\r\n\r\n    public class EndWhileAction : MacroAction\r\n    {\r\n        public EndWhileAction()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return \"End While\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"endwhile\";\r\n        }\r\n    }\r\n\r\n    public class StartDoWhileAction : MacroAction\r\n    {\r\n        public StartDoWhileAction()\r\n        {\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return \"Do\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"# do-while not implemented, use while\";\r\n        }\r\n    }\r\n\r\n    public class DoWhileAction : MacroAction\r\n    {\r\n        public enum DoWhileVarType : int\r\n        {\r\n            Hits = 0,\r\n            Mana,\r\n            Stamina,\r\n            Poisoned,\r\n            SysMessage,\r\n            Weight,\r\n            Mounted,\r\n            RHandEmpty,\r\n            LHandEmpty,\r\n\r\n            BeginCountersMarker,\r\n\r\n            Counter = 50,\r\n            Skill = 100\r\n        }\r\n\r\n        // 0 <=,1 >=,2 <,3 >\r\n        private sbyte m_Direction;\r\n        private object m_Value;\r\n        private DoWhileVarType m_Var;\r\n        private string m_Counter;\r\n        private int m_SkillId = -1;\r\n        private Assistant.Counter m_CountObj;\r\n\r\n        public sbyte Op\r\n        {\r\n            get { return m_Direction; }\r\n        }\r\n\r\n        public object Value\r\n        {\r\n            get { return m_Value; }\r\n        }\r\n\r\n        public DoWhileVarType Variable\r\n        {\r\n            get { return m_Var; }\r\n        }\r\n\r\n        public string Counter\r\n        {\r\n            get { return m_Counter; }\r\n        }\r\n\r\n        public int SkillId\r\n        {\r\n            get { return m_SkillId; }\r\n        }\r\n\r\n        public DoWhileAction(string[] args)\r\n        {\r\n            m_Var = (DoWhileVarType) Convert.ToInt32(args[1]);\r\n            try\r\n            {\r\n                m_Direction = Convert.ToSByte(args[2]);\r\n                if (m_Direction > 3)\r\n                    m_Direction = 0;\r\n            }\r\n            catch\r\n            {\r\n                m_Direction = -1;\r\n            }\r\n\r\n            if (m_Var == DoWhileVarType.SysMessage)\r\n            {\r\n                m_Value = args[3].ToLower();\r\n            }\r\n            else if (m_Var == DoWhileVarType.Skill)\r\n            {\r\n                if (args[3] is string strVal)\r\n                {\r\n                    m_Value = strVal;\r\n                }\r\n                else\r\n                {\r\n                    m_Value = Convert.ToDouble(args[3]);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                if (args[3] is string strVal)\r\n                {\r\n                    m_Value = strVal;\r\n                }\r\n                else\r\n                {\r\n                    m_Value = Convert.ToInt32(args[3]);\r\n                }\r\n            }\r\n\r\n            if (m_Var == DoWhileVarType.Counter)\r\n                m_Counter = args[4];\r\n\r\n            if (m_Var == DoWhileVarType.Skill)\r\n                m_SkillId = Convert.ToInt32(args[4]);\r\n        }\r\n\r\n        public DoWhileAction(DoWhileVarType var, sbyte dir, int val)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n        }\r\n\r\n        public DoWhileAction(DoWhileVarType var, sbyte dir, string val)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n        }\r\n\r\n        public DoWhileAction(DoWhileVarType var, sbyte dir, int val, string counter)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n            m_Counter = counter;\r\n        }\r\n\r\n        public DoWhileAction(DoWhileVarType var, sbyte dir, double val, int skillId)\r\n        {\r\n            m_Var = var;\r\n            m_Direction = dir;\r\n            m_Value = val;\r\n            m_SkillId = skillId;\r\n        }\r\n\r\n        public DoWhileAction(DoWhileVarType var, string text)\r\n        {\r\n            m_Var = var;\r\n            m_Value = text.ToLower();\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return \"# do-while not implemented, use while\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            if (m_Var == DoWhileVarType.Counter && m_Counter != null)\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value, m_Counter);\r\n            else if (m_Var == DoWhileVarType.Skill && m_SkillId != -1)\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value, m_SkillId);\r\n            else\r\n                return DoSerialize((int) m_Var, m_Direction, m_Value);\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return true;\r\n        }\r\n\r\n        public bool Evaluate()\r\n        {\r\n            switch (m_Var)\r\n            {\r\n                case DoWhileVarType.Hits:\r\n                case DoWhileVarType.Mana:\r\n                case DoWhileVarType.Stamina:\r\n                case DoWhileVarType.Weight:\r\n                {\r\n                    bool isNumeric = true;\r\n                    int val;\r\n\r\n                    if (m_Value is string value)\r\n                    {\r\n                        isNumeric = int.TryParse(value, out val);\r\n                    }\r\n                    else\r\n                    {\r\n                        val = Convert.ToInt32(m_Value);\r\n                    }\r\n\r\n                    if (!isNumeric && m_Value is string strVal)\r\n                    {\r\n                        if (strVal.Equals(\"{maxhp}\"))\r\n                        {\r\n                            val = World.Player.HitsMax;\r\n                        }\r\n                        else if (strVal.Equals(\"{maxstam}\"))\r\n                        {\r\n                            val = World.Player.StamMax;\r\n                        }\r\n                        else if (strVal.Equals(\"{maxmana}\"))\r\n                        {\r\n                            val = World.Player.ManaMax;\r\n                        }\r\n                        else\r\n                        {\r\n                            val = 0;\r\n                        }\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            // if stat <= m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case DoWhileVarType.Hits:\r\n                                    return World.Player.Hits <= val;\r\n                                case DoWhileVarType.Mana:\r\n                                    return World.Player.Mana <= val;\r\n                                case DoWhileVarType.Stamina:\r\n                                    return World.Player.Stam <= val;\r\n                                case DoWhileVarType.Weight:\r\n                                    return World.Player.Weight <= val;\r\n                            }\r\n\r\n                            break;\r\n                        case 1:\r\n                            // if stat >= m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case DoWhileVarType.Hits:\r\n                                    return World.Player.Hits >= val;\r\n                                case DoWhileVarType.Mana:\r\n                                    return World.Player.Mana >= val;\r\n                                case DoWhileVarType.Stamina:\r\n                                    return World.Player.Stam >= val;\r\n                                case DoWhileVarType.Weight:\r\n                                    return World.Player.Weight >= val;\r\n                            }\r\n\r\n                            break;\r\n                        case 2:\r\n                            // if stat < m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case DoWhileVarType.Hits:\r\n                                    return World.Player.Hits < val;\r\n                                case DoWhileVarType.Mana:\r\n                                    return World.Player.Mana < val;\r\n                                case DoWhileVarType.Stamina:\r\n                                    return World.Player.Stam < val;\r\n                                case DoWhileVarType.Weight:\r\n                                    return World.Player.Weight < val;\r\n                            }\r\n\r\n                            break;\r\n                        case 3:\r\n                            // if stat > m_Value\r\n                            switch (m_Var)\r\n                            {\r\n                                case DoWhileVarType.Hits:\r\n                                    return World.Player.Hits > val;\r\n                                case DoWhileVarType.Mana:\r\n                                    return World.Player.Mana > val;\r\n                                case DoWhileVarType.Stamina:\r\n                                    return World.Player.Stam > val;\r\n                                case DoWhileVarType.Weight:\r\n                                    return World.Player.Weight > val;\r\n                            }\r\n\r\n                            break;\r\n                    }\r\n\r\n                    return false;\r\n                }\r\n\r\n                case DoWhileVarType.Poisoned:\r\n                {\r\n                    if (Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n                        return World.Player.Poisoned;\r\n                    else\r\n                        return false;\r\n                }\r\n\r\n                case DoWhileVarType.SysMessage:\r\n                {\r\n                    string text = (string) m_Value;\r\n\r\n                    return SystemMessages.Exists(text);\r\n                }\r\n\r\n                case DoWhileVarType.Mounted:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.Mount) != null;\r\n                }\r\n\r\n                case DoWhileVarType.RHandEmpty:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.RightHand) == null;\r\n                }\r\n\r\n                case DoWhileVarType.LHandEmpty:\r\n                {\r\n                    return World.Player.GetItemOnLayer(Layer.LeftHand) == null;\r\n                }\r\n\r\n                case DoWhileVarType.Skill:\r\n\r\n                    double skillValToCompare;\r\n\r\n                    if (m_Value is string skillVal)\r\n                    {\r\n                        double.TryParse(skillVal, out skillValToCompare);\r\n                    }\r\n                    else\r\n                    {\r\n                        skillValToCompare = Convert.ToDouble(m_Value);\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            return World.Player.Skills[m_SkillId].Value <= skillValToCompare;\r\n                        case 1:\r\n                            return World.Player.Skills[m_SkillId].Value >= skillValToCompare;\r\n                        case 2:\r\n                            return World.Player.Skills[m_SkillId].Value < skillValToCompare;\r\n                        case 3:\r\n                            return World.Player.Skills[m_SkillId].Value > skillValToCompare;\r\n                        default:\r\n                            return World.Player.Skills[m_SkillId].Value <= skillValToCompare;\r\n                    }\r\n\r\n                case DoWhileVarType.Counter:\r\n                {\r\n                    if (m_CountObj == null)\r\n                    {\r\n                        foreach (Assistant.Counter c in Assistant.Counter.List)\r\n                        {\r\n                            if (c.Name == m_Counter)\r\n                            {\r\n                                m_CountObj = c;\r\n                                break;\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    if (m_CountObj == null || !m_CountObj.Enabled)\r\n                        return false;\r\n\r\n                    int val;\r\n\r\n                    if (m_Value is string value)\r\n                    {\r\n                        int.TryParse(value, out val);\r\n                    }\r\n                    else\r\n                    {\r\n                        val = Convert.ToInt32(m_Value);\r\n                    }\r\n\r\n                    switch (m_Direction)\r\n                    {\r\n                        case 0:\r\n                            return m_CountObj.Amount <= val;\r\n                        case 1:\r\n                            return m_CountObj.Amount >= val;\r\n                        case 2:\r\n                            return m_CountObj.Amount < val;\r\n                        case 3:\r\n                            return m_CountObj.Amount > val;\r\n                        default:\r\n                            return m_CountObj.Amount <= val;\r\n                    }\r\n                }\r\n\r\n                default:\r\n                    return false;\r\n            }\r\n        }\r\n\r\n        private string DirectionString()\r\n        {\r\n            switch (m_Direction)\r\n            {\r\n                case 0:\r\n                    return \"<=\";\r\n                case 1:\r\n                    return \">=\";\r\n                case 2:\r\n                    return \"<\";\r\n                case 3:\r\n                    return \">\";\r\n                default:\r\n                    return \"<=\";\r\n            }\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            switch (m_Var)\r\n            {\r\n                case DoWhileVarType.Hits:\r\n                case DoWhileVarType.Mana:\r\n                case DoWhileVarType.Stamina:\r\n                case DoWhileVarType.Weight:\r\n                    return $\"Do While ( {m_Var} {DirectionString()} {m_Value} )\";\r\n                case DoWhileVarType.Poisoned:\r\n                    return \"Do While ( Poisoned )\";\r\n                case DoWhileVarType.SysMessage:\r\n                {\r\n                    string str = (string) m_Value;\r\n                    if (str.Length > 10)\r\n                        str = str.Substring(0, 7) + \"...\";\r\n                    return $\"Do While ( SysMessage \\\"{str}\\\" )\";\r\n                }\r\n\r\n                case DoWhileVarType.Skill:\r\n                    return $\"Do While ( \\\"{Skills.GetSkillDisplayName(m_SkillId)}\\\" {DirectionString()} {m_Value})\";\r\n                case DoWhileVarType.Mounted:\r\n                    return \"Do While ( Mounted )\";\r\n                case DoWhileVarType.RHandEmpty:\r\n                    return \"Do While ( R-Hand Empty )\";\r\n                case DoWhileVarType.LHandEmpty:\r\n                    return \"Do While ( L-Hand Empty )\";\r\n                case DoWhileVarType.Counter:\r\n                    return $\"Do While ( \\\"{m_Counter} count\\\" {DirectionString()} {m_Value} )\";\r\n                default:\r\n                    return \"Do While ( ??? )\";\r\n            }\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit))\r\n                };\r\n            }\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertDoWhile(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n    }\r\n\r\n    public class ContextMenuAction : MacroAction\r\n    {\r\n        private ushort m_CtxName;\r\n        private ushort m_Idx;\r\n        private Serial m_Entity;\r\n\r\n        public ContextMenuAction(UOEntity ent, ushort idx, ushort ctxName)\r\n        {\r\n            m_Entity = ent != null ? ent.Serial : Serial.MinusOne;\r\n\r\n            if (World.Player != null && World.Player.Serial == m_Entity)\r\n                m_Entity = Serial.Zero;\r\n\r\n            m_Idx = idx;\r\n            m_CtxName = ctxName;\r\n        }\r\n\r\n        public ContextMenuAction(string[] args)\r\n        {\r\n            m_Entity = Serial.Parse(args[1]);\r\n            m_Idx = Convert.ToUInt16(args[2]);\r\n            try\r\n            {\r\n                m_CtxName = Convert.ToUInt16(args[3]);\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            Serial s = m_Entity;\r\n\r\n            if (s == Serial.Zero && World.Player != null)\r\n                s = World.Player.Serial;\r\n\r\n            Client.Instance.SendToServer(new ContextMenuRequest(s));\r\n            Client.Instance.SendToServer(new ContextMenuResponse(s, m_Idx));\r\n            return true;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"menu {m_Entity} {m_Idx}\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Entity, m_Idx, m_CtxName);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            string ent;\r\n\r\n            if (m_Entity == Serial.Zero)\r\n                ent = \"(self)\";\r\n            else\r\n                ent = m_Entity.ToString();\r\n            return String.Format(\"ContextMenu: {1} ({0})\", ent, m_Idx);\r\n        }\r\n    }\r\n\r\n    public class PromptAction : MacroAction\r\n    {\r\n        private string m_Response;\r\n\r\n        public PromptAction(string[] args)\r\n        {\r\n            m_Response = args[1];\r\n        }\r\n\r\n        public PromptAction(string response)\r\n        {\r\n            m_Response = response;\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            if (m_Response.Length > 1)\r\n            {\r\n                World.Player.ResponsePrompt(m_Response);\r\n\r\n                return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return $\"promptresponse '{m_Response}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_Response);\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            return $\"PromptAction: {m_Response}\";\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (this.m_MenuItems == null)\r\n                this.m_MenuItems = (ToolStripMenuItem[]) new MacroMenuItem[1]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(this.Edit), new object[0])\r\n                };\r\n            return this.m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            if (InputBox.Show(Language.GetString(LocString.EnterNewText), \"Input Box\", this.m_Response))\r\n                m_Response = InputBox.GetString();\r\n\r\n            Parent?.Update();\r\n        }\r\n    }\r\n\r\n    public class WaitForPromptAction : MacroWaitAction\r\n    {\r\n        private uint m_PromptID;\r\n        private bool m_Strict;\r\n\r\n        public WaitForPromptAction()\r\n        {\r\n            m_PromptID = 0;\r\n            m_Strict = false;\r\n        }\r\n\r\n        public WaitForPromptAction(uint gid)\r\n        {\r\n            m_PromptID = gid;\r\n            m_Strict = false;\r\n        }\r\n\r\n        public WaitForPromptAction(string[] args)\r\n        {\r\n            m_PromptID = Convert.ToUInt32(args[1]);\r\n            try\r\n            {\r\n                m_Strict = Convert.ToBoolean(args[2]);\r\n            }\r\n            catch\r\n            {\r\n                m_Strict = false;\r\n            }\r\n\r\n            try\r\n            {\r\n                m_Timeout = TimeSpan.FromSeconds(Convert.ToDouble(args[3]));\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public override bool Perform()\r\n        {\r\n            return !PerformWait();\r\n        }\r\n\r\n        public override bool PerformWait()\r\n        {\r\n            return !(World.Player.HasPrompt && (World.Player.PromptID == m_PromptID || !m_Strict || m_PromptID == 0));\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            //if (m_PromptID == 0 || !m_Strict)\r\n            //    return Language.GetString(LocString.WaitAnyGump);\r\n            //else\r\n            //    return Language.Format(LocString.WaitGumpA1, m_GumpID);\r\n\r\n            if (m_PromptID == 0 || !m_Strict)\r\n                return \"Wait For Prompt (Any)\";\r\n\r\n            return $\"Wait For Prompt ({m_PromptID})\";\r\n        }\r\n\r\n        public override string ToScript()\r\n        {\r\n            return m_PromptID == 0 || !m_Strict ? \"waitforprompt\" : $\"waitforprompt '{m_PromptID}'\";\r\n        }\r\n\r\n        public override string Serialize()\r\n        {\r\n            return DoSerialize(m_PromptID, m_Strict, m_Timeout.TotalSeconds);\r\n        }\r\n\r\n        public override bool CheckMatch(MacroAction a)\r\n        {\r\n            if (a is WaitForGumpAction)\r\n            {\r\n                if (m_PromptID == 0 || ((WaitForPromptAction) a).m_PromptID == m_PromptID)\r\n                    return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        private ToolStripMenuItem[] m_MenuItems;\r\n\r\n        public override ToolStripMenuItem[] GetContextMenuItems()\r\n        {\r\n            if (m_MenuItems == null)\r\n            {\r\n                m_MenuItems = new MacroMenuItem[]\r\n                {\r\n                    new MacroMenuItem(LocString.Edit, new MacroMenuCallback(Edit)),\r\n                    new MacroMenuItem(LocString.Null, new MacroMenuCallback(ToggleStrict)),\r\n                    this.EditTimeoutMenuItem\r\n                };\r\n            }\r\n\r\n            if (!m_Strict)\r\n                m_MenuItems[1].Text = $\"Change to \\\"Wait For Prompt ({m_PromptID})\\\"\";\r\n            else\r\n                m_MenuItems[1].Text = $\"Change to \\\"Wait For Prompt (Any)\\\"\";\r\n\r\n            m_MenuItems[1].Enabled = m_PromptID != 0 || m_Strict;\r\n\r\n            return m_MenuItems;\r\n        }\r\n\r\n        private void Edit(object[] args)\r\n        {\r\n            new MacroInsertWait(this).ShowDialog(Engine.MainWindow);\r\n        }\r\n\r\n        private void ToggleStrict(object[] args)\r\n        {\r\n            m_Strict = !m_Strict;\r\n            if (m_Parent != null)\r\n                m_Parent.Update();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Macros/Actions.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n<root>\r\n\t<xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n\t\t<xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n\t\t\t<xsd:complexType>\r\n\t\t\t\t<xsd:choice maxOccurs=\"unbounded\">\r\n\t\t\t\t\t<xsd:element name=\"data\">\r\n\t\t\t\t\t\t<xsd:complexType>\r\n\t\t\t\t\t\t\t<xsd:sequence>\r\n\t\t\t\t\t\t\t\t<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n\t\t\t\t\t\t\t\t<xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n\t\t\t\t\t\t\t</xsd:sequence>\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n\t\t\t\t\t\t</xsd:complexType>\r\n\t\t\t\t\t</xsd:element>\r\n\t\t\t\t\t<xsd:element name=\"resheader\">\r\n\t\t\t\t\t\t<xsd:complexType>\r\n\t\t\t\t\t\t\t<xsd:sequence>\r\n\t\t\t\t\t\t\t\t<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n\t\t\t\t\t\t\t</xsd:sequence>\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n\t\t\t\t\t\t</xsd:complexType>\r\n\t\t\t\t\t</xsd:element>\r\n\t\t\t\t</xsd:choice>\r\n\t\t\t</xsd:complexType>\r\n\t\t</xsd:element>\r\n\t</xsd:schema>\r\n\t<resheader name=\"ResMimeType\">\r\n\t\t<value>text/microsoft-resx</value>\r\n\t</resheader>\r\n\t<resheader name=\"Version\">\r\n\t\t<value>1.0.0.0</value>\r\n\t</resheader>\r\n\t<resheader name=\"Reader\">\r\n\t\t<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n\t</resheader>\r\n\t<resheader name=\"Writer\">\r\n\t\t<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n\t</resheader>\r\n</root>\r\n"
  },
  {
    "path": "Razor/Macros/Macro.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections;\r\nusing System.Windows.Forms;\r\nusing System.Reflection;\r\nusing System.IO;\r\nusing System.Text;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant.Macros\r\n{\r\n    public class Macro\r\n    {\r\n        private string m_Path;\r\n        private ArrayList m_Actions;\r\n        private bool m_Recording, m_Playing;\r\n        private MacroWaitAction m_Wait;\r\n        private int m_CurrentAction;\r\n        private bool m_Loop;\r\n        private bool m_Loaded;\r\n        private ListBox m_ListBox;\r\n        private Stack m_IfStatus;\r\n\r\n        public Macro(string path)\r\n        {\r\n            m_Actions = new ArrayList();\r\n            m_Path = path;\r\n            m_Loaded = false;\r\n            m_IfStatus = new Stack();\r\n        }\r\n\r\n        public string GetName()\r\n        {\r\n            return Path.GetFileNameWithoutExtension(m_Path);\r\n        }\r\n\r\n        public string Filename\r\n        {\r\n            get { return m_Path; }\r\n            set { m_Path = value; }\r\n        }\r\n\r\n        public ArrayList Actions\r\n        {\r\n            get { return m_Actions; }\r\n        }\r\n\r\n        public bool Recording\r\n        {\r\n            get { return m_Recording; }\r\n        }\r\n\r\n        public bool Playing\r\n        {\r\n            get { return m_Playing; }\r\n        }\r\n\r\n        public bool StepThrough { get; set; }\r\n\r\n        public bool Waiting\r\n        {\r\n            get { return m_Wait != null; }\r\n        }\r\n\r\n        public int CurrentAction\r\n        {\r\n            get { return m_CurrentAction; }\r\n        }\r\n\r\n        public bool Loop\r\n        {\r\n            get { return m_Loop && Client.Instance.AllowBit(FeatureBit.LoopingMacros); }\r\n            set { m_Loop = value; }\r\n        }\r\n\r\n        public void DisplayTo(ListBox list)\r\n        {\r\n            m_ListBox = list;\r\n\r\n            m_ListBox.SafeAction(s => s.Items.Clear());\r\n\r\n            if (!m_Loaded)\r\n                Load();\r\n\r\n            m_ListBox.SafeAction(s =>\r\n            {\r\n                s.BeginUpdate();\r\n                if (m_Actions.Count > 0)\r\n                    s.Items.AddRange((object[]) m_Actions.ToArray(typeof(object)));\r\n                if (m_Playing && m_CurrentAction >= 0 && m_CurrentAction < m_Actions.Count)\r\n                    s.SelectedIndex = m_CurrentAction;\r\n                else\r\n                    s.SelectedIndex = -1;\r\n                s.EndUpdate();\r\n            });\r\n        }\r\n\r\n        public override string ToString()\r\n        {\r\n            //return Path.GetFileNameWithoutExtension( m_Path );\r\n            StringBuilder sb = new StringBuilder(Path.GetFullPath(m_Path));\r\n            sb.Remove(sb.Length - 6, 6);\r\n            sb.Remove(0, Config.GetUserDirectory(\"Macros\").Length + 1);\r\n            return sb.ToString();\r\n        }\r\n\r\n        public void Insert(int idx, MacroAction a)\r\n        {\r\n            a.Parent = this;\r\n            if (idx < 0 || idx > m_Actions.Count)\r\n                idx = m_Actions.Count;\r\n            m_Actions.Insert(idx, a);\r\n        }\r\n\r\n        public void Record()\r\n        {\r\n            m_Actions.Clear();\r\n            if (m_ListBox != null)\r\n                m_ListBox.SafeAction(s => s.Items.Clear());\r\n            RecordAt(0);\r\n        }\r\n\r\n        public void RecordAt(int at)\r\n        {\r\n            Stop();\r\n            m_Recording = true;\r\n            m_Loaded = true;\r\n            m_CurrentAction = at;\r\n            if (m_CurrentAction > m_Actions.Count)\r\n                m_CurrentAction = m_Actions.Count;\r\n        }\r\n\r\n        public void Play()\r\n        {\r\n            Stop();\r\n            if (!m_Loaded)\r\n                Load();\r\n            else\r\n                Save();\r\n\r\n            if (m_Actions.Count > 0)\r\n            {\r\n                m_IfStatus.Clear();\r\n                m_Playing = true;\r\n                m_CurrentAction = -1;\r\n                if (m_ListBox != null)\r\n                    m_ListBox.SafeAction(s => s.SelectedIndex = -1);\r\n            }\r\n        }\r\n\r\n        public void PlayAt(int at)\r\n        {\r\n            Stop();\r\n            if (!m_Loaded)\r\n                Load();\r\n            else\r\n                Save();\r\n\r\n            if (m_Actions.Count > 0)\r\n            {\r\n                m_IfStatus.Clear();\r\n                m_Playing = true;\r\n                m_CurrentAction = at - 1;\r\n                if (m_CurrentAction >= 0)\r\n                    m_CurrentAction--;\r\n            }\r\n        }\r\n\r\n        public void Reset()\r\n        {\r\n            if (m_Playing && World.Player != null && DragDropManager.Holding != null &&\r\n                DragDropManager.Holding == LiftAction.LastLift)\r\n                Client.Instance.SendToServer(new DropRequest(DragDropManager.Holding, World.Player.Serial));\r\n\r\n            m_Wait = null;\r\n\r\n            m_IfStatus.Clear();\r\n\r\n            foreach (MacroAction a in m_Actions)\r\n            {\r\n                if (a is ForAction)\r\n                    ((ForAction) a).Count = 0;\r\n            }\r\n        }\r\n\r\n        public void Stop()\r\n        {\r\n            if (m_Recording)\r\n                Save();\r\n\r\n            m_Recording = m_Playing = false;\r\n            Reset();\r\n        }\r\n\r\n        // returns true if the were waiting for this action\r\n        public bool Action(MacroAction action)\r\n        {\r\n            if (m_Recording)\r\n            {\r\n                action.Parent = this;\r\n                m_Actions.Insert(m_CurrentAction, action);\r\n                if (m_ListBox != null)\r\n                    m_ListBox.SafeAction(s => s.Items.Insert(m_CurrentAction, action));\r\n                m_CurrentAction++;\r\n\r\n                return false;\r\n            }\r\n            else if (m_Playing && m_Wait != null && m_Wait.CheckMatch(action))\r\n            {\r\n                m_Wait = null;\r\n                ExecNext();\r\n                return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        public void Save()\r\n        {\r\n            if (m_Actions.Count == 0)\r\n                return;\r\n\r\n            using (StreamWriter writer = new StreamWriter(m_Path))\r\n            {\r\n                if (m_Loop)\r\n                    writer.WriteLine(\"!Loop\");\r\n\r\n                for (int i = 0; i < m_Actions.Count; i++)\r\n                {\r\n                    MacroAction a = (MacroAction) m_Actions[i];\r\n                    try\r\n                    {\r\n                        writer.WriteLine(a.Serialize());\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static Type[] ctorArgs = new Type[1] {typeof(string[])};\r\n\r\n        public void Load()\r\n        {\r\n            m_Actions.Clear();\r\n            m_Loaded = false;\r\n\r\n            if (!File.Exists(m_Path))\r\n                return;\r\n\r\n            using (StreamReader reader = new StreamReader(m_Path))\r\n            {\r\n                string line;\r\n                while ((line = reader.ReadLine()) != null)\r\n                {\r\n                    if (line.Length <= 2)\r\n                        continue;\r\n\r\n                    if (line == \"!Loop\")\r\n                    {\r\n                        m_Loop = true;\r\n                        continue;\r\n                    }\r\n\r\n                    if (line[0] == '#')\r\n                    {\r\n                        m_Actions.Add(new MacroComment(line.Substring(1)));\r\n                        continue;\r\n                    }\r\n                    else if (line[0] == '/' && line[1] == '/')\r\n                    {\r\n                        MacroAction a = new MacroComment(line.Substring(2));\r\n                        a.Parent = this;\r\n                        m_Actions.Add(a);\r\n                        continue;\r\n                    }\r\n\r\n                    string[] args = line.Split('|');\r\n                    object[] invokeArgs = new object[1] {args};\r\n\r\n                    Type at = null;\r\n                    try\r\n                    {\r\n                        at = Type.GetType(args[0], false);\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n\r\n                    if (at == null)\r\n                        continue;\r\n\r\n                    if (args.Length > 1)\r\n                    {\r\n                        try\r\n                        {\r\n                            ConstructorInfo ctor = at.GetConstructor(ctorArgs);\r\n                            if (ctor == null)\r\n                                continue;\r\n\r\n                            MacroAction a = (MacroAction) ctor.Invoke(invokeArgs);\r\n                            a.Parent = this;\r\n                            m_Actions.Add(a);\r\n                        }\r\n                        catch\r\n                        {\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        try\r\n                        {\r\n                            ConstructorInfo ctor = at.GetConstructor(Type.EmptyTypes);\r\n                            if (ctor == null)\r\n                                continue;\r\n\r\n                            MacroAction a = (MacroAction) ctor.Invoke(null);\r\n                            a.Parent = this;\r\n                            m_Actions.Add(a);\r\n                        }\r\n                        catch\r\n                        {\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            m_Loaded = true;\r\n        }\r\n\r\n        public void Convert(MacroAction old, MacroAction newAct)\r\n        {\r\n            for (int i = 0; i < m_Actions.Count; i++)\r\n            {\r\n                if (m_Actions[i] == old)\r\n                {\r\n                    m_Actions[i] = newAct;\r\n                    newAct.Parent = this;\r\n                    Update();\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        public void Update()\r\n        {\r\n            if (m_ListBox != null)\r\n            {\r\n                int sel = m_ListBox.SelectedIndex;\r\n                DisplayTo(m_ListBox);\r\n                try\r\n                {\r\n                    m_ListBox.SafeAction(s => s.SelectedIndex = sel);\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        private bool NextIsInstantWait()\r\n        {\r\n            int nextAct = m_CurrentAction + 1;\r\n\r\n            if (nextAct >= 0 && nextAct < m_Actions.Count)\r\n                return m_Actions[nextAct] is WaitForTargetAction || m_Actions[nextAct] is WaitForGumpAction ||\r\n                       m_Actions[nextAct] is\r\n                           WaitForMenuAction; //|| m_Actions[nextAct] is ElseAction || m_Actions[nextAct] is EndIfAction;\r\n            else\r\n                return false;\r\n        }\r\n\r\n        private static MacroWaitAction PauseB4Loop = new PauseAction(TimeSpan.FromSeconds(0.1));\r\n\r\n        //return true to continue the macro, false to stop (macro's over)\r\n        public bool ExecNext()\r\n        {\r\n            try\r\n            {\r\n                if (!m_Playing)\r\n                    return false;\r\n\r\n                if (m_Wait != null)\r\n                {\r\n                    TimeSpan waitLen = DateTime.UtcNow - m_Wait.StartTime;\r\n                    if (!(m_Wait is PauseAction) && waitLen >= m_Wait.Timeout)\r\n                    {\r\n                        if (Loop)\r\n                        {\r\n                            if (Engine.MainWindow.WaitDisplay != null)\r\n                                Engine.MainWindow.WaitDisplay.SafeAction(s => s.Text = string.Empty);\r\n                            m_CurrentAction = -1;\r\n                            m_IfStatus.Clear();\r\n                            PauseB4Loop.Perform();\r\n                            PauseB4Loop.Parent = this;\r\n                            m_Wait = PauseB4Loop;\r\n                            return true;\r\n                        }\r\n                        else\r\n                        {\r\n                            Stop();\r\n                            return false;\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        if (!m_Wait.PerformWait())\r\n                        {\r\n                            m_Wait = null; // done waiting\r\n                            if (Engine.MainWindow.WaitDisplay != null)\r\n                                Engine.MainWindow.WaitDisplay.SafeAction(s => s.Text = string.Empty);\r\n                        }\r\n                        else\r\n                        {\r\n                            if (waitLen >= TimeSpan.FromSeconds(4.0) && Engine.MainWindow.WaitDisplay != null)\r\n                            {\r\n                                StringBuilder sb = new StringBuilder(Language.GetString(LocString.WaitingTimeout));\r\n\r\n                                sb.AppendLine(\"\\n\");\r\n\r\n                                int s = (int) (m_Wait.Timeout - waitLen).TotalSeconds;\r\n                                int m = 0;\r\n\r\n                                if (s > 60)\r\n                                {\r\n                                    m = s / 60;\r\n                                    s %= 60;\r\n                                    if (m > 60)\r\n                                    {\r\n                                        sb.AppendFormat(\"{0}:\", m / 60);\r\n                                        m %= 60;\r\n                                    }\r\n                                }\r\n\r\n                                sb.AppendFormat(\"{0:00}:{1:00}\", m, s);\r\n\r\n                                Engine.MainWindow.WaitDisplay.SafeAction(w => w.Text = sb.ToString());\r\n                            }\r\n\r\n                            return true; // keep waiting\r\n                        }\r\n                    }\r\n                }\r\n\r\n                m_CurrentAction++;\r\n                //MacroManager.ActionUpdate( this, m_CurrentAction );\r\n                if (m_ListBox != null)\r\n                {\r\n                    if (m_CurrentAction < m_ListBox.Items.Count)\r\n                        m_ListBox.SafeAction(s => s.SelectedIndex = m_CurrentAction);\r\n                    else\r\n                        m_ListBox.SafeAction(s => s.SelectedIndex = -1);\r\n                }\r\n\r\n                if (m_CurrentAction >= 0 && m_CurrentAction < m_Actions.Count)\r\n                {\r\n                    MacroAction action = (MacroAction) m_Actions[m_CurrentAction];\r\n\r\n                    if (action is IfAction)\r\n                    {\r\n                        bool val = ((IfAction) action).Evaluate();\r\n                        m_IfStatus.Push(val);\r\n\r\n                        if (!val)\r\n                        {\r\n                            // false so skip to an else or an endif\r\n                            int ifcount = 0;\r\n                            while (m_CurrentAction + 1 < m_Actions.Count)\r\n                            {\r\n                                if (m_Actions[m_CurrentAction + 1] is IfAction)\r\n                                {\r\n                                    ifcount++;\r\n                                }\r\n                                else if (m_Actions[m_CurrentAction + 1] is ElseAction && ifcount <= 0)\r\n                                {\r\n                                    break;\r\n                                }\r\n                                else if (m_Actions[m_CurrentAction + 1] is EndIfAction)\r\n                                {\r\n                                    if (ifcount <= 0)\r\n                                        break;\r\n                                    else\r\n                                        ifcount--;\r\n                                }\r\n\r\n                                m_CurrentAction++;\r\n                            }\r\n                        }\r\n                    }\r\n                    else if (action is ElseAction && m_IfStatus.Count > 0)\r\n                    {\r\n                        bool val = (bool) m_IfStatus.Peek();\r\n                        if (val)\r\n                        {\r\n                            // the if was true, so skip to an endif\r\n                            int ifcount = 0;\r\n                            while (m_CurrentAction + 1 < m_Actions.Count)\r\n                            {\r\n                                if (m_Actions[m_CurrentAction + 1] is IfAction)\r\n                                {\r\n                                    ifcount++;\r\n                                }\r\n                                else if (m_Actions[m_CurrentAction + 1] is EndIfAction)\r\n                                {\r\n                                    if (ifcount <= 0)\r\n                                        break;\r\n                                    else\r\n                                        ifcount--;\r\n                                }\r\n\r\n                                m_CurrentAction++;\r\n                            }\r\n                        }\r\n                    }\r\n                    else if (action is EndIfAction && m_IfStatus.Count > 0)\r\n                    {\r\n                        m_IfStatus.Pop();\r\n                    }\r\n                    else if (action is ForAction)\r\n                    {\r\n                        ForAction fa = (ForAction) action;\r\n                        fa.Count++;\r\n\r\n                        if (fa.Count > fa.Max)\r\n                        {\r\n                            fa.Count = 0;\r\n\r\n                            int forcount = 0;\r\n                            m_CurrentAction++;\r\n                            while (m_CurrentAction < m_Actions.Count)\r\n                            {\r\n                                if (m_Actions[m_CurrentAction] is ForAction)\r\n                                {\r\n                                    forcount++;\r\n                                }\r\n                                else if (m_Actions[m_CurrentAction] is EndForAction)\r\n                                {\r\n                                    if (forcount <= 0)\r\n                                        break;\r\n                                    else\r\n                                        forcount--;\r\n                                }\r\n\r\n                                m_CurrentAction++;\r\n                            }\r\n\r\n                            if (m_CurrentAction < m_Actions.Count)\r\n                                action = (MacroAction) m_Actions[m_CurrentAction];\r\n                        }\r\n                    }\r\n                    else if (action is EndForAction && Client.Instance.AllowBit(FeatureBit.LoopingMacros))\r\n                    {\r\n                        int ca = m_CurrentAction - 1;\r\n                        int forcount = 0;\r\n\r\n                        while (ca >= 0)\r\n                        {\r\n                            if (m_Actions[ca] is EndForAction)\r\n                            {\r\n                                forcount--;\r\n                            }\r\n                            else if (m_Actions[ca] is ForAction)\r\n                            {\r\n                                if (forcount >= 0)\r\n                                    break;\r\n                                else\r\n                                    forcount++;\r\n                            }\r\n\r\n                            ca--;\r\n                        }\r\n\r\n                        if (ca >= 0 && m_Actions[ca] is ForAction)\r\n                            m_CurrentAction = ca - 1;\r\n                    }\r\n                    else if (action is WhileAction && Client.Instance.AllowBit(FeatureBit.LoopingMacros))\r\n                    {\r\n                        bool val = ((WhileAction) action).Evaluate();\r\n\r\n                        if (!val)\r\n                        {\r\n                            // false so skip to the endwhile\r\n                            int whilecount = 0;\r\n                            while (m_CurrentAction + 1 < m_Actions.Count)\r\n                            {\r\n                                if (m_Actions[m_CurrentAction + 1] is WhileAction)\r\n                                {\r\n                                    whilecount++;\r\n                                }\r\n                                else if (m_Actions[m_CurrentAction + 1] is EndWhileAction)\r\n                                {\r\n                                    if (whilecount <= 0)\r\n                                    {\r\n                                        // Skip over the end while\r\n                                        m_CurrentAction++;\r\n                                        break;\r\n                                    }\r\n\r\n                                    whilecount--;\r\n                                }\r\n\r\n                                m_CurrentAction++;\r\n                            }\r\n                        }\r\n                    }\r\n                    else if (action is EndWhileAction && Client.Instance.AllowBit(FeatureBit.LoopingMacros))\r\n                    {\r\n                        int ca = m_CurrentAction - 1;\r\n                        int whilecount = 0;\r\n\r\n                        while (ca >= 0)\r\n                        {\r\n                            if (m_Actions[ca] is EndWhileAction)\r\n                            {\r\n                                whilecount--;\r\n                            }\r\n                            else if (m_Actions[ca] is WhileAction)\r\n                            {\r\n                                if (whilecount >= 0)\r\n                                    break;\r\n                                else\r\n                                    whilecount++;\r\n                            }\r\n\r\n                            ca--;\r\n                        }\r\n\r\n                        if (ca >= 0 && m_Actions[ca] is WhileAction)\r\n                            m_CurrentAction = ca - 1;\r\n                    }\r\n                    else if (action is DoWhileAction && Client.Instance.AllowBit(FeatureBit.LoopingMacros))\r\n                    {\r\n                        bool val = ((DoWhileAction) action).Evaluate();\r\n\r\n                        if (val)\r\n                        {\r\n                            int ca = m_CurrentAction - 1;\r\n                            int dowhilecount = 0;\r\n\r\n                            while (ca >= 0)\r\n                            {\r\n                                if (m_Actions[ca] is DoWhileAction)\r\n                                {\r\n                                    dowhilecount--;\r\n                                }\r\n                                else if (m_Actions[ca] is StartDoWhileAction)\r\n                                {\r\n                                    if (dowhilecount >= 0)\r\n                                        break;\r\n                                    else\r\n                                        dowhilecount++;\r\n                                }\r\n\r\n                                ca--;\r\n                            }\r\n\r\n                            if (ca >= 0 && m_Actions[ca] is StartDoWhileAction)\r\n                                m_CurrentAction = ca - 1;\r\n                        }\r\n                    }\r\n\r\n                    bool isWait = action is MacroWaitAction;\r\n                    if (!action.Perform() && isWait)\r\n                    {\r\n                        m_Wait = (MacroWaitAction) action;\r\n                        m_Wait.StartTime = DateTime.UtcNow;\r\n                    }\r\n                    else if (NextIsInstantWait() && !isWait)\r\n                    {\r\n                        return ExecNext();\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    if (Engine.MainWindow.WaitDisplay != null)\r\n                        Engine.MainWindow.WaitDisplay.SafeAction(s => s.Text = string.Empty);\r\n\r\n                    if (Loop)\r\n                    {\r\n                        m_CurrentAction = -1;\r\n\r\n                        Reset();\r\n\r\n                        PauseB4Loop.Perform();\r\n                        PauseB4Loop.Parent = this;\r\n                        m_Wait = PauseB4Loop;\r\n                    }\r\n                    else\r\n                    {\r\n                        Stop();\r\n                        return false;\r\n                    }\r\n                }\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                new MessageDialog(\"Macro Exception\", true, e.ToString()).Show();\r\n                return false;\r\n            }\r\n\r\n            return true;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Macros/MacroManager.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Windows.Forms;\r\nusing Assistant.Scripts;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant.Macros\r\n{\r\n    public class MacroManager\r\n    {\r\n        private static List<Macro> m_MacroList;\r\n        private static Macro m_Current, m_PrevPlay;\r\n        private static bool m_Paused;\r\n        private static MacroTimer m_Timer;\r\n\r\n        public static void Initialize()\r\n        {\r\n            HotKey.Add(HKCategory.Macros, LocString.StopCurrent, new HotKeyCallback(HotKeyStop));\r\n            HotKey.Add(HKCategory.Macros, LocString.PauseCurrent, new HotKeyCallback(HotKeyPause));\r\n\r\n            string path = Config.GetUserDirectory(\"Macros\");\r\n            Recurse(null, path);\r\n        }\r\n\r\n        static MacroManager()\r\n        {\r\n            m_MacroList = new List<Macro>();\r\n            m_Timer = new MacroTimer();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Saves all the macros and variable lists\r\n        /// </summary>\r\n        public static void Save()\r\n        {\r\n            Engine.EnsureDirectory(Config.GetUserDirectory(\"Macros\"));\r\n\r\n            foreach (Macro macro in m_MacroList)\r\n            {\r\n                macro.Save();\r\n            }\r\n        }\r\n\r\n        public static List<Macro> List\r\n        {\r\n            get { return m_MacroList; }\r\n        }\r\n\r\n        public static bool Recording\r\n        {\r\n            get { return m_Current != null && m_Current.Recording; }\r\n        }\r\n\r\n        public static bool Playing\r\n        {\r\n            get { return m_Current != null && m_Current.Playing && m_Timer != null && m_Timer.Running; }\r\n        }\r\n\r\n        public static bool StepThrough\r\n        {\r\n            get { return m_Current != null && m_Current.StepThrough && m_Current.Playing; }\r\n        }\r\n\r\n        public static Macro Current\r\n        {\r\n            get { return m_Current; }\r\n        }\r\n\r\n        public static bool AcceptActions\r\n        {\r\n            get { return Recording || (Playing && m_Current.Waiting); }\r\n        }\r\n        //public static bool IsWaiting{ get{ return Playing && m_Current != null && m_Current.Waiting; } }\r\n\r\n        public static void Add(Macro m)\r\n        {\r\n            HotKey.Add(HKCategory.Macros, HKSubCat.None, Language.Format(LocString.PlayA1, m),\r\n                new HotKeyCallbackState(HotKeyPlay), m);\r\n            m_MacroList.Add(m);\r\n        }\r\n\r\n        public static void Remove(Macro m)\r\n        {\r\n            HotKey.Remove(Language.Format(LocString.PlayA1, m));\r\n            m_MacroList.Remove(m);\r\n        }\r\n\r\n        public static void RecordAt(Macro m, int at)\r\n        {\r\n            if (m_Current != null)\r\n                m_Current.Stop();\r\n            m_Current = m;\r\n            m_Current.RecordAt(at);\r\n        }\r\n\r\n        public static void Record(Macro m)\r\n        {\r\n            if (m_Current != null)\r\n                m_Current.Stop();\r\n            m_Current = m;\r\n            m_Current.Record();\r\n        }\r\n\r\n        public static void PlayAt(Macro m, int at)\r\n        {\r\n            ScriptManager.StopScript();\r\n\r\n            if (m_Current != null)\r\n            {\r\n                if (m_Current.Playing && m_Current.Loop && !m.Loop)\r\n                    m_PrevPlay = m_Current;\r\n                else\r\n                    m_PrevPlay = null;\r\n\r\n                m_Current.Stop();\r\n            }\r\n            else\r\n            {\r\n                m_PrevPlay = null;\r\n            }\r\n\r\n            LiftAction.LastLift = null;\r\n            m_Current = m;\r\n            m_Current.PlayAt(at);\r\n\r\n            m_Timer.Macro = m_Current;\r\n\r\n            if (!Config.GetBool(\"StepThroughMacro\"))\r\n            {\r\n                m_Timer.Start();\r\n            }\r\n\r\n            if (Engine.MainWindow.WaitDisplay != null)\r\n                Engine.MainWindow.SafeAction(s => s.WaitDisplay.Text = \"\");\r\n        }\r\n\r\n        private static void HotKeyPlay(ref object state)\r\n        {\r\n            HotKeyPlay(state as Macro);\r\n        }\r\n\r\n        public static void HotKeyPlay(Macro m)\r\n        {\r\n            if (m != null)\r\n            {\r\n                Play(m);\r\n\r\n                if (!Config.GetBool(\"DisableMacroPlayFinish\"))\r\n                    World.Player.SendMessage(LocString.PlayingA1, m);\r\n\r\n                Engine.MainWindow.SafeAction(s => s.PlayMacro(m));\r\n            }\r\n        }\r\n\r\n        public static void Play(Macro m)\r\n        {\r\n            ScriptManager.StopScript();\r\n\r\n            if (m_Current != null)\r\n            {\r\n                if (m_Current.Playing && m_Current.Loop && !m.Loop)\r\n                    m_PrevPlay = m_Current;\r\n                else\r\n                    m_PrevPlay = null;\r\n\r\n                m_Current.Stop();\r\n            }\r\n            else\r\n            {\r\n                m_PrevPlay = null;\r\n            }\r\n\r\n            LiftAction.LastLift = null;\r\n            m_Current = m;\r\n            m_Current.Play();\r\n\r\n            m_Timer.Macro = m_Current;\r\n\r\n            if (!Config.GetBool(\"StepThroughMacro\"))\r\n            {\r\n                m_Timer.Start();\r\n            }\r\n\r\n            if (Engine.MainWindow.WaitDisplay != null)\r\n                Engine.MainWindow.SafeAction(s => s.WaitDisplay.Text = \"\");\r\n        }\r\n\r\n        public static void PlayNext()\r\n        {\r\n            if (m_Current == null)\r\n                return;\r\n\r\n            m_Timer.PerformNextAction();\r\n        }\r\n\r\n        private static void HotKeyPause()\r\n        {\r\n            Pause();\r\n        }\r\n\r\n        private static void HotKeyStop()\r\n        {\r\n            Stop();\r\n        }\r\n\r\n        public static void Stop()\r\n        {\r\n            Stop(false);\r\n        }\r\n\r\n        public static void Stop(bool restartPrev)\r\n        {\r\n            m_Timer.Stop();\r\n            if (m_Current != null)\r\n            {\r\n                m_Current.Stop();\r\n                m_Current = null;\r\n            }\r\n\r\n            UOAssist.PostMacroStop();\r\n\r\n            if (Engine.MainWindow.WaitDisplay != null)\r\n                Engine.MainWindow.SafeAction(s => s.WaitDisplay.Text = \"\");\r\n\r\n            Engine.MainWindow.SafeAction(s => s.OnMacroStop());\r\n\r\n            //if ( restartPrev )\r\n            //\tPlay( m_PrevPlay );\r\n            m_PrevPlay = null;\r\n        }\r\n\r\n        public static void Pause()\r\n        {\r\n            if (m_Current == null)\r\n                return;\r\n\r\n            if (m_Paused)\r\n            {\r\n                // unpause\r\n                int sel = m_Current.CurrentAction;\r\n                if (sel < 0 || sel > m_Current.Actions.Count)\r\n                    sel = m_Current.Actions.Count;\r\n\r\n                //m_Current.PlayAt(sel);\r\n                m_Timer.Start();\r\n\r\n                m_Paused = false;\r\n\r\n                World.Player.SendMessage(LocString.MacroResuming);\r\n            }\r\n            else\r\n            {\r\n                // pause\r\n                m_Timer.Stop();\r\n\r\n                if (Engine.MainWindow.WaitDisplay != null)\r\n                    Engine.MainWindow.SafeAction(s => s.WaitDisplay.Text = \"Paused\");\r\n\r\n                World.Player.SendMessage(LocString.MacroPaused);\r\n\r\n                m_Paused = true;\r\n            }\r\n        }\r\n\r\n        public static void DisplayTo(TreeView tree)\r\n        {\r\n            tree.BeginUpdate();\r\n            tree.Nodes.Clear();\r\n            Recurse(tree.Nodes, Config.GetUserDirectory(\"Macros\"));\r\n            tree.EndUpdate();\r\n            tree.Refresh();\r\n            tree.Update();\r\n        }\r\n\r\n        public static void DisplayMacroVariables(ListBox list)\r\n        {\r\n            list.BeginUpdate();\r\n            list.Items.Clear();\r\n\r\n            foreach (MacroVariables.MacroVariable at in MacroVariables.MacroVariableList)\r\n            {\r\n                list.Items.Add($\"${at.Name} ({at.TargetInfo.Serial})\");\r\n            }\r\n\r\n            list.EndUpdate();\r\n            list.Refresh();\r\n            list.Update();\r\n        }\r\n\r\n        private static void Recurse(TreeNodeCollection nodes, string path)\r\n        {\r\n            try\r\n            {\r\n                string[] macros = Directory.GetFiles(path, \"*.macro\");\r\n                for (int i = 0; i < macros.Length; i++)\r\n                {\r\n                    Macro m = null;\r\n                    for (int j = 0; j < m_MacroList.Count; j++)\r\n                    {\r\n                        Macro check = m_MacroList[j];\r\n\r\n                        if (check.Filename == macros[i])\r\n                        {\r\n                            m = check;\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    if (m == null)\r\n                        Add(m = new Macro(macros[i]));\r\n\r\n                    if (nodes != null)\r\n                    {\r\n                        TreeNode node = new TreeNode(Path.GetFileNameWithoutExtension(m.Filename));\r\n                        node.Tag = m;\r\n                        nodes.Add(node);\r\n                    }\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            try\r\n            {\r\n                string[] dirs = Directory.GetDirectories(path);\r\n                for (int i = 0; i < dirs.Length; i++)\r\n                {\r\n                    if (dirs[i] != \"\" && dirs[i] != \".\" && dirs[i] != \"..\")\r\n                    {\r\n                        if (nodes != null)\r\n                        {\r\n                            TreeNode node = new TreeNode($\"[{Path.GetFileName(dirs[i])}]\");\r\n                            node.Tag = dirs[i];\r\n                            nodes.Add(node);\r\n                            Recurse(node.Nodes, dirs[i]);\r\n                        }\r\n                        else\r\n                        {\r\n                            Recurse(null, dirs[i]);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public static void Select(Macro m, ListBox actionList, Button play, Button rec, CheckBox loop)\r\n        {\r\n            if (m == null)\r\n                return;\r\n\r\n            m.DisplayTo(actionList);\r\n\r\n            if (Recording)\r\n            {\r\n                play.Enabled = false;\r\n                play.Text = \"Play\";\r\n                rec.Enabled = true;\r\n                rec.Text = \"Stop\";\r\n            }\r\n            else\r\n            {\r\n                play.Enabled = true;\r\n                if (m.Playing)\r\n                {\r\n                    play.Text = \"Stop\";\r\n                    rec.Enabled = false;\r\n                }\r\n                else\r\n                {\r\n                    play.Text = \"Play\";\r\n                    rec.Enabled = true;\r\n                }\r\n\r\n                rec.Text = \"Record\";\r\n                loop.Checked = m.Loop;\r\n            }\r\n        }\r\n\r\n        public static bool Action(MacroAction a)\r\n        {\r\n            if (m_Current != null)\r\n                return m_Current.Action(a);\r\n            else\r\n                return false;\r\n        }\r\n\r\n        private class MacroTimer : Timer\r\n        {\r\n            private Macro m_Macro;\r\n\r\n            // The default Razor delay has always been 50ms, but for CUO, that delay isn't needed since it isn't\r\n            // passing messages back and forth.\r\n            public MacroTimer() : base(TimeSpan.FromMilliseconds(Config.GetBool(\"MacroActionDelay\") ? 50 : 0),\r\n                TimeSpan.FromMilliseconds(Config.GetBool(\"MacroActionDelay\") ? 50 : 0))\r\n            {\r\n            }\r\n\r\n            public Macro Macro\r\n            {\r\n                get { return m_Macro; }\r\n                set { m_Macro = value; }\r\n            }\r\n\r\n            public void PerformNextAction()\r\n            {\r\n                ExecuteNextAction();\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                ExecuteNextAction();\r\n            }\r\n\r\n            private void ExecuteNextAction()\r\n            {\r\n                try\r\n                {\r\n                    if (m_Macro == null || World.Player == null)\r\n                    {\r\n                        this.Stop();\r\n                        MacroManager.Stop();\r\n                    }\r\n                    else if (!m_Macro.ExecNext())\r\n                    {\r\n                        this.Stop();\r\n                        MacroManager.Stop(true);\r\n\r\n                        if (!Config.GetBool(\"DisableMacroPlayFinish\"))\r\n                            World.Player.SendMessage(LocString.MacroFinished, m_Macro);\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                    this.Stop();\r\n                    MacroManager.Stop();\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Macros/MacroVariables.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Xml;\n\nnamespace Assistant.Macros\n{\n    public class MacroVariables\n    {\n        public class MacroVariable\n        {\n            public TargetInfo TargetInfo { get; set; }\n            public string Name { get; set; }\n\n            public bool TargetWasSet { get; set; }\n\n            public MacroVariable(string targetVarName, TargetInfo t)\n            {\n                TargetInfo = t;\n                Name = targetVarName;\n                TargetWasSet = true;\n            }\n\n            public void TargetSetMacroVariable()\n            {\n                if (World.Player != null)\n                {\n                    TargetWasSet = false;\n\n                    Targeting.OneTimeTarget(OnMacroVariableTarget);\n                    World.Player.SendMessage(MsgLevel.Force, $\"Select target for ${Name}\");\n\n                    //OneTimeTarget(false, new Targeting.TargetResponseCallback(OnMacroVariableTarget), new Targeting.CancelTargetCallback(OnSLTCancel));\n                }\n            }\n\n            private void OnMacroVariableTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\n            {\n                TargetInfo t = new TargetInfo\n                {\n                    Gfx = gfx,\n                    Serial = serial,\n                    Type = (byte) (ground ? 1 : 0),\n                    X = pt.X,\n                    Y = pt.Y,\n                    Z = pt.Z\n                };\n\n                bool foundVar = false;\n\n                foreach (MacroVariables.MacroVariable mV in MacroVariables.MacroVariableList\n                )\n                {\n                    if (mV.Name.ToLower().Equals(Name.ToLower()))\n                    {\n                        foundVar = true;\n                        // macro exists, update\n                        mV.TargetInfo = t;\n\n                        World.Player.SendMessage(MsgLevel.Force, $\"'{mV.Name}' macro variable updated to '{t.Serial}'\");\n\n                        break;\n                    }\n                }\n\n                if (!foundVar)\n                {\n                    //MacroVariables.MacroVariableList.Add(new MacroVariables.MacroVariable(_lastMacroVariable, t));\n                    //World.Player.SendMessage(MsgLevel.Force, $\"'{_lastMacroVariable}' not found, created variable and set to '{t.Serial}'\");\n                }\n\n                // Save and reload the macros and vars\n                Engine.MainWindow.SaveMacroVariables();\n\n                TargetWasSet = true;\n            }\n\n            /*\n            private void OnSLTCancel()\n            {\n                if (m_LastTarget != null)\n                    m_LTWasSet = true;\n            }*/\n        }\n\n        public static List<MacroVariable> MacroVariableList = new List<MacroVariable>();\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (MacroVariable target in MacroVariableList)\n            {\n                xml.WriteStartElement(\"macrovariable\");\n                xml.WriteAttributeString(\"type\", target.TargetInfo.Type.ToString());\n                xml.WriteAttributeString(\"flags\", target.TargetInfo.Flags.ToString());\n                xml.WriteAttributeString(\"serial\", target.TargetInfo.Serial.ToString());\n                xml.WriteAttributeString(\"x\", target.TargetInfo.X.ToString());\n                xml.WriteAttributeString(\"y\", target.TargetInfo.Y.ToString());\n                xml.WriteAttributeString(\"z\", target.TargetInfo.X.ToString());\n                xml.WriteAttributeString(\"gfx\", target.TargetInfo.Gfx.ToString());\n                xml.WriteAttributeString(\"name\", target.Name);\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"macrovariable\"))\n                {\n                    TargetInfo target = new TargetInfo\n                    {\n                        Type = Convert.ToByte(el.GetAttribute(\"type\")),\n                        Flags = Convert.ToByte(el.GetAttribute(\"flags\")),\n                        Serial = Convert.ToUInt32(Serial.Parse(el.GetAttribute(\"serial\"))),\n                        X = Convert.ToUInt16(el.GetAttribute(\"x\")),\n                        Y = Convert.ToUInt16(el.GetAttribute(\"y\")),\n                        Z = Convert.ToUInt16(el.GetAttribute(\"z\")),\n                        Gfx = Convert.ToUInt16(el.GetAttribute(\"gfx\"))\n                    };\n\n                    MacroVariable macroVariable = new MacroVariable(el.GetAttribute(\"name\"), target);\n                    MacroVariableList.Add(macroVariable);\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        public static void Import(XmlElement node)\n        {\n            //import absolutetargets and doubleclickvariables to macrovariables\n\n            try\n            {\n                foreach (XmlElement el in node[\"absolutetargets\"].GetElementsByTagName(\"absolutetarget\"))\n                {\n                    TargetInfo target = new TargetInfo\n                    {\n                        Type = Convert.ToByte(el.GetAttribute(\"type\")),\n                        Flags = Convert.ToByte(el.GetAttribute(\"flags\")),\n                        Serial = Convert.ToUInt32(Serial.Parse(el.GetAttribute(\"serial\"))),\n                        X = Convert.ToUInt16(el.GetAttribute(\"x\")),\n                        Y = Convert.ToUInt16(el.GetAttribute(\"y\")),\n                        Z = Convert.ToUInt16(el.GetAttribute(\"z\")),\n                        Gfx = Convert.ToUInt16(el.GetAttribute(\"gfx\"))\n                    };\n\n                    MacroVariable macroVariable = new MacroVariable(el.GetAttribute(\"name\"), target);\n                    MacroVariableList.Add(macroVariable);\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n\n            try\n            {\n                foreach (XmlElement el in node[\"doubleclickvariables\"].GetElementsByTagName(\"doubleclickvariable\"))\n                {\n                    TargetInfo target = new TargetInfo\n                    {\n                        Type = 0,\n                        Flags = 0,\n                        Serial = Convert.ToUInt32(Serial.Parse(el.GetAttribute(\"serial\"))),\n                        X = 0,\n                        Y = 0,\n                        Z = 0,\n                        Gfx = Convert.ToUInt16(el.GetAttribute(\"gfx\"))\n                    };\n\n                    MacroVariable macroVariable = new MacroVariable(el.GetAttribute(\"name\"), target);\n                    MacroVariableList.Add(macroVariable);\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        public static void ClearAll()\n        {\n            MacroVariableList.Clear();\n        }\n    }\n}"
  },
  {
    "path": "Razor/Map/MapWindow.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Drawing;\r\nusing System.Windows.Forms;\r\nusing System.Runtime.InteropServices;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant.MapUO\r\n{\r\n    /// <summary>\r\n    /// Summary description for MapWindow.\r\n    /// </summary>\r\n    public class MapWindow : System.Windows.Forms.Form\r\n    {\r\n        public const int WM_NCLBUTTONDOWN = 0xA1;\r\n        public const int HT_CAPTION = 0x2;\r\n        private Assistant.MapUO.UOMapControl Map;\r\n\r\n        [DllImport(\"user32.dll\")]\r\n        private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);\r\n\r\n        [DllImport(\"user32.dll\")]\r\n        internal static extern bool ReleaseCapture();\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        public MapWindow()\r\n        {\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n            this.ContextMenuStrip = new ContextMenuStrip();\r\n            this.ContextMenuStrip.Opening += ContextMenu_Popup;\r\n            this.Location = new Point(Config.GetInt(\"MapX\"), Config.GetInt(\"MapY\"));\r\n            this.ClientSize = new Size(Config.GetInt(\"MapW\"), Config.GetInt(\"MapH\"));\r\n\r\n            if (this.Location.X < -10 || this.Location.Y < -10)\r\n                this.Location = Point.Empty;\r\n\r\n            if (this.Width < 50)\r\n                this.Width = 50;\r\n            if (this.Height < 50)\r\n                this.Height = 50;\r\n\r\n            //\r\n            // TODO: Add any constructor code after InitializeComponent call\r\n            //\r\n\r\n            this.Map.FullUpdate();\r\n            Client.Instance.SetMapWndHandle(this);\r\n        }\r\n\r\n        public class MapMenuItem : ToolStripMenuItem\r\n        {\r\n            public MapMenuItem(System.String text, System.EventHandler onClick) : base(text, null, onClick)\r\n            {\r\n                Tag = null;\r\n            }\r\n        }\r\n\r\n        void ContextMenu_Popup(object sender, EventArgs e)\r\n        {\r\n            ContextMenuStrip cm = this.ContextMenuStrip;\r\n            cm.Items.Clear();\r\n            if (World.Player != null && PacketHandlers.Party.Count > 0)\r\n            {\r\n                MapMenuItem mi = new MapMenuItem(\"You\", new EventHandler(FocusChange));\r\n                mi.Tag = World.Player.Serial;\r\n                cm.Items.Add(mi);\r\n                foreach (Serial s in PacketHandlers.Party)\r\n                {\r\n                    Mobile m = World.FindMobile(s);\r\n                    if (m.Name != null)\r\n                    {\r\n                        mi = new MapMenuItem(m.Name, new EventHandler(FocusChange));\r\n                        mi.Tag = s;\r\n                        if (this.Map.FocusMobile == m)\r\n                            mi.Checked = true;\r\n                        cm.Items.Add(mi);\r\n                    }\r\n                }\r\n            }\r\n\r\n            this.ContextMenuStrip = cm;\r\n        }\r\n\r\n\r\n        private void FocusChange(object sender, System.EventArgs e)\r\n        {\r\n            if (sender != null)\r\n            {\r\n                MapMenuItem mItem = sender as MapMenuItem;\r\n\r\n                if (mItem != null)\r\n                {\r\n                    Serial s = (Serial) mItem.Tag;\r\n                    Mobile m = World.FindMobile(s);\r\n                    this.Map.FocusMobile = m;\r\n                    this.Map.FullUpdate();\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void Initialize()\r\n        {\r\n            new ReqPartyLocTimer().Start();\r\n\r\n            HotKey.Add(HKCategory.Misc, LocString.ToggleMap, new HotKeyCallback(ToggleMap));\r\n        }\r\n\r\n        public static void ToggleMap()\r\n        {\r\n            if (World.Player != null && Engine.MainWindow != null)\r\n            {\r\n                if (Engine.MainWindow.MapWindow == null)\r\n                {\r\n                    Engine.MainWindow.SafeAction(s =>\r\n                    {\r\n                        s.MapWindow = new Assistant.MapUO.MapWindow();\r\n                        s.MapWindow.Show();\r\n                        s.MapWindow.BringToFront();\r\n                    });\r\n                }\r\n                else\r\n                {\r\n                    if (Engine.MainWindow.MapWindow.Visible)\r\n                    {\r\n                        Engine.MainWindow.SafeAction(s =>\r\n                        {\r\n                            s.MapWindow.Hide();\r\n                            s.BringToFront();\r\n                        });\r\n                        Platform.BringToFront(Client.Instance.GetWindowHandle());\r\n                    }\r\n                    else\r\n                    {\r\n                        Engine.MainWindow.MapWindow.Show();\r\n                        Engine.MainWindow.MapWindow.BringToFront();\r\n                        Engine.MainWindow.MapWindow.TopMost = true;\r\n                        Client.Instance.SetMapWndHandle(Engine.MainWindow.MapWindow);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MapWindow));\r\n            this.Map = new Assistant.MapUO.UOMapControl();\r\n            this.SuspendLayout();\r\n            //\r\n            // Map\r\n            //\r\n            this.Map.Active = true;\r\n            this.Map.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;\r\n            this.Map.FocusMobile = null;\r\n            this.Map.Location = new System.Drawing.Point(0, 0);\r\n            this.Map.Name = \"Map\";\r\n            this.Map.Size = new System.Drawing.Size(296, 272);\r\n            this.Map.TabIndex = 0;\r\n            this.Map.TabStop = false;\r\n            this.Map.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Map_MouseDown);\r\n            //\r\n            // MapWindow\r\n            //\r\n            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);\r\n            this.BackColor = System.Drawing.Color.Black;\r\n            this.ClientSize = new System.Drawing.Size(292, 266);\r\n            this.Controls.Add(this.Map);\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;\r\n            this.Icon = ((System.Drawing.Icon) (resources.GetObject(\"$this.Icon\")));\r\n            this.MaximizeBox = false;\r\n            this.Name = \"MapWindow\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;\r\n            this.Text = \"UO Positioning System\";\r\n            this.TopMost = true;\r\n            this.Resize += new System.EventHandler(this.MapWindow_Resize);\r\n            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.MapWindow_MouseDown);\r\n            this.Closing += new System.ComponentModel.CancelEventHandler(this.MapWindow_Closing);\r\n            this.Move += new System.EventHandler(this.MapWindow_Move);\r\n            this.Deactivate += new System.EventHandler(this.MapWindow_Deactivate);\r\n            this.ResumeLayout(false);\r\n        }\r\n\r\n        #endregion\r\n\r\n        public void CheckLocalUpdate(Mobile mob)\r\n        {\r\n            if (mob.InParty)\r\n                this.Map.FullUpdate();\r\n        }\r\n\r\n        private static Font m_RegFont = new Font(\"Courier New\", 8);\r\n        /*private   int ButtonRows;\r\n        protected override void OnPaint(PaintEventArgs e)\r\n        {\r\n        base.OnPaint(e);\r\n        if ( PacketHandlers.Party.Count > 0 )\r\n        {\r\n        //75x15\r\n        int xcount = 0;\r\n        int ycount = 0;\r\n        Point org = new Point(0, (ButtonRows * 15));\r\n        if (this.FormBorderStyle == FormBorderStyle.None)\r\n        {\r\n        org = new Point(0,  (ButtonRows * 15) + 32);\r\n        }\r\n\r\n        foreach ( Serial s in PacketHandlers.Party )\r\n        {\r\n        Mobile mob = World.FindMobile( s );\r\n        if ( mob == null )\r\n             continue;\r\n\r\n        if (((75 * (xcount+1)) - this.Width) > 0)\r\n        {\r\n             xcount = 0;\r\n             ycount++;\r\n        }\r\n        string name = mob.Name;\r\n        if ( name != null && name.Length > 8)\r\n        {\r\n             name = name.Substring(0, 8);\r\n             name += \"...\";\r\n        }\r\n        else if ( name == null || name.Length < 1 )\r\n        {\r\n             name = \"(Not Seen)\";\r\n        }\r\n\r\n        Point drawPoint = new Point(org.X + (75 * xcount), org.Y + (15*ycount));\r\n        mob.ButtonPoint = new Point2D( drawPoint.X, drawPoint.Y );\r\n        e.Graphics.FillRectangle( Brushes.Black, drawPoint.X, drawPoint.Y, 75, 15 );\r\n        e.Graphics.DrawRectangle(Pens.Gray, drawPoint.X, drawPoint.Y, 75, 15 );\r\n        e.Graphics.DrawString(name, m_RegFont, Brushes.White, drawPoint);\r\n        xcount++;\r\n        }\r\n        if(ycount > 0)\r\n        ButtonRows = ycount;\r\n        }\r\n\r\n        }*/\r\n\r\n        private class ReqPartyLocTimer : Timer\r\n        {\r\n            public ReqPartyLocTimer() : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))\r\n            {\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                // never send this packet to encrypted servers (could lead to OSI detecting razor)\r\n                if (Client.Instance.ServerEncrypted)\r\n                {\r\n                    Stop();\r\n                    return;\r\n                }\r\n\r\n                if (Engine.MainWindow == null || Engine.MainWindow.MapWindow == null ||\r\n                    !Engine.MainWindow.MapWindow.Visible)\r\n                    return; // don't bother when the map window isnt visible\r\n\r\n                if (World.Player != null && PacketHandlers.Party.Count > 0)\r\n                {\r\n                    if (PacketHandlers.SpecialPartySent > PacketHandlers.SpecialPartyReceived)\r\n                    {\r\n                        // If we sent more than we received then the server stopped responding\r\n                        // in that case, wait a long while before trying again\r\n                        PacketHandlers.SpecialPartySent = PacketHandlers.SpecialPartyReceived = 0;\r\n                        this.Interval = TimeSpan.FromSeconds(5.0);\r\n                        return;\r\n                    }\r\n                    else\r\n                    {\r\n                        this.Interval = TimeSpan.FromSeconds(1.0);\r\n                    }\r\n\r\n                    bool send = false;\r\n                    foreach (Serial s in PacketHandlers.Party)\r\n                    {\r\n                        Mobile m = World.FindMobile(s);\r\n\r\n                        if (m == World.Player)\r\n                            continue;\r\n\r\n                        if (m == null || Utility.Distance(World.Player.Position, m.Position) > World.Player.VisRange ||\r\n                            !m.Visible)\r\n                        {\r\n                            send = true;\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    if (send)\r\n                    {\r\n                        PacketHandlers.SpecialPartySent++;\r\n                        Client.Instance.SendToServer(new QueryPartyLocs());\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    this.Interval = TimeSpan.FromSeconds(1.0);\r\n                }\r\n            }\r\n        }\r\n\r\n        private void RequestPartyLocations()\r\n        {\r\n            if (World.Player != null && PacketHandlers.Party.Count > 0)\r\n                Client.Instance.SendToServer(new QueryPartyLocs());\r\n        }\r\n\r\n        public void UpdateMap()\r\n        {\r\n            Client.Instance.SetMapWndHandle(this);\r\n            this.Map.UpdateMap();\r\n        }\r\n\r\n        private void MapWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)\r\n        {\r\n            if (Engine.Running)\r\n            {\r\n                Engine.MainWindow.MapWindow.SafeAction(s =>\r\n                {\r\n                    e.Cancel = true;\r\n                    s.Hide();\r\n                });\r\n            }\r\n        }\r\n\r\n        public void PlayerMoved()\r\n        {\r\n            if (this.Visible && this.Map != null)\r\n                this.Map.FullUpdate();\r\n        }\r\n\r\n        private void MapWindow_Resize(object sender, System.EventArgs e)\r\n        {\r\n            this.Map.Height = this.Height;\r\n            this.Map.Width = this.Width;\r\n\r\n            if (this.Width < 50)\r\n                this.Width = 50;\r\n            if (this.Height < 50)\r\n                this.Height = 50;\r\n\r\n            this.Refresh();\r\n\r\n            Config.SetProperty(\"MapX\", this.Location.X);\r\n            Config.SetProperty(\"MapY\", this.Location.Y);\r\n            Config.SetProperty(\"MapW\", this.ClientSize.Width);\r\n            Config.SetProperty(\"MapH\", this.ClientSize.Height);\r\n        }\r\n\r\n        private void MapWindow_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Clicks == 2)\r\n            {\r\n                if (this.FormBorderStyle == FormBorderStyle.None)\r\n                    this.FormBorderStyle = FormBorderStyle.SizableToolWindow;\r\n                else\r\n                    this.FormBorderStyle = FormBorderStyle.None;\r\n            }\r\n\r\n            if (e.Button == MouseButtons.Left)\r\n            {\r\n                ReleaseCapture();\r\n                SendMessage(Handle, WM_NCLBUTTONDOWN, (IntPtr) HT_CAPTION, IntPtr.Zero);\r\n                /*foreach ( Serial s in PacketHandlers.Party )\r\n                {\r\n                Mobile m = World.FindMobile( s );\r\n                if ( m == null )\r\n                     continue;\r\n                Rectangle rec = new Rectangle( m.ButtonPoint.X, m.ButtonPoint.Y, 75, 15 );\r\n                if ( rec.Contains( e.X, e.Y ) )\r\n                {\r\n                     this.Map.FocusMobile = m;\r\n                     this.Map.Refresh();\r\n                }\r\n                }*/\r\n            }\r\n\r\n            this.Map.MapClick(e);\r\n        }\r\n\r\n        private void Map_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            MapWindow_MouseDown(sender, e);\r\n        }\r\n\r\n        private void MapWindow_Move(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"MapX\", this.Location.X);\r\n            Config.SetProperty(\"MapY\", this.Location.Y);\r\n            Config.SetProperty(\"MapW\", this.ClientSize.Width);\r\n            Config.SetProperty(\"MapH\", this.ClientSize.Height);\r\n        }\r\n\r\n        private void MapWindow_Deactivate(object sender, System.EventArgs e)\r\n        {\r\n            if (this.TopMost)\r\n                this.TopMost = false;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Map/MapWindow.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 1.3\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">1.3</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\">this is my long string</data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        [base64 mime encoded serialized .NET Framework object]\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        [base64 mime encoded string representing a byte array form of the .NET Framework object]\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used forserialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>1.3</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <data name=\"Map.Locked\" type=\"System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>False</value>\r\n  </data>\r\n  <data name=\"Map.DefaultModifiers\" type=\"System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>Private</value>\r\n  </data>\r\n  <data name=\"Map.Modifiers\" type=\"System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>Private</value>\r\n  </data>\r\n  <data name=\"$this.Locked\" type=\"System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>False</value>\r\n  </data>\r\n  <data name=\"$this.Language\" type=\"System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>(Default)</value>\r\n  </data>\r\n  <data name=\"$this.TrayLargeIcon\" type=\"System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>False</value>\r\n  </data>\r\n  <data name=\"$this.Localizable\" type=\"System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>False</value>\r\n  </data>\r\n  <data name=\"$this.GridSize\" type=\"System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\r\n    <value>8, 8</value>\r\n  </data>\r\n  <data name=\"$this.DrawGrid\" type=\"System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>True</value>\r\n  </data>\r\n  <data name=\"$this.TrayHeight\" type=\"System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>80</value>\r\n  </data>\r\n  <data name=\"$this.Name\">\r\n    <value>MapWindow</value>\r\n  </data>\r\n  <data name=\"$this.SnapToGrid\" type=\"System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>True</value>\r\n  </data>\r\n  <data name=\"$this.DefaultModifiers\" type=\"System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>Private</value>\r\n  </data>\r\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        AAABAAEAEBAQAAAAAAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAABAA\r\n        AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//\r\n        AAD///8AIiIiIiiIiCIAAAAAAIiAAAAAAAAACAAAAAAAAAAIAAAACIiIAAgAAAAAAHiICAAAAAAAB3iI\r\n        AAAAAAAAiIAAAAAAAAiIeAAAAAC7AYB4gAAAAACwAAeAAAC7AAsAAIAAAACwCwAAgAAAAAsAAACAAAuw\r\n        CwAAAAAAALAAAAAAAAAAAAAA/8cAAP/vAAD/7wAA4O8AAPwvAAD+DwAA/x8AAP4PAADyRwAA/ecAAM73\r\n        AAD29wAA+/cAAJv/AADf/wAA\r\n</value>\r\n  </data>\r\n</root>"
  },
  {
    "path": "Razor/Map/Region.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System.IO;\r\nusing System.Collections;\r\n\r\nnamespace Assistant.MapUO\r\n{\r\n    class Region\r\n    {\r\n        private int m_Height;\r\n        private int m_Width;\r\n        private int m_X;\r\n        private int m_Y;\r\n\r\n        public Region(string line)\r\n        {\r\n            string[] textArray1 = line.Split(new char[] {' '});\r\n            this.m_X = int.Parse(textArray1[0]);\r\n            this.m_Y = int.Parse(textArray1[1]);\r\n            this.m_Width = int.Parse(textArray1[2]);\r\n            this.m_Height = int.Parse(textArray1[3]);\r\n        }\r\n\r\n        public Region(int x, int y, int width, int height)\r\n        {\r\n            this.m_X = x;\r\n            this.m_Y = y;\r\n            this.m_Width = width;\r\n            this.m_Height = height;\r\n        }\r\n\r\n\r\n        public static Region[] Load(string path)\r\n        {\r\n            if (!File.Exists(path))\r\n            {\r\n                return new Region[0];\r\n            }\r\n\r\n            ArrayList list1 = new ArrayList();\r\n            try\r\n            {\r\n                using (StreamReader reader1 = new StreamReader(path))\r\n                {\r\n                    string text1;\r\n                    while ((text1 = reader1.ReadLine()) != null)\r\n                    {\r\n                        if ((text1.Length != 0) && !text1.StartsWith(\"#\"))\r\n                        {\r\n                            list1.Add(new Region(text1));\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            return (Region[]) list1.ToArray(typeof(Region));\r\n        }\r\n\r\n        public int X\r\n        {\r\n            get { return m_X; }\r\n            set { m_X = value; }\r\n        }\r\n\r\n        public int Y\r\n        {\r\n            get { return m_Y; }\r\n            set { m_Y = value; }\r\n        }\r\n\r\n        public int Length\r\n        {\r\n            get { return m_Height; }\r\n            set { m_Height = value; }\r\n        }\r\n\r\n        public int Width\r\n        {\r\n            get { return m_Width; }\r\n            set { m_Width = value; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Map/UOMapControl.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Drawing;\r\nusing System.Windows.Forms;\r\nusing System.Collections;\r\nusing System.Drawing.Drawing2D;\r\nusing System.IO;\r\n\r\nnamespace Assistant.MapUO\r\n{\r\n    public class UOMapControl : PictureBox\r\n    {\r\n        delegate void UpdateMapCallback();\r\n\r\n        private bool m_Active;\r\n        private Region[] m_Regions;\r\n        private ArrayList m_MapButtons;\r\n        private Point prevPoint;\r\n        private Mobile m_Focus;\r\n        private const double RotateAngle = Math.PI / 4 + Math.PI;\r\n        private Bitmap m_Background;\r\n        private DateTime LastRefresh;\r\n\r\n        public Mobile FocusMobile\r\n        {\r\n            get\r\n            {\r\n                if (m_Focus == null || m_Focus.Deleted || !PacketHandlers.Party.Contains(m_Focus.Serial))\r\n                {\r\n                    /*if ( World.Player == null )\r\n                         return new Mobile( Serial.Zero );\r\n                    else*/\r\n                    return World.Player;\r\n                }\r\n\r\n                return m_Focus;\r\n            }\r\n            set { m_Focus = value; }\r\n        }\r\n\r\n        public UOMapControl()\r\n        {\r\n            Active = false;\r\n            this.prevPoint = new Point(0, 0);\r\n            this.BorderStyle = BorderStyle.Fixed3D;\r\n            this.m_MapButtons = new ArrayList();\r\n            m_Regions = Assistant.MapUO.Region.Load(Path.Combine(Config.GetInstallDirectory(), \"guardlines.def\"));\r\n            m_MapButtons = UOMapRuneButton.Load(\"test.xml\");\r\n        }\r\n\r\n        private static Font m_BoldFont = new Font(\"Courier New\", 8, FontStyle.Bold);\r\n        private static Font m_SmallFont = new Font(\"Arial\", 6);\r\n        private static Font m_RegFont = new Font(\"Arial\", 8);\r\n\r\n        public override void Refresh()\r\n        {\r\n            TimeSpan now = DateTime.UtcNow - LastRefresh;\r\n            if (now.TotalMilliseconds <= 100)\r\n                return;\r\n            LastRefresh = DateTime.UtcNow;\r\n            base.Refresh();\r\n        }\r\n\r\n        private PointF AdjustPoint(PointF center, PointF pos)\r\n        {\r\n            PointF newp = new PointF(center.X - pos.X, center.Y - pos.Y);\r\n            float dis = (float) Distance(center, pos);\r\n            dis += dis * 0.50f;\r\n            float slope = 0;\r\n            if (newp.X != 0)\r\n                slope = (float) newp.Y / (float) newp.X;\r\n            else\r\n                return new PointF(0 + center.X, -1f * (newp.Y + (newp.Y * 0.25f)) + center.Y);\r\n            slope *= -1;\r\n            //Both of these algorithms oddly produce the same results.\r\n            //float x = dis / (float)(Math.Sqrt(1f + Math.Pow(slope, 2)));\r\n            float x = newp.X + (newp.X * 0.5f);\r\n            // if (newp.X > 0)\r\n            x *= -1;\r\n            float y = (-1) * slope * x;\r\n\r\n            PointF def = new PointF(x + center.X, y + center.Y);\r\n\r\n            return def;\r\n        }\r\n\r\n        public double Distance(PointF center, PointF pos)\r\n        {\r\n            PointF newp = new PointF(center.X - pos.X, center.Y - pos.Y);\r\n            double distX = Math.Pow(newp.X, 2);\r\n            double distY = Math.Pow(newp.Y, 2);\r\n            return Math.Sqrt(distX + distY);\r\n        }\r\n\r\n        private PointF RotatePoint(PointF center, PointF pos)\r\n        {\r\n            PointF newp = new PointF(center.X - pos.X, center.Y - pos.Y);\r\n            double x = newp.X * Math.Cos(RotateAngle) - newp.Y * Math.Sin(RotateAngle);\r\n            double y = newp.X * Math.Sin(RotateAngle) + newp.Y * Math.Sin(RotateAngle);\r\n            return AdjustPoint(center, new PointF((float) (x) + center.X, (float) (y) + center.Y));\r\n        }\r\n\r\n        public void FullUpdate()\r\n        {\r\n            if (!Active)\r\n                return;\r\n\r\n            if (m_Background != null)\r\n                m_Background.Dispose();\r\n            m_Background = new Bitmap(this.Width, this.Height);\r\n\r\n            int xLong = 0, yLat = 0;\r\n            int xMins = 0, yMins = 0;\r\n            bool xEast = false, ySouth = false;\r\n\r\n            int w = (this.Width) >> 3;\r\n            int h = (this.Height) >> 3;\r\n            int xtrans = this.Width / 2;\r\n            int ytrans = this.Height / 2;\r\n            Point3D focus = this.FocusMobile.Position;\r\n            Point offset = new Point(focus.X & 7, focus.Y & 7);\r\n            Point mapOrigin = new Point((focus.X >> 3) - (w / 2), (focus.Y >> 3) - (h / 2));\r\n            Point pntPlayer = new Point((focus.X) - (mapOrigin.X << 3) - offset.X,\r\n                (focus.Y) - (mapOrigin.Y << 3) - offset.Y);\r\n\r\n            Graphics gfx = Graphics.FromImage(m_Background);\r\n\r\n            gfx.FillRectangle(Brushes.Black, 0, 0, this.Width, this.Height);\r\n\r\n            gfx.TranslateTransform(-xtrans, -ytrans, MatrixOrder.Append);\r\n            gfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;\r\n            gfx.PageUnit = GraphicsUnit.Pixel;\r\n            gfx.ScaleTransform(1.5f, 1.5f, MatrixOrder.Append);\r\n            gfx.RotateTransform(45, MatrixOrder.Append);\r\n            gfx.TranslateTransform(xtrans, ytrans, MatrixOrder.Append);\r\n\r\n            Ultima.Map map = Map.GetMap(this.FocusMobile.Map);\r\n            if (map == null)\r\n                map = Ultima.Map.Felucca;\r\n\r\n            gfx.DrawImage(map.GetImage(mapOrigin.X, mapOrigin.Y, w + offset.X, h + offset.Y, true), -offset.X,\r\n                -offset.Y);\r\n\r\n            gfx.ScaleTransform(1.0f, 1.0f, MatrixOrder.Append);\r\n\r\n            ArrayList regions = new ArrayList();\r\n            ArrayList mButtons = new ArrayList();\r\n            if (this.Width > this.Height)\r\n            {\r\n                regions = RegionList(focus.X, focus.Y, this.Width);\r\n                mButtons = ButtonList(focus.X, focus.Y, this.Width);\r\n            }\r\n            else\r\n            {\r\n                regions = RegionList(focus.X, focus.Y, this.Height);\r\n                mButtons = ButtonList(focus.X, focus.Y, this.Height);\r\n            }\r\n\r\n            foreach (Assistant.MapUO.Region region in regions)\r\n                gfx.DrawRectangle(Pens.LimeGreen, (region.X) - ((mapOrigin.X << 3) + offset.X),\r\n                    (region.Y) - ((mapOrigin.Y << 3) + offset.Y), region.Width, region.Length);\r\n\r\n            gfx.DrawLine(Pens.Silver, pntPlayer.X - 2, pntPlayer.Y - 2, pntPlayer.X + 2, pntPlayer.Y + 2);\r\n            gfx.DrawLine(Pens.Silver, pntPlayer.X - 2, pntPlayer.Y + 2, pntPlayer.X + 2, pntPlayer.Y - 2);\r\n            gfx.FillRectangle(Brushes.Red, pntPlayer.X, pntPlayer.Y, 1, 1);\r\n            //gfx.DrawEllipse( Pens.Silver, pntPlayer.X - 2, pntPlayer.Y - 2, 4, 4 );\r\n\r\n            gfx.DrawString(\"W\", m_BoldFont, Brushes.Red, pntPlayer.X - 35, pntPlayer.Y - 5);\r\n            gfx.DrawString(\"E\", m_BoldFont, Brushes.Red, pntPlayer.X + 25, pntPlayer.Y - 5);\r\n            gfx.DrawString(\"N\", m_BoldFont, Brushes.Red, pntPlayer.X - 5, pntPlayer.Y - 35);\r\n            gfx.DrawString(\"S\", m_BoldFont, Brushes.Red, pntPlayer.X - 5, pntPlayer.Y + 25);\r\n\r\n            gfx.ResetTransform();\r\n\r\n\r\n            if (Format(new Point(focus.X, focus.Y), Ultima.Map.Felucca, ref xLong, ref yLat, ref xMins, ref yMins,\r\n                ref xEast, ref ySouth))\r\n            {\r\n                string locString =\r\n                    $\"{yLat}°{yMins}'{(ySouth ? \"S\" : \"N\")} {xLong}°{xMins}'{(xEast ? \"E\" : \"W\")} | ({World.Player.Position.X},{World.Player.Position.Y})\";\r\n                SizeF size = gfx.MeasureString(locString, m_RegFont);\r\n                gfx.FillRectangle(Brushes.Wheat, 0, 0, size.Width + 2, size.Height + 2);\r\n                gfx.DrawRectangle(Pens.Black, 0, 0, size.Width + 2, size.Height + 2);\r\n                gfx.DrawString(locString, m_RegFont, Brushes.Black, 1, 1);\r\n            }\r\n\r\n            gfx.ResetTransform();\r\n            gfx.Dispose();\r\n\r\n            this.Refresh();\r\n        }\r\n\r\n        protected override void OnPaint(PaintEventArgs pe)\r\n        {\r\n            try\r\n            {\r\n                if (Active)\r\n                {\r\n                    Graphics gfx = pe.Graphics;\r\n\r\n                    gfx.DrawImageUnscaled(m_Background, 0, 0);\r\n\r\n                    int w = (this.Width) >> 3;\r\n                    int h = (this.Height) >> 3;\r\n                    int xtrans = this.Width / 2;\r\n                    int ytrans = this.Height / 2;\r\n                    Point3D focus = this.FocusMobile.Position;\r\n                    Point offset = new Point(focus.X & 7, focus.Y & 7);\r\n                    Point mapOrigin = new Point((focus.X >> 3) - (w / 2), (focus.Y >> 3) - (h / 2));\r\n\r\n                    gfx.TranslateTransform(-xtrans, -ytrans, MatrixOrder.Append);\r\n                    gfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;\r\n                    gfx.PageUnit = GraphicsUnit.Pixel;\r\n                    gfx.ScaleTransform(1.5f, 1.5f, MatrixOrder.Append);\r\n                    gfx.RotateTransform(45, MatrixOrder.Append);\r\n                    gfx.TranslateTransform(xtrans, ytrans, MatrixOrder.Append);\r\n                    gfx.ScaleTransform(1.0f, 1.0f, MatrixOrder.Append);\r\n                    gfx.ResetTransform();\r\n\r\n                    //Point pntTest2 = new Point((3256) - (mapOrigin.X << 3) - offset.X, (326) - (mapOrigin.Y << 3) - offset.Y);\r\n                    //PointF pntTest2F = RotatePoint(new Point(xtrans, ytrans), pntTest2);\r\n                    //gfx.FillRectangle(Brushes.LimeGreen, pntTest2F.X, pntTest2F.Y, 4, 4);\r\n                    /*foreach ( Serial s in PacketHandlers.Party )\r\n                    {\r\n                         Mobile mob = World.FindMobile( s );\r\n                         if ( mob == null )\r\n                              continue;\r\n                         if (mob == this.FocusMobile)\r\n                              continue;\r\n                         Point drawPoint = new Point((mob.Position.X) - (mapOrigin.X << 3) - offset.X, (mob.Position.Y) - (mapOrigin.Y << 3) - offset.Y);\r\n\r\n                         if (drawPoint.X < 0)\r\n                              drawPoint.X = 0;\r\n                         if (drawPoint.X > this.Width)\r\n                              drawPoint.X = this.Width;\r\n                         if (drawPoint.Y < 0)\r\n                              drawPoint.Y = 0;\r\n                         if (drawPoint.Y > this.Height)\r\n                              drawPoint.Y = this.Height;\r\n                         PointF drawPointF = RotatePoint(new Point(xtrans,ytrans),drawPoint);\r\n                         //gfx.FillRectangle(Brushes.Gold, drawPointF.X, drawPointF.Y, 2f, 2f);\r\n                    }*/\r\n                    foreach (Serial s in PacketHandlers.Party)\r\n                    {\r\n                        Mobile mob = World.FindMobile(s);\r\n                        if (mob == null)\r\n                            continue;\r\n\r\n                        if (mob == this.FocusMobile && mob == World.Player)\r\n                            continue;\r\n\r\n                        string name = mob.Name;\r\n                        if (name == null || name.Length < 1)\r\n                            name = \"(Not Seen)\";\r\n                        if (name != null && name.Length > 8)\r\n                            name = name.Substring(0, 8);\r\n                        Point drawPoint = new Point((mob.Position.X) - (mapOrigin.X << 3) - offset.X,\r\n                            (mob.Position.Y) - (mapOrigin.Y << 3) - offset.Y);\r\n                        if (drawPoint.X < 0)\r\n                            drawPoint.X = 0;\r\n                        if (drawPoint.X > this.Width)\r\n                            drawPoint.X = this.Width;\r\n                        if (drawPoint.Y < 0)\r\n                            drawPoint.Y = 0;\r\n                        if (drawPoint.Y > this.Height)\r\n                            drawPoint.Y = this.Height;\r\n\r\n                        PointF drawPointF = RotatePoint(new Point(xtrans, ytrans), drawPoint);\r\n                        gfx.FillRectangle(Brushes.Gold, drawPointF.X, drawPointF.Y, 2f, 2f);\r\n                        gfx.DrawString(name, m_RegFont, Brushes.White, drawPointF.X, drawPointF.Y);\r\n                    }\r\n\r\n                    if (World.Player != null)\r\n                    {\r\n                        if (World.Player != this.FocusMobile)\r\n                        {\r\n                            Mobile mob = World.Player;\r\n                            Point drawPoint = new Point((mob.Position.X) - (mapOrigin.X << 3) - offset.X,\r\n                                (mob.Position.Y) - (mapOrigin.Y << 3) - offset.Y);\r\n                            PointF drawPointF = RotatePoint(new Point(xtrans, ytrans), drawPoint);\r\n                            gfx.FillRectangle(Brushes.Gold, drawPointF.X, drawPointF.Y, 2, 2);\r\n                            drawPoint = new Point((mob.Position.X) - (mapOrigin.X << 3) - offset.X,\r\n                                (mob.Position.Y) - (mapOrigin.Y << 3) - offset.Y);\r\n                            drawPointF = RotatePoint(new Point(xtrans, ytrans), drawPoint);\r\n                            string name = mob.Name;\r\n                            if (name != null && name.Length > 8)\r\n                                name = name.Substring(0, 8);\r\n\r\n                            gfx.DrawString(name, m_RegFont, Brushes.White, drawPointF.X, drawPointF.Y);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            base.OnPaint(pe);\r\n        }\r\n\r\n        public void MapClick(System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (Active)\r\n            {\r\n                Point clickedbox = MousePointToMapPoint(new Point(e.X, e.Y));\r\n                UOMapRuneButton button = ButtonCheck(new Rectangle(clickedbox.X - 2, clickedbox.Y - 2, 5, 5));\r\n                if (button != null)\r\n                    button.OnClick(e);\r\n            }\r\n        }\r\n\r\n        private Point MousePointToMapPoint(Point p)\r\n        {\r\n            double rad = (Math.PI / 180) * 45;\r\n            int w = (this.Width) >> 3;\r\n            int h = (this.Height) >> 3;\r\n            Point3D focus = this.FocusMobile.Position;\r\n\r\n            Point mapOrigin = new Point((focus.X >> 3) - (w / 2), (focus.Y >> 3) - (h / 2));\r\n            Point pnt1 = new Point((mapOrigin.X << 3) + (p.X), (mapOrigin.Y << 3) + (p.Y));\r\n            Point check = new Point(pnt1.X - focus.X, pnt1.Y - focus.Y);\r\n            check = RotatePoint(new Point((int) (check.X * 0.695), (int) (check.Y * 0.68)), rad, 1);\r\n            return new Point(check.X + focus.X, check.Y + focus.Y);\r\n        }\r\n\r\n        private Point RotatePoint(Point p, double angle, double dist)\r\n        {\r\n            int x = (int) ((p.X * Math.Cos(angle) + p.Y * Math.Sin(angle)) * dist);\r\n            int y = (int) ((-p.X * Math.Sin(angle) + p.Y * Math.Cos(angle)) * dist);\r\n\r\n            return new Point(x, y);\r\n        }\r\n\r\n        private UOMapRuneButton ButtonCheck(Rectangle rec)\r\n        {\r\n            ArrayList buttons = new ArrayList();\r\n            foreach (UOMapRuneButton mbutton in this.m_MapButtons)\r\n            {\r\n                Rectangle rec2 = new Rectangle(mbutton.X, mbutton.Y, 10, 10);\r\n                if (rec2.IntersectsWith(rec))\r\n                    return mbutton;\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            m_Background.Dispose();\r\n            m_Background = null;\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        protected override void OnResize(EventArgs e)\r\n        {\r\n            base.OnResize(e);\r\n            FullUpdate();\r\n        }\r\n\r\n        public void UpdateMap()\r\n        {\r\n            try\r\n            {\r\n                if (this.InvokeRequired)\r\n                {\r\n                    UpdateMapCallback d = new UpdateMapCallback(UpdateMap);\r\n                    this.Invoke(d, new object[0]);\r\n                }\r\n                else\r\n                {\r\n                    this.Refresh();\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private ArrayList RegionList(int x, int y, int maxDist)\r\n        {\r\n            int count = m_Regions.Length;\r\n            ArrayList aList = new ArrayList();\r\n            for (int i = 0; i < count; i++)\r\n            {\r\n                Assistant.MapUO.Region rg1 = this.m_Regions[i];\r\n                if (Utility.Distance(rg1.X, rg1.Y, x, y) <= maxDist * 2)\r\n                {\r\n                    aList.Add(rg1);\r\n                }\r\n            }\r\n\r\n            return aList;\r\n        }\r\n\r\n        private ArrayList ButtonList(int x, int y, int maxDist)\r\n        {\r\n            if (this.m_MapButtons == null)\r\n                return null;\r\n            int count = this.m_MapButtons.Count;\r\n            ArrayList aList = new ArrayList();\r\n            for (int i = 0; i < count; i++)\r\n            {\r\n                UOMapRuneButton btn = (UOMapRuneButton) this.m_MapButtons[i];\r\n                if (Utility.Distance(btn.X, btn.Y, x, y) <= maxDist * 2)\r\n                {\r\n                    aList.Add(btn);\r\n                }\r\n            }\r\n\r\n            return aList;\r\n        }\r\n\r\n        public static bool Format(Point p, Ultima.Map map, ref int xLong, ref int yLat, ref int xMins, ref int yMins,\r\n            ref bool xEast, ref bool ySouth)\r\n        {\r\n            if (map == null)\r\n                return false;\r\n\r\n            int x = p.X, y = p.Y;\r\n            int xCenter, yCenter;\r\n            int xWidth, yHeight;\r\n\r\n            if (!ComputeMapDetails(map, x, y, out xCenter, out yCenter, out xWidth, out yHeight))\r\n                return false;\r\n\r\n            double absLong = (double) ((x - xCenter) * 360) / xWidth;\r\n            double absLat = (double) ((y - yCenter) * 360) / yHeight;\r\n\r\n            if (absLong > 180.0)\r\n                absLong = -180.0 + (absLong % 180.0);\r\n\r\n            if (absLat > 180.0)\r\n                absLat = -180.0 + (absLat % 180.0);\r\n\r\n            bool east = (absLong >= 0), south = (absLat >= 0);\r\n\r\n            if (absLong < 0.0)\r\n                absLong = -absLong;\r\n\r\n            if (absLat < 0.0)\r\n                absLat = -absLat;\r\n\r\n            xLong = (int) absLong;\r\n            yLat = (int) absLat;\r\n\r\n            xMins = (int) ((absLong % 1.0) * 60);\r\n            yMins = (int) ((absLat % 1.0) * 60);\r\n\r\n            xEast = east;\r\n            ySouth = south;\r\n\r\n            return true;\r\n        }\r\n\r\n        public static bool ComputeMapDetails(Ultima.Map map, int x, int y, out int xCenter, out int yCenter,\r\n            out int xWidth, out int yHeight)\r\n        {\r\n            xWidth = 5120;\r\n            yHeight = 4096;\r\n\r\n            if (map == Ultima.Map.Trammel || map == Ultima.Map.Felucca)\r\n            {\r\n                if (x >= 0 && y >= 0 && x < 5120 && y < map.Height)\r\n                {\r\n                    xCenter = 1323;\r\n                    yCenter = 1624;\r\n                }\r\n                else if (x >= 5120 && y >= 2304 && x < 6144 && y < map.Height)\r\n                {\r\n                    xCenter = 5936;\r\n                    yCenter = 3112;\r\n                }\r\n                else\r\n                {\r\n                    xCenter = 0;\r\n                    yCenter = 0;\r\n                    return false;\r\n                }\r\n            }\r\n            else if (x >= 0 && y >= 0 && x < map.Width && y < map.Height)\r\n            {\r\n                xCenter = 1323;\r\n                yCenter = 1624;\r\n            }\r\n            else\r\n            {\r\n                xCenter = map.Width / 2;\r\n                yCenter = map.Height / 2;\r\n                return false;\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        public bool Active\r\n        {\r\n            get { return m_Active; }\r\n            set\r\n            {\r\n                m_Active = value;\r\n                if (value)\r\n                {\r\n                    FullUpdate();\r\n                }\r\n            }\r\n        }\r\n\r\n        public ArrayList MapButtons\r\n        {\r\n            get { return m_MapButtons; }\r\n            set { m_MapButtons = value; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Map/UOMapControl.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n<root>\r\n\t<xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n\t\t<xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n\t\t\t<xsd:complexType>\r\n\t\t\t\t<xsd:choice maxOccurs=\"unbounded\">\r\n\t\t\t\t\t<xsd:element name=\"data\">\r\n\t\t\t\t\t\t<xsd:complexType>\r\n\t\t\t\t\t\t\t<xsd:sequence>\r\n\t\t\t\t\t\t\t\t<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n\t\t\t\t\t\t\t\t<xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n\t\t\t\t\t\t\t</xsd:sequence>\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n\t\t\t\t\t\t</xsd:complexType>\r\n\t\t\t\t\t</xsd:element>\r\n\t\t\t\t\t<xsd:element name=\"resheader\">\r\n\t\t\t\t\t\t<xsd:complexType>\r\n\t\t\t\t\t\t\t<xsd:sequence>\r\n\t\t\t\t\t\t\t\t<xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n\t\t\t\t\t\t\t</xsd:sequence>\r\n\t\t\t\t\t\t\t<xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n\t\t\t\t\t\t</xsd:complexType>\r\n\t\t\t\t\t</xsd:element>\r\n\t\t\t\t</xsd:choice>\r\n\t\t\t</xsd:complexType>\r\n\t\t</xsd:element>\r\n\t</xsd:schema>\r\n\t<resheader name=\"ResMimeType\">\r\n\t\t<value>text/microsoft-resx</value>\r\n\t</resheader>\r\n\t<resheader name=\"Version\">\r\n\t\t<value>1.0.0.0</value>\r\n\t</resheader>\r\n\t<resheader name=\"Reader\">\r\n\t\t<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n\t</resheader>\r\n\t<resheader name=\"Writer\">\r\n\t\t<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n\t</resheader>\r\n</root>\r\n"
  },
  {
    "path": "Razor/Map/UOMapRuneButton.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Drawing;\r\nusing System.Collections;\r\nusing System.Windows.Forms;\r\n\r\nnamespace Assistant.MapUO\r\n{\r\n    class UOMapRuneButton\r\n    {\r\n        private int m_BookID;\r\n        private int m_RuneSpot;\r\n        private int m_X;\r\n        private int m_Y;\r\n        private Bitmap m_Icon;\r\n\r\n        public UOMapRuneButton(int bookid, int runeSpot, int x, int y)\r\n        {\r\n            this.m_BookID = bookid;\r\n            this.m_RuneSpot = runeSpot;\r\n            this.m_X = x;\r\n            this.m_Y = y;\r\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\r\n                this.m_Icon = Ultima.Art.GetStatic(7956);\r\n        }\r\n\r\n        public static ArrayList Load(string path)\r\n        {\r\n            ArrayList buttonlist = new ArrayList();\r\n            //if (!File.Exists(path))\r\n            // {\r\n            //    return buttonlist;\r\n            // }\r\n            buttonlist.Add(new UOMapRuneButton(0, 0, 1158, 743));\r\n            buttonlist.Add(new UOMapRuneButton(0, 0, 3230, 305));\r\n            //XML shit\r\n            return buttonlist;\r\n        }\r\n\r\n        public void OnClick(MouseEventArgs e)\r\n        {\r\n            switch (e.Button)\r\n            {\r\n                case MouseButtons.Left:\r\n                    //recall\r\n                    break;\r\n                case MouseButtons.Right:\r\n                    //gate\r\n                    break;\r\n            }\r\n        }\r\n\r\n        public int X\r\n        {\r\n            get { return m_X; }\r\n            set { m_X = value; }\r\n        }\r\n\r\n        public int Y\r\n        {\r\n            get { return m_Y; }\r\n            set { m_Y = value; }\r\n        }\r\n\r\n        public int BookID\r\n        {\r\n            get { return m_BookID; }\r\n            set { m_BookID = value; }\r\n        }\r\n\r\n        public int RuneSpot\r\n        {\r\n            get { return m_RuneSpot; }\r\n            set { m_RuneSpot = value; }\r\n        }\r\n\r\n        public Bitmap Icon\r\n        {\r\n            get { return m_Icon; }\r\n            set { m_Icon = value; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Network/Handlers.cs",
    "content": "#region license\r\n\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text.RegularExpressions;\r\nusing Assistant.Agents;\r\nusing Assistant.Core;\r\nusing Assistant.Filters;\r\nusing Assistant.Gumps;\r\nusing Assistant.Macros;\r\nusing Assistant.Scripts;\r\nusing Assistant.UI;\r\nusing Ultima;\r\n\r\nnamespace Assistant\r\n{\r\n    public class PacketHandlers\r\n    {\r\n        private static List<Item> _ignoreGumps = new List<Item>();\r\n\r\n        public static List<Item> IgnoreGumps => _ignoreGumps;\r\n\r\n        public static void Initialize()\r\n        {\r\n            //Client -> Server handlers\r\n            PacketHandler.RegisterClientToServerViewer(0x00, CreateCharacter);\r\n            //PacketHandler.RegisterClientToServerViewer(0x01, new PacketViewerCallback(Disconnect));\r\n            PacketHandler.RegisterClientToServerFilter(0x02, MovementRequest);\r\n            PacketHandler.RegisterClientToServerFilter(0x05, AttackRequest);\r\n            PacketHandler.RegisterClientToServerViewer(0x06, ClientDoubleClick);\r\n            PacketHandler.RegisterClientToServerViewer(0x07, LiftRequest);\r\n            PacketHandler.RegisterClientToServerViewer(0x08, DropRequest);\r\n            PacketHandler.RegisterClientToServerViewer(0x09, ClientSingleClick);\r\n            PacketHandler.RegisterClientToServerViewer(0x12, ClientTextCommand);\r\n            PacketHandler.RegisterClientToServerViewer(0x13, EquipRequest);\r\n            // 0x29 - UOKR confirm drop.  0 bytes payload (just a single byte, 0x29, no length or data)\r\n            PacketHandler.RegisterClientToServerViewer(0x3A, SetSkillLock);\r\n            PacketHandler.RegisterClientToServerViewer(0x5D, PlayCharacter);\r\n            PacketHandler.RegisterClientToServerViewer(0x7D, MenuResponse);\r\n            PacketHandler.RegisterClientToServerFilter(0x80, ServerListLogin);\r\n            PacketHandler.RegisterClientToServerFilter(0x91, GameLogin);\r\n            PacketHandler.RegisterClientToServerViewer(0x95, HueResponse);\r\n            PacketHandler.RegisterClientToServerViewer(0xA0, PlayServer);\r\n            PacketHandler.RegisterClientToServerViewer(0xB1, ClientGumpResponse);\r\n            PacketHandler.RegisterClientToServerFilter(0xBF, ExtendedClientCommand);\r\n            //PacketHandler.RegisterClientToServerViewer( 0xD6, new PacketViewerCallback( BatchQueryProperties ) );\r\n            PacketHandler.RegisterClientToServerFilter(0xC2, UnicodePromptSend);\r\n            PacketHandler.RegisterClientToServerViewer(0xD7, ClientEncodedPacket);\r\n            PacketHandler.RegisterClientToServerViewer(0xF8, CreateCharacter);\r\n\r\n            //Server -> Client handlers\r\n            PacketHandler.RegisterServerToClientViewer(0x0B, Damage);\r\n            PacketHandler.RegisterServerToClientViewer(0x11, MobileStatus);\r\n            PacketHandler.RegisterServerToClientViewer(0x17, NewMobileStatus);\r\n            PacketHandler.RegisterServerToClientViewer(0x1A, WorldItem);\r\n            PacketHandler.RegisterServerToClientViewer(0x1B, LoginConfirm);\r\n            PacketHandler.RegisterServerToClientViewer(0x55, CompleteLogin);\r\n            PacketHandler.RegisterServerToClientFilter(0x1C, AsciiSpeech);\r\n            PacketHandler.RegisterServerToClientViewer(0x1D, RemoveObject);\r\n            PacketHandler.RegisterServerToClientFilter(0x20, MobileUpdate);\r\n            PacketHandler.RegisterServerToClientViewer(0x24, BeginContainerContent);\r\n            PacketHandler.RegisterServerToClientFilter(0x25, ContainerContentUpdate);\r\n            PacketHandler.RegisterServerToClientViewer(0x27, LiftReject);\r\n            PacketHandler.RegisterServerToClientViewer(0x2D, MobileStatInfo);\r\n            PacketHandler.RegisterServerToClientFilter(0x2E, EquipmentUpdate);\r\n            PacketHandler.RegisterServerToClientViewer(0x3A, PlayerSkills);\r\n            PacketHandler.RegisterServerToClientFilter(0x3C, ContainerContent);\r\n            PacketHandler.RegisterServerToClientViewer(0x4E, PersonalLight);\r\n            PacketHandler.RegisterServerToClientViewer(0x4F, GlobalLight);\r\n            PacketHandler.RegisterServerToClientViewer(0x6F, TradeRequest);\r\n            PacketHandler.RegisterServerToClientViewer(0x72, ServerSetWarMode);\r\n            PacketHandler.RegisterServerToClientViewer(0x73, PingResponse);\r\n            PacketHandler.RegisterServerToClientViewer(0x76, ServerChange);\r\n            PacketHandler.RegisterServerToClientFilter(0x77, MobileMoving);\r\n            PacketHandler.RegisterServerToClientFilter(0x78, MobileIncoming);\r\n            PacketHandler.RegisterServerToClientViewer(0x7C, SendMenu);\r\n            PacketHandler.RegisterServerToClientFilter(0x8C, ServerAddress);\r\n            PacketHandler.RegisterServerToClientViewer(0xA1, HitsUpdate);\r\n            PacketHandler.RegisterServerToClientViewer(0xA2, ManaUpdate);\r\n            PacketHandler.RegisterServerToClientViewer(0xA3, StamUpdate);\r\n            PacketHandler.RegisterServerToClientViewer(0xA8, ServerList);\r\n            PacketHandler.RegisterServerToClientViewer(0xAB, DisplayStringQuery);\r\n            PacketHandler.RegisterServerToClientViewer(0xAF, DeathAnimation);\r\n            PacketHandler.RegisterServerToClientFilter(0xAE, UnicodeSpeech);\r\n            PacketHandler.RegisterServerToClientViewer(0xB0, SendGump);\r\n            PacketHandler.RegisterServerToClientViewer(0xB9, Features);\r\n            PacketHandler.RegisterServerToClientViewer(0xBC, ChangeSeason);\r\n            PacketHandler.RegisterServerToClientFilter(0xBE, OnAssistVersion);\r\n            PacketHandler.RegisterServerToClientViewer(0xBF, ExtendedPacket);\r\n            PacketHandler.RegisterServerToClientFilter(0xC1, OnLocalizedMessage);\r\n            PacketHandler.RegisterServerToClientFilter(0xC2, UnicodePromptReceived);\r\n            PacketHandler.RegisterServerToClientFilter(0xC8, SetUpdateRange);\r\n            PacketHandler.RegisterServerToClientFilter(0xCC, OnLocalizedMessageAffix);\r\n            PacketHandler.RegisterServerToClientViewer(0xD6, EncodedPacket); //0xD6 \"encoded\" packets\r\n            PacketHandler.RegisterServerToClientViewer(0xD8, CustomHouseInfo);\r\n            //PacketHandler.RegisterServerToClientFilter( 0xDC, new PacketFilterCallback( ServOPLHash ) );\r\n            PacketHandler.RegisterServerToClientViewer(0xDD, CompressedGump);\r\n            PacketHandler.RegisterServerToClientViewer(0xF0,\r\n                RunUOProtocolExtention); // Special RunUO protocol extentions (for KUOC/Razor)\r\n\r\n            PacketHandler.RegisterServerToClientViewer(0xF3, SAWorldItem);\r\n\r\n            PacketHandler.RegisterServerToClientViewer(0x2C, ResurrectionGump);\r\n\r\n            PacketHandler.RegisterServerToClientViewer(0xDF, BuffDebuff);\r\n\r\n            PacketHandler.RegisterServerToClientFilter(0x54, PlaySoundEffect);\r\n            PacketHandler.RegisterServerToClientFilter(0x6D, PlayMusic);\r\n        }\r\n\r\n        private static void DisplayStringQuery(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            // See also Packets.cs: StringQueryResponse\r\n            /*if ( MacroManager.AcceptActions )\r\n            {\r\n                 int serial = p.ReadInt32();\r\n                 byte type = p.ReadByte();\r\n                 byte index = p.ReadByte();\r\n\r\n                 MacroManager.Action( new WaitForTextEntryAction( serial, type, index ) );\r\n            }*/\r\n        }\r\n\r\n        private static void SetUpdateRange(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player != null)\r\n                World.Player.VisRange = p.ReadByte();\r\n        }\r\n\r\n        private static void EncodedPacket(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            /*ushort id = p.ReadUInt16();\r\n\r\n            switch ( id )\r\n            {\r\n                 case 1: // object property list\r\n                 {\r\n                      Serial s = p.ReadUInt32();\r\n\r\n                      if ( s.IsItem )\r\n                      {\r\n                           Item item = World.FindItem( s );\r\n                           if ( item == null )\r\n                                World.AddItem( item=new Item( s ) );\r\n\r\n                           item.ReadPropertyList( p );\r\n                           if ( item.ModifiedOPL )\r\n                           {\r\n                                args.Block = true;\r\n                                Client.Instance.SendToClient( item.ObjPropList.BuildPacket() );\r\n                           }\r\n                      }\r\n                      else if ( s.IsMobile )\r\n                      {\r\n                           Mobile m = World.FindMobile( s );\r\n                           if ( m == null )\r\n                                World.AddMobile( m=new Mobile( s ) );\r\n\r\n                           m.ReadPropertyList( p );\r\n                           if ( m.ModifiedOPL )\r\n                           {\r\n                                args.Block = true;\r\n                                Client.Instance.SendToClient( m.ObjPropList.BuildPacket() );\r\n                           }\r\n                      }\r\n                      break;\r\n                 }\r\n            }*/\r\n        }\r\n\r\n        private static void ServOPLHash(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            /*Serial s = p.ReadUInt32();\r\n            int hash = p.ReadInt32();\r\n\r\n            if ( s.IsItem )\r\n            {\r\n                 Item item = World.FindItem( s );\r\n                 if ( item != null && item.OPLHash != hash )\r\n                 {\r\n                      item.OPLHash = hash;\r\n                      p.Seek( -4, SeekOrigin.Current );\r\n                      p.Write( (uint)item.OPLHash );\r\n                 }\r\n            }\r\n            else if ( s.IsMobile )\r\n            {\r\n                 Mobile m = World.FindMobile( s );\r\n                 if ( m != null && m.OPLHash != hash )\r\n                 {\r\n                      m.OPLHash = hash;\r\n                      p.Seek( -4, SeekOrigin.Current );\r\n                      p.Write( (uint)m.OPLHash );\r\n                 }\r\n            }*/\r\n        }\r\n\r\n        private static void ClientSingleClick(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial ser = p.ReadUInt32();\r\n\r\n            Mobile m = World.FindMobile(ser);\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            // if you modify this, don't forget to modify the allnames hotkey\r\n            if (Config.GetBool(\"LastTargTextFlags\"))\r\n                Targeting.CheckTextFlags(m);\r\n\r\n            FriendsManager.ShowOverhead(m);\r\n        }\r\n\r\n        private static void ClientDoubleClick(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial ser = p.ReadUInt32();\r\n            if (Config.GetBool(\"BlockDismount\") && World.Player != null && ser == World.Player.Serial &&\r\n                World.Player.Warmode && World.Player.GetItemOnLayer(Layer.Mount) != null)\r\n            {\r\n                // mount layer = 0x19\r\n                World.Player.SendMessage(LocString.DismountBlocked);\r\n                args.Block = true;\r\n                return;\r\n            }\r\n\r\n            if (Config.GetBool(\"QueueActions\"))\r\n                args.Block = !PlayerData.DoubleClick(ser, false);\r\n\r\n            if (ser.IsItem && World.Player != null)\r\n                World.Player.LastObject = ser;\r\n\r\n            if (Macros.MacroManager.AcceptActions || ScriptManager.Recording)\r\n            {\r\n                ushort gfx = 0;\r\n                if (ser.IsItem)\r\n                {\r\n                    Item i = World.FindItem(ser);\r\n                    if (i != null)\r\n                        gfx = i.ItemID;\r\n                }\r\n                else\r\n                {\r\n                    Mobile m = World.FindMobile(ser);\r\n                    if (m != null)\r\n                        gfx = m.Body;\r\n                }\r\n\r\n                if (gfx != 0)\r\n                {\r\n                    MacroManager.Action(new DoubleClickAction(ser, gfx));\r\n\r\n                    ScriptManager.AddToScript($\"dclick {ser}\");\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void DeathAnimation(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial killed = p.ReadUInt32();\r\n            Mobile m = World.FindMobile(killed);\r\n\r\n            if (Config.GetBool(\"CaptureOthersDeath\"))\r\n            {\r\n                if (m != null && ((m.Body >= 0x0190 && m.Body <= 0x0193) || (m.Body >= 0x025D && m.Body <= 0x0260)) &&\r\n                    Utility.Distance(World.Player.Position, m.Position) <= 12)\r\n                {\r\n                    if (!string.IsNullOrEmpty(m.Name))\r\n                        ScreenCapManager.LastMobileDeathName = m.Name;\r\n\r\n                    ScreenCapManager.DeathCapture(Config.GetDouble(\"CaptureOthersDeathDelay\"));\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ExtendedClientCommand(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            ushort ext = p.ReadUInt16();\r\n            switch (ext)\r\n            {\r\n                case 0x10: // query object properties\r\n                {\r\n                    break;\r\n                }\r\n\r\n                case 0x15: // context menu response\r\n                {\r\n                    UOEntity ent = null;\r\n                    Serial ser = p.ReadUInt32();\r\n                    ushort idx = p.ReadUInt16();\r\n\r\n                    if (ser.IsMobile)\r\n                        ent = World.FindMobile(ser);\r\n                    else if (ser.IsItem)\r\n                        ent = World.FindItem(ser);\r\n\r\n                    if (ent != null && ent.ContextMenu != null)\r\n                    {\r\n                        if (MacroManager.AcceptActions)\r\n                        {\r\n                            try\r\n                            {\r\n                                MacroManager.Action(new ContextMenuAction(ent, idx, ent.ContextMenu[idx].Value));\r\n                            }\r\n                            catch\r\n                            {\r\n                                // ignored\r\n                            }\r\n                        }\r\n\r\n                        if (ScriptManager.Recording)\r\n                        {\r\n                            try\r\n                            {\r\n                                ScriptManager.AddToScript(ent.Serial == World.Player.Serial\r\n                                    ? $\"menu 'self' {idx}\"\r\n                                    : $\"menu {ent.Serial} {idx}\");\r\n                            }\r\n                            catch\r\n                            {\r\n                                // ignored\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x1C: // cast spell\r\n                {\r\n                    Serial ser = Serial.MinusOne;\r\n                    if (p.ReadUInt16() == 1)\r\n                        ser = p.ReadUInt32();\r\n                    ushort sid = p.ReadUInt16();\r\n                    Spell s = Spell.Get(sid);\r\n                    if (s != null)\r\n                    {\r\n                        s.OnCast(p);\r\n                        args.Block = true;\r\n\r\n                        if (Macros.MacroManager.AcceptActions)\r\n                            MacroManager.Action(new ExtCastSpellAction(s, ser));\r\n\r\n                        ScriptManager.AddToScript($\"cast '{Spell.GetName(sid)}'\");\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x24:\r\n                {\r\n                    // for the cheatx0r part 2...  anything outside this range indicates some haxing, just hide it with 0x30s\r\n                    byte b = p.ReadByte();\r\n                    if (b < 0x25 || b >= 0x5E + 0x25)\r\n                    {\r\n                        p.Seek(-1, SeekOrigin.Current);\r\n                        p.Write((byte) 0x30);\r\n                    }\r\n\r\n                    //using ( StreamWriter w = new StreamWriter( \"bf24.txt\", true ) )\r\n                    //\tw.WriteLine( \"{0} : 0x{1:X2}\", Engine.MistedDateTime.ToString( \"HH:mm:ss.ffff\" ), b );\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ClientTextCommand(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            int type = p.ReadByte();\r\n            string command = p.ReadString();\r\n\r\n            switch (type)\r\n            {\r\n                case 0x24: // Use skill\r\n                {\r\n                    int skillIndex;\r\n\r\n                    try\r\n                    {\r\n                        skillIndex = Convert.ToInt32(command.Split(' ')[0]);\r\n                    }\r\n                    catch\r\n                    {\r\n                        break;\r\n                    }\r\n\r\n                    if (World.Player != null)\r\n                        World.Player.LastSkill = skillIndex;\r\n\r\n                    if (MacroManager.AcceptActions)\r\n                        MacroManager.Action(new UseSkillAction(skillIndex));\r\n\r\n                    if (Skills.SkillsByIndex.TryGetValue(skillIndex, out SkillInfo skill))\r\n                    {\r\n                        ScriptManager.AddToScript($\"skill '{skill.Name}'\");\r\n                    }\r\n\r\n                    if (World.Player != null && (skillIndex == Skills.StealthIndex && !World.Player.Visible))\r\n                        StealthSteps.Hide();\r\n\r\n                    SkillTimer.Start();\r\n                    break;\r\n                }\r\n\r\n                case 0x27: // Cast spell from book\r\n                {\r\n                    try\r\n                    {\r\n                        string[] split = command.Split(' ');\r\n\r\n                        if (split.Length > 0)\r\n                        {\r\n                            ushort spellID = Convert.ToUInt16(split[0]);\r\n                            Serial serial = Convert.ToUInt32(split.Length > 1 ? Utility.ToInt32(split[1], -1) : -1);\r\n                            Spell s = Spell.Get(spellID);\r\n                            if (s != null)\r\n                            {\r\n                                s.OnCast(p);\r\n                                args.Block = true;\r\n                                if (Macros.MacroManager.AcceptActions)\r\n                                    MacroManager.Action(new BookCastSpellAction(s, serial));\r\n\r\n                                ScriptManager.AddToScript($\"cast '{Spell.GetName(spellID)}'\");\r\n                            }\r\n                        }\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x56: // Cast spell from macro\r\n                {\r\n                    try\r\n                    {\r\n                        ushort spellID = Convert.ToUInt16(command);\r\n                        Spell s = Spell.Get(spellID);\r\n                        if (s != null)\r\n                        {\r\n                            s.OnCast(p);\r\n                            args.Block = true;\r\n                            if (Macros.MacroManager.AcceptActions)\r\n                                MacroManager.Action(new MacroCastSpellAction(s));\r\n\r\n                            ScriptManager.AddToScript($\"cast '{Spell.GetName(spellID)}'\");\r\n                        }\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        public static DateTime PlayCharTime = DateTime.MinValue;\r\n\r\n        private static void CreateCharacter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            p.Seek(1 + 4 + 4 + 1, SeekOrigin.Begin); // skip begining crap\r\n            World.OrigPlayerName = p.ReadStringSafe(30);\r\n\r\n            PlayCharTime = DateTime.UtcNow;\r\n\r\n            if (Engine.MainWindow != null)\r\n                Engine.MainWindow.SafeAction(s => s.UpdateControlLocks());\r\n        }\r\n\r\n        private static void PlayCharacter(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            p.ReadUInt32(); //0xedededed\r\n            World.OrigPlayerName = p.ReadStringSafe(30);\r\n\r\n            PlayCharTime = DateTime.UtcNow;\r\n\r\n            if (Engine.MainWindow != null)\r\n                Engine.MainWindow.SafeAction(s => s.UpdateControlLocks());\r\n\r\n            //Client.TranslateLogin( World.OrigPlayerName, World.ShardName );\r\n        }\r\n\r\n        private static void ServerList(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            p.ReadByte(); //unknown\r\n            ushort numServers = p.ReadUInt16();\r\n\r\n            for (int i = 0; i < numServers; ++i)\r\n            {\r\n                ushort num = p.ReadUInt16();\r\n                World.Servers[num] = p.ReadString(32);\r\n                p.ReadByte(); // full %\r\n                p.ReadSByte(); // time zone\r\n                p.ReadUInt32(); // ip\r\n            }\r\n        }\r\n\r\n        private static void PlayServer(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            ushort index = p.ReadUInt16();\r\n            string name;\r\n            if (World.Servers.TryGetValue(index, out name) && !string.IsNullOrEmpty(name))\r\n                World.ShardName = name;\r\n            else\r\n                World.ShardName = \"[Unknown]\";\r\n        }\r\n\r\n        private static void LiftRequest(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n            ushort amount = p.ReadUInt16();\r\n\r\n            Item item = World.FindItem(serial);\r\n            ushort iid = 0;\r\n\r\n            if (item != null)\r\n                iid = item.ItemID.Value;\r\n\r\n            if (Config.GetBool(\"QueueActions\"))\r\n            {\r\n                if (item == null)\r\n                {\r\n                    World.AddItem(item = new Item(serial));\r\n                    item.Amount = amount;\r\n                }\r\n\r\n                DragDropManager.Drag(item, amount, true);\r\n                //Client.Instance.SendToClient( new RemoveObject( serial ) ); // remove the object from the client view\r\n                args.Block = true;\r\n            }\r\n\r\n            if (Macros.MacroManager.AcceptActions)\r\n            {\r\n                MacroManager.Action(new LiftAction(serial, amount, iid));\r\n                //MacroManager.Action( new PauseAction( TimeSpan.FromMilliseconds( Config.GetInt( \"ObjectDelay\" ) ) ) );\r\n            }\r\n\r\n            ScriptManager.AddToScript($\"lift {serial} {amount}\");\r\n        }\r\n\r\n        private static void LiftReject(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            /*\r\n            if ( ActionQueue.FilterLiftReject() )\r\n                 args.Block = true;\r\n            */\r\n            int reason = p.ReadByte();\r\n\r\n            if (!DragDropManager.LiftReject())\r\n                args.Block = true;\r\n            //MacroManager.PlayError( MacroError.LiftRej );\r\n        }\r\n\r\n        private static void EquipRequest(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial iser = p.ReadUInt32(); // item being dropped serial\r\n            Layer layer = (Layer) p.ReadByte();\r\n            Serial mser = p.ReadUInt32();\r\n\r\n            Item item = World.FindItem(iser);\r\n\r\n            if (MacroManager.AcceptActions || ScriptManager.Recording)\r\n            {\r\n                if (layer == Layer.Invalid || layer > Layer.LastValid)\r\n                {\r\n                    if (item != null)\r\n                    {\r\n                        layer = item.Layer;\r\n                        if (layer == Layer.Invalid || layer > Layer.LastValid)\r\n                            layer = (Layer) item.ItemID.ItemData.Quality;\r\n                    }\r\n                }\r\n\r\n                if (layer > Layer.Invalid && layer <= Layer.LastUserValid)\r\n                {\r\n                    if (MacroManager.AcceptActions)\r\n                        MacroManager.Action(new DropAction(mser, Point3D.Zero, layer));\r\n\r\n                    ScriptManager.AddToScript($\"drop {mser} {layer}\");\r\n                }\r\n            }\r\n\r\n            if (item == null)\r\n                return;\r\n\r\n            Mobile m = World.FindMobile(mser);\r\n            if (m == null)\r\n                return;\r\n\r\n            if (Config.GetBool(\"QueueActions\"))\r\n                args.Block = DragDropManager.Drop(item, m, layer);\r\n        }\r\n\r\n        private static void DropRequest(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial iser = p.ReadUInt32();\r\n            int x = p.ReadInt16();\r\n            int y = p.ReadInt16();\r\n            int z = p.ReadSByte();\r\n            if (Engine.UsePostKRPackets)\r\n                /* grid num */\r\n                p.ReadByte();\r\n            Point3D newPos = new Point3D(x, y, z);\r\n            Serial dser = p.ReadUInt32();\r\n\r\n            if (Macros.MacroManager.AcceptActions)\r\n                MacroManager.Action(new DropAction(dser, newPos));\r\n\r\n            ScriptManager.AddToScript($\"drop {dser} {newPos.X} {newPos.Y} {newPos.Z}\");\r\n\r\n            Item i = World.FindItem(iser);\r\n            if (i == null)\r\n                return;\r\n\r\n            Item dest = World.FindItem(dser);\r\n            if (dest != null && dest.IsContainer && World.Player != null &&\r\n                (dest.IsChildOf(World.Player.Backpack) || dest.IsChildOf(World.Player.Quiver)))\r\n                i.IsNew = true;\r\n\r\n            if (Config.GetBool(\"QueueActions\"))\r\n                args.Block = DragDropManager.Drop(i, dser, newPos);\r\n        }\r\n\r\n        private static void MovementRequest(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                Direction dir = (Direction) p.ReadByte();\r\n                byte seq = p.ReadByte();\r\n\r\n                World.Player.Direction = (dir & Direction.Mask);\r\n\r\n                WalkAction.LastWalkTime = DateTime.UtcNow;\r\n                if (MacroManager.AcceptActions)\r\n                    MacroManager.Action(new WalkAction(dir));\r\n\r\n                ScriptManager.AddToScript($\"walk '{dir}'\");\r\n            }\r\n        }\r\n\r\n        private static void ContainerContentUpdate(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            // This function will ignore the item if the container item has not been sent to the client yet.\r\n            // We can do this because we can't really count on getting all of the container info anyway.\r\n            // (So we'd need to request the container be updated, so why bother with the extra stuff required to find the container once its been sent?)\r\n            Serial serial = p.ReadUInt32();\r\n            ushort itemid = p.ReadUInt16();\r\n            itemid = (ushort) (itemid + p.ReadSByte()); // signed, itemID offset\r\n            ushort amount = p.ReadUInt16();\r\n            if (amount == 0)\r\n                amount = 1;\r\n            Point3D pos = new Point3D(p.ReadUInt16(), p.ReadUInt16(), 0);\r\n            byte gridPos = 0;\r\n            if (Engine.UsePostKRPackets)\r\n                gridPos = p.ReadByte();\r\n            Serial cser = p.ReadUInt32();\r\n            ushort hue = p.ReadUInt16();\r\n\r\n            Item i = World.FindItem(serial);\r\n            if (i == null)\r\n            {\r\n                if (!serial.IsItem)\r\n                    return;\r\n\r\n                World.AddItem(i = new Item(serial));\r\n                i.IsNew = i.AutoStack = true;\r\n            }\r\n            else\r\n            {\r\n                i.CancelRemove();\r\n            }\r\n\r\n            if (serial != DragDropManager.Pending)\r\n            {\r\n                if (!DragDropManager.EndHolding(serial))\r\n                    return;\r\n            }\r\n\r\n            i.ItemID = itemid;\r\n            i.Amount = amount;\r\n            i.Position = pos;\r\n            i.GridNum = gridPos;\r\n            i.Hue = hue;\r\n\r\n            if (SearchExemptionAgent.Contains(i))\r\n            {\r\n                p.Seek(-2, System.IO.SeekOrigin.Current);\r\n                p.Write((short) Config.GetInt(\"ExemptColor\"));\r\n            }\r\n\r\n            i.Container = cser;\r\n            if (i.IsNew)\r\n                Item.UpdateContainers();\r\n            if (!SearchExemptionAgent.IsExempt(i) &&\r\n                (i.IsChildOf(World.Player.Backpack) || i.IsChildOf(World.Player.Quiver)))\r\n                Counter.Count(i);\r\n        }\r\n\r\n        private static void BeginContainerContent(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial ser = p.ReadUInt32();\r\n            if (!ser.IsItem)\r\n                return;\r\n            Item item = World.FindItem(ser);\r\n            if (item != null)\r\n            {\r\n                if (_ignoreGumps.Contains(item))\r\n                {\r\n                    _ignoreGumps.Remove(item);\r\n                    args.Block = true;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                World.AddItem(new Item(ser));\r\n                Item.UpdateContainers();\r\n            }\r\n        }\r\n\r\n        private static void ContainerContent(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            int count = p.ReadUInt16();\r\n\r\n            for (int i = 0; i < count; i++)\r\n            {\r\n                Serial serial = p.ReadUInt32();\r\n                // serial is purposely not checked to be valid, sometimes buy lists dont have \"valid\" item serials (and we are okay with that).\r\n                Item item = World.FindItem(serial);\r\n                if (item == null)\r\n                {\r\n                    World.AddItem(item = new Item(serial));\r\n                    item.IsNew = true;\r\n                    item.AutoStack = false;\r\n                }\r\n                else\r\n                {\r\n                    item.CancelRemove();\r\n                }\r\n\r\n                if (!DragDropManager.EndHolding(serial))\r\n                    continue;\r\n\r\n                item.ItemID = p.ReadUInt16();\r\n                item.ItemID = (ushort) (item.ItemID + p.ReadSByte()); // signed, itemID offset\r\n                item.Amount = p.ReadUInt16();\r\n                if (item.Amount == 0)\r\n                    item.Amount = 1;\r\n                item.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), 0);\r\n                if (Engine.UsePostKRPackets)\r\n                    item.GridNum = p.ReadByte();\r\n                Serial cont = p.ReadUInt32();\r\n                item.Hue = p.ReadUInt16();\r\n                if (SearchExemptionAgent.Contains(item))\r\n                {\r\n                    p.Seek(-2, System.IO.SeekOrigin.Current);\r\n                    p.Write((short) Config.GetInt(\"ExemptColor\"));\r\n                }\r\n\r\n                item.Container = cont; // must be done after hue is set (for counters)\r\n                if (World.Player != null && !SearchExemptionAgent.IsExempt(item) &&\r\n                    (item.IsChildOf(World.Player.Backpack) || item.IsChildOf(World.Player.Quiver)))\r\n                    Counter.Count(item);\r\n            }\r\n\r\n            Item.UpdateContainers();\r\n        }\r\n\r\n        private static void EquipmentUpdate(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n\r\n            Item i = World.FindItem(serial);\r\n            bool isNew = false;\r\n            if (i == null)\r\n            {\r\n                World.AddItem(i = new Item(serial));\r\n                isNew = true;\r\n                Item.UpdateContainers();\r\n            }\r\n            else\r\n            {\r\n                i.CancelRemove();\r\n            }\r\n\r\n            if (!DragDropManager.EndHolding(serial))\r\n                return;\r\n\r\n            ushort iid = p.ReadUInt16();\r\n            i.ItemID = (ushort) (iid + p.ReadSByte()); // signed, itemID offset\r\n            i.Layer = (Layer) p.ReadByte();\r\n            Serial ser = p.ReadUInt32(); // cont must be set after hue (for counters)\r\n            i.Hue = p.ReadUInt16();\r\n\r\n            i.Container = ser;\r\n\r\n            int ltHue = Config.GetInt(\"LTHilight\");\r\n            if (ltHue != 0 && Targeting.IsLastTarget(i.Container as Mobile))\r\n            {\r\n                p.Seek(-2, SeekOrigin.Current);\r\n                p.Write((ushort) (ltHue & 0x3FFF));\r\n            }\r\n\r\n            if (i.Layer == Layer.Backpack && isNew && Config.GetBool(\"AutoSearch\") && ser == World.Player.Serial)\r\n            {\r\n                _ignoreGumps.Add(i);\r\n                PlayerData.DoubleClick(i);\r\n            }\r\n        }\r\n\r\n        private static void SetSkillLock(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            int i = p.ReadUInt16();\r\n\r\n            if (i >= 0 && i < Skills.TotalSkills())\r\n            {\r\n                Skill skill = World.Player.Skills[i];\r\n\r\n                skill.Lock = (LockType) p.ReadByte();\r\n                Engine.MainWindow.SafeAction(s => s.UpdateSkill(skill));\r\n            }\r\n        }\r\n\r\n        private static void PlayerSkills(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null || World.Player.Skills == null || Engine.MainWindow == null)\r\n                return;\r\n            byte type = p.ReadByte();\r\n\r\n            switch (type)\r\n            {\r\n                case 0x02: //list (with caps, 3.0.8 and up)\r\n                {\r\n                    int i;\r\n                    while ((i = p.ReadUInt16()) > 0)\r\n                    {\r\n                        if (i > 0 && i <= Skills.TotalSkills())\r\n                        {\r\n                            Skill skill = World.Player.Skills[i - 1];\r\n\r\n                            if (skill == null)\r\n                                continue;\r\n\r\n                            skill.FixedValue = p.ReadUInt16();\r\n                            skill.FixedBase = p.ReadUInt16();\r\n                            skill.Lock = (LockType) p.ReadByte();\r\n                            skill.FixedCap = p.ReadUInt16();\r\n                            if (!World.Player.SkillsSent)\r\n                                skill.Delta = 0;\r\n\r\n                            UOAssist.PostSkillUpdate(i - 1, skill.FixedBase);\r\n                        }\r\n                        else\r\n                        {\r\n                            p.Seek(7, SeekOrigin.Current);\r\n                        }\r\n                    }\r\n\r\n                    World.Player.SkillsSent = true;\r\n                    Engine.MainWindow.SafeAction(s => s.RedrawSkills());\r\n                    break;\r\n                }\r\n\r\n                case 0x00: // list (without caps, older clients)\r\n                {\r\n                    int i;\r\n                    while ((i = p.ReadUInt16()) > 0)\r\n                    {\r\n                        if (i > 0 && i <= Skills.TotalSkills())\r\n                        {\r\n                            Skill skill = World.Player.Skills[i - 1];\r\n\r\n                            if (skill == null)\r\n                                continue;\r\n\r\n                            skill.FixedValue = p.ReadUInt16();\r\n                            skill.FixedBase = p.ReadUInt16();\r\n                            skill.Lock = (LockType) p.ReadByte();\r\n                            skill.FixedCap = 100; //p.ReadUInt16();\r\n                            if (!World.Player.SkillsSent)\r\n                                skill.Delta = 0;\r\n\r\n                            UOAssist.PostSkillUpdate(i - 1, skill.FixedBase);\r\n                        }\r\n                        else\r\n                        {\r\n                            p.Seek(5, SeekOrigin.Current);\r\n                        }\r\n                    }\r\n\r\n                    World.Player.SkillsSent = true;\r\n                    Engine.MainWindow.SafeAction(s => s.RedrawSkills());\r\n                    break;\r\n                }\r\n\r\n                case 0xDF: //change (with cap, new clients)\r\n                {\r\n                    int i = p.ReadUInt16();\r\n\r\n                    if (i >= 0 && i < Skills.TotalSkills())\r\n                    {\r\n                        Skill skill = World.Player.Skills[i];\r\n\r\n                        if (skill == null)\r\n                            break;\r\n\r\n                        ushort old = skill.FixedBase;\r\n                        skill.FixedValue = p.ReadUInt16();\r\n                        skill.FixedBase = p.ReadUInt16();\r\n                        skill.Lock = (LockType) p.ReadByte();\r\n                        skill.FixedCap = p.ReadUInt16();\r\n                        Engine.MainWindow.SafeAction(s => s.UpdateSkill(skill));\r\n\r\n                        //Your skill in {0} has changed by {4}{5:F1}, it is now {3:F1} ({1}{2:F1}).\r\n                        if (Config.GetBool(\"DisplaySkillChanges\") && skill.FixedBase != old)\r\n                        {\r\n                            if (Config.GetBool(\"DisplaySkillChangesOverhead\"))\r\n                            {\r\n                                World.Player.OverheadMessage(LocString.SkillChangeOverhead,\r\n                                    Skills.GetSkillDisplayName(i),\r\n                                    skill.Delta > 0 ? \"+\" : \"\", skill.Delta, skill.Value,\r\n                                    skill.FixedBase - old > 0 ? \"+\" : \"\",\r\n                                    (skill.FixedBase - old) / 10.0);\r\n                            }\r\n                            else\r\n                            {\r\n                                World.Player.SendMessage(MsgLevel.Force, LocString.SkillChanged,\r\n                                    Skills.GetSkillDisplayName(i),\r\n                                    skill.Delta > 0 ? \"+\" : \"\", skill.Delta, skill.Value,\r\n                                    skill.FixedBase - old > 0 ? \"+\" : \"\", ((double) (skill.FixedBase - old)) / 10.0);\r\n                            }\r\n                        }\r\n\r\n                        UOAssist.PostSkillUpdate(i, skill.FixedBase);\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0xFF: //change (without cap, older clients)\r\n                {\r\n                    int i = p.ReadUInt16();\r\n\r\n                    if (i >= 0 && i < Skills.TotalSkills())\r\n                    {\r\n                        Skill skill = World.Player.Skills[i];\r\n\r\n                        if (skill == null)\r\n                            break;\r\n\r\n                        ushort old = skill.FixedBase;\r\n                        skill.FixedValue = p.ReadUInt16();\r\n                        skill.FixedBase = p.ReadUInt16();\r\n                        skill.Lock = (LockType) p.ReadByte();\r\n                        skill.FixedCap = 100;\r\n                        Engine.MainWindow.SafeAction(s => s.UpdateSkill(skill));\r\n                        if (Config.GetBool(\"DisplaySkillChanges\") && skill.FixedBase != old)\r\n                        {\r\n                            if (Config.GetBool(\"DisplaySkillChangesOverhead\"))\r\n                            {\r\n                                World.Player.OverheadMessage(LocString.SkillChangeOverhead,\r\n                                    Skills.GetSkillDisplayName(i),\r\n                                    skill.Delta > 0 ? \"+\" : \"\", skill.Delta, skill.Value,\r\n                                    skill.FixedBase - old > 0 ? \"+\" : \"\",\r\n                                    (skill.FixedBase - old) / 10.0);\r\n                            }\r\n                            else\r\n                            {\r\n                                World.Player.SendMessage(MsgLevel.Force, LocString.SkillChanged,\r\n                                    Skills.GetSkillDisplayName(i),\r\n                                    skill.Delta > 0 ? \"+\" : \"\", skill.Delta, skill.Value,\r\n                                    ((double) (skill.FixedBase - old)) / 10.0, skill.FixedBase - old > 0 ? \"+\" : \"\");\r\n                            }\r\n                        }\r\n\r\n                        UOAssist.PostSkillUpdate(i, skill.FixedBase);\r\n                    }\r\n\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void LoginConfirm(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            World.Items.Clear();\r\n            World.Mobiles.Clear();\r\n\r\n            UseNewStatus = false;\r\n\r\n            Serial serial = p.ReadUInt32();\r\n\r\n            PlayerData m = new PlayerData(serial);\r\n            m.Name = World.OrigPlayerName;\r\n\r\n            Mobile test = World.FindMobile(serial);\r\n            if (test != null)\r\n                test.Remove();\r\n\r\n            World.AddMobile(World.Player = m);\r\n            Config.LoadProfileFor(World.Player);\r\n\r\n            p.ReadUInt32(); // always 0?\r\n            m.Body = p.ReadUInt16();\r\n            m.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadInt16());\r\n            m.Direction = (Direction) p.ReadByte();\r\n\r\n            Client.Instance.RequestTitlebarUpdate();\r\n            UOAssist.PostLogin((int) serial.Value);\r\n            Engine.MainWindow.SafeAction(s => s.UpdateTitle()); // update player name & shard name\r\n\r\n            Client.Instance.SetPosition((uint) m.Position.X, (uint) m.Position.Y, (uint) m.Position.Z,\r\n                (byte) m.Direction);\r\n\r\n            if (World.Player != null)\r\n                World.Player.SetSeason();\r\n            \r\n            ScriptManager.OnLogin();\r\n        }\r\n\r\n        private static void CompleteLogin(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            // Set the default min light level if they have limits set\r\n            if (World.Player != null)\r\n                EnforceLightLevels(-1);\r\n        }\r\n\r\n        private static void MobileMoving(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n            Mobile m = World.FindMobile(serial);\r\n\r\n            if (m == null)\r\n            {\r\n                World.AddMobile(m = new Mobile(serial));\r\n                World.RequestMobileStatus(m);\r\n            }\r\n\r\n            if (m != null)\r\n            {\r\n                m.Body = p.ReadUInt16();\r\n\r\n                MobileFilter.Apply(p, m);\r\n\r\n                m.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadSByte());\r\n\r\n                if (World.Player != null && !Utility.InRange(World.Player.Position, m.Position, World.Player.VisRange))\r\n                {\r\n                    m.Remove();\r\n                    return;\r\n                }\r\n\r\n                Targeting.CheckLastTargetRange(m);\r\n\r\n                m.Direction = (Direction) p.ReadByte();\r\n                m.Hue = p.ReadUInt16();\r\n                int ltHue = Config.GetInt(\"LTHilight\");\r\n                if (ltHue != 0 && Targeting.IsLastTarget(m))\r\n                {\r\n                    p.Seek(-2, SeekOrigin.Current);\r\n                    p.Write((short) (ltHue | 0x8000));\r\n                }\r\n\r\n                bool wasPoisoned = m.Poisoned;\r\n                m.ProcessPacketFlags(p.ReadByte());\r\n                byte oldNoto = m.Notoriety;\r\n                m.Notoriety = p.ReadByte();\r\n\r\n                if (m == World.Player)\r\n                {\r\n                    Client.Instance.SetPosition((uint) m.Position.X, (uint) m.Position.Y, (uint) m.Position.Z,\r\n                        (byte) m.Direction);\r\n\r\n                    if (wasPoisoned != m.Poisoned || (oldNoto != m.Notoriety && Config.GetBool(\"ShowNotoHue\")))\r\n                        Client.Instance.RequestTitlebarUpdate();\r\n                }\r\n            }\r\n        }\r\n\r\n        private static readonly int[] HealthHues = new int[] {428, 333, 37, 44, 49, 53, 158, 263, 368, 473, 578};\r\n\r\n        private static void HitsUpdate(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Mobile m = World.FindMobile(p.ReadUInt32());\r\n\r\n            if (m != null)\r\n            {\r\n                int oldPercent = (int) (m.Hits * 100 / (m.HitsMax == 0 ? (ushort) 1 : m.HitsMax));\r\n\r\n                m.HitsMax = p.ReadUInt16();\r\n                m.Hits = p.ReadUInt16();\r\n\r\n                if (m == World.Player)\r\n                {\r\n                    Client.Instance.RequestTitlebarUpdate();\r\n                    UOAssist.PostHitsUpdate();\r\n                }\r\n\r\n                if (Client.Instance.AllowBit(FeatureBit.OverheadHealth) && Config.GetBool(\"ShowHealth\"))\r\n                {\r\n                    int percent = (int) (m.Hits * 100 / (m.HitsMax == 0 ? (ushort) 1 : m.HitsMax));\r\n\r\n                    // Limit to people who are on screen and check the previous value so we dont get spammed.\r\n                    if (oldPercent != percent && World.Player != null &&\r\n                        Utility.Distance(World.Player.Position, m.Position) <= 12)\r\n                    {\r\n                        try\r\n                        {\r\n                            m.OverheadMessageFrom(HealthHues[((percent + 5) / 10) % HealthHues.Length],\r\n                                m.Name ?? string.Empty,\r\n                                Config.GetString(\"HealthFmt\"), percent);\r\n                        }\r\n                        catch\r\n                        {\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void StamUpdate(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Mobile m = World.FindMobile(p.ReadUInt32());\r\n\r\n            if (m != null)\r\n            {\r\n                int oldPercent = (int) (m.Stam * 100 / (m.StamMax == 0 ? (ushort) 1 : m.StamMax));\r\n\r\n                m.StamMax = p.ReadUInt16();\r\n                m.Stam = p.ReadUInt16();\r\n\r\n                if (m == World.Player)\r\n                {\r\n                    Client.Instance.RequestTitlebarUpdate();\r\n                    UOAssist.PostStamUpdate();\r\n                }\r\n\r\n                if (m != World.Player && Client.Instance.AllowBit(FeatureBit.OverheadHealth) &&\r\n                    Config.GetBool(\"ShowPartyStats\"))\r\n                {\r\n                    int stamPercent = (int) (m.Stam * 100 / (m.StamMax == 0 ? (ushort) 1 : m.StamMax));\r\n                    int manaPercent = (int) (m.Mana * 100 / (m.ManaMax == 0 ? (ushort) 1 : m.ManaMax));\r\n\r\n                    // Limit to people who are on screen and check the previous value so we dont get spammed.\r\n                    if (oldPercent != stamPercent && World.Player != null &&\r\n                        Utility.Distance(World.Player.Position, m.Position) <= 12)\r\n                    {\r\n                        try\r\n                        {\r\n                            m.OverheadMessageFrom(0x63,\r\n                                m.Name ?? string.Empty,\r\n                                Config.GetString(\"PartyStatFmt\"), manaPercent, stamPercent);\r\n                        }\r\n                        catch\r\n                        {\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ManaUpdate(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Mobile m = World.FindMobile(p.ReadUInt32());\r\n\r\n            if (m != null)\r\n            {\r\n                int oldPercent = (int) (m.Mana * 100 / (m.ManaMax == 0 ? (ushort) 1 : m.ManaMax));\r\n\r\n                m.ManaMax = p.ReadUInt16();\r\n                m.Mana = p.ReadUInt16();\r\n\r\n                if (m == World.Player)\r\n                {\r\n                    Client.Instance.RequestTitlebarUpdate();\r\n                    UOAssist.PostManaUpdate();\r\n                }\r\n\r\n                if (m != World.Player && Client.Instance.AllowBit(FeatureBit.OverheadHealth) &&\r\n                    Config.GetBool(\"ShowPartyStats\"))\r\n                {\r\n                    int stamPercent = (int) (m.Stam * 100 / (m.StamMax == 0 ? (ushort) 1 : m.StamMax));\r\n                    int manaPercent = (int) (m.Mana * 100 / (m.ManaMax == 0 ? (ushort) 1 : m.ManaMax));\r\n\r\n                    // Limit to people who are on screen and check the previous value so we dont get spammed.\r\n                    if (oldPercent != manaPercent && World.Player != null &&\r\n                        Utility.Distance(World.Player.Position, m.Position) <= 12)\r\n                    {\r\n                        try\r\n                        {\r\n                            m.OverheadMessageFrom(0x63,\r\n                                Language.Format(LocString.sStatsA1, m.Name),\r\n                                Config.GetString(\"PartyStatFmt\"), manaPercent, stamPercent);\r\n                        }\r\n                        catch\r\n                        {\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void MobileStatInfo(PacketReader pvSrc, PacketHandlerEventArgs args)\r\n        {\r\n            Mobile m = World.FindMobile(pvSrc.ReadUInt32());\r\n            if (m == null)\r\n                return;\r\n            PlayerData p = World.Player;\r\n\r\n            m.HitsMax = pvSrc.ReadUInt16();\r\n            m.Hits = pvSrc.ReadUInt16();\r\n\r\n            m.ManaMax = pvSrc.ReadUInt16();\r\n            m.Mana = pvSrc.ReadUInt16();\r\n\r\n            m.StamMax = pvSrc.ReadUInt16();\r\n            m.Stam = pvSrc.ReadUInt16();\r\n\r\n            if (m == World.Player)\r\n            {\r\n                Client.Instance.RequestTitlebarUpdate();\r\n                UOAssist.PostHitsUpdate();\r\n                UOAssist.PostStamUpdate();\r\n                UOAssist.PostManaUpdate();\r\n            }\r\n        }\r\n\r\n        public static bool UseNewStatus = false;\r\n\r\n        private static void NewMobileStatus(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Mobile m = World.FindMobile((Serial) p.ReadUInt32());\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            UseNewStatus = true;\r\n\r\n            // 00 01\r\n            p.ReadUInt16();\r\n\r\n            // 00 01 Poison\r\n            // 00 02 Yellow Health Bar\r\n\r\n            ushort id = p.ReadUInt16();\r\n\r\n            // 00 Off\r\n            // 01 On\r\n            // For Poison: Poison Level + 1\r\n\r\n            byte flag = p.ReadByte();\r\n\r\n            if (id == 1)\r\n            {\r\n                bool wasPoisoned = m.Poisoned;\r\n                m.Poisoned = (flag != 0);\r\n\r\n                if (m == World.Player && wasPoisoned != m.Poisoned)\r\n                    Client.Instance.RequestTitlebarUpdate();\r\n            }\r\n        }\r\n\r\n        private static void Damage(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            uint serial = p.ReadUInt32();\r\n            ushort damage = p.ReadUInt16();\r\n\r\n            if (Config.GetBool(\"ShowDamageTaken\") || Config.GetBool(\"ShowDamageDealt\"))\r\n            {\r\n                if (serial == World.Player.Serial && Config.GetBool(\"ShowDamageTaken\"))\r\n                {\r\n                    if (Config.GetBool(\"ShowDamageTakenOverhead\"))\r\n                    {\r\n                        World.Player.OverheadMessage(37, $\"[{damage}]\", true);\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Info, $\"{World.Player.Name}: {damage} damage taken\");\r\n                    }\r\n                }\r\n                else if (Config.GetBool(\"ShowDamageDealt\"))\r\n                {\r\n                    Mobile m = World.FindMobile(serial);\r\n\r\n                    if (m == null)\r\n                        return;\r\n\r\n                    if (Config.GetBool(\"ShowDamageDealtOverhead\"))\r\n                    {\r\n                        m.OverheadMessageFrom(37, m.Name, $\"[{damage}]\", true);\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Info, $\"{World.Player.Name}: {damage} damage on '{m.Name}'\");\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (DamageTracker.Running)\r\n                DamageTracker.AddDamage(serial, damage);\r\n        }\r\n\r\n        private static void MobileStatus(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n            Mobile m = World.FindMobile(serial);\r\n            if (m == null)\r\n                World.AddMobile(m = new Mobile(serial));\r\n\r\n            m.Name = p.ReadString(30);\r\n\r\n            m.Hits = p.ReadUInt16();\r\n            m.HitsMax = p.ReadUInt16();\r\n\r\n            //p.ReadBoolean();//CanBeRenamed\r\n            if (p.ReadBoolean())\r\n                m.CanRename = true;\r\n\r\n            byte type = p.ReadByte();\r\n\r\n            if (m == World.Player && type != 0x00)\r\n            {\r\n                PlayerData player = (PlayerData) m;\r\n\r\n                player.Female = p.ReadBoolean();\r\n\r\n                int oStr = player.Str, oDex = player.Dex, oInt = player.Int;\r\n\r\n                player.Str = p.ReadUInt16();\r\n                player.Dex = p.ReadUInt16();\r\n                player.Int = p.ReadUInt16();\r\n\r\n                //Your strength has changed by {0}{1}, it is now {2}.\r\n                if (player.Str != oStr && oStr != 0 && Config.GetBool(\"DisplaySkillChanges\"))\r\n                {\r\n                    if (Config.GetBool(\"DisplaySkillChangesOverhead\"))\r\n                    {\r\n                        World.Player.OverheadMessage(LocString.StrChangeOverhead, player.Str - oStr > 0 ? \"+\" : \"\",\r\n                            player.Str - oStr, player.Str);\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Force, LocString.StrChanged, player.Str - oStr > 0 ? \"+\" : \"\",\r\n                            player.Str - oStr, player.Str);\r\n                    }\r\n                }\r\n\r\n                if (player.Dex != oDex && oDex != 0 && Config.GetBool(\"DisplaySkillChanges\"))\r\n                {\r\n                    if (Config.GetBool(\"DisplaySkillChangesOverhead\"))\r\n                    {\r\n                        World.Player.OverheadMessage(LocString.DexChangeOverhead, player.Dex - oDex > 0 ? \"+\" : \"\",\r\n                            player.Dex - oDex, player.Dex);\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Force, LocString.DexChanged, player.Dex - oDex > 0 ? \"+\" : \"\",\r\n                            player.Dex - oDex, player.Dex);\r\n                    }\r\n                }\r\n\r\n                if (player.Int != oInt && oInt != 0 && Config.GetBool(\"DisplaySkillChanges\"))\r\n                {\r\n                    if (Config.GetBool(\"DisplaySkillChangesOverhead\"))\r\n                    {\r\n                        World.Player.OverheadMessage(LocString.IntChangeOverhead, player.Int - oInt > 0 ? \"+\" : \"\",\r\n                            player.Int - oInt, player.Int);\r\n                    }\r\n                    else\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Force, LocString.IntChanged, player.Int - oInt > 0 ? \"+\" : \"\",\r\n                            player.Int - oInt, player.Int);\r\n                    }\r\n                }\r\n\r\n                player.Stam = p.ReadUInt16();\r\n                player.StamMax = p.ReadUInt16();\r\n                player.Mana = p.ReadUInt16();\r\n                player.ManaMax = p.ReadUInt16();\r\n\r\n                player.Gold = p.ReadUInt32();\r\n                player.AR = p.ReadUInt16(); // ar / physical resist\r\n                player.Weight = p.ReadUInt16();\r\n\r\n                if (type >= 0x03)\r\n                {\r\n                    if (type > 0x04)\r\n                    {\r\n                        player.MaxWeight = p.ReadUInt16();\r\n\r\n                        p.ReadByte(); // race?\r\n                    }\r\n\r\n                    player.StatCap = p.ReadUInt16();\r\n\r\n                    player.Followers = p.ReadByte();\r\n                    player.FollowersMax = p.ReadByte();\r\n\r\n                    if (type > 0x03)\r\n                    {\r\n                        player.FireResistance = p.ReadInt16();\r\n                        player.ColdResistance = p.ReadInt16();\r\n                        player.PoisonResistance = p.ReadInt16();\r\n                        player.EnergyResistance = p.ReadInt16();\r\n\r\n                        player.Luck = p.ReadInt16();\r\n\r\n                        player.DamageMin = p.ReadUInt16();\r\n                        player.DamageMin = p.ReadUInt16();\r\n                        player.DamageMax = p.ReadUInt16();\r\n\r\n                        player.Tithe = p.ReadInt32();\r\n                    }\r\n                }\r\n\r\n                Client.Instance.RequestTitlebarUpdate();\r\n\r\n                UOAssist.PostHitsUpdate();\r\n                UOAssist.PostStamUpdate();\r\n                UOAssist.PostManaUpdate();\r\n\r\n                Engine.MainWindow.SafeAction(s => s.UpdateTitle()); // update player name\r\n            }\r\n        }\r\n\r\n        private static void MobileUpdate(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            Serial serial = p.ReadUInt32();\r\n            Mobile m = World.FindMobile(serial);\r\n            if (m == null)\r\n                World.AddMobile(m = new Mobile(serial));\r\n\r\n            bool wasHidden = !m.Visible;\r\n\r\n            m.Body = (ushort) (p.ReadUInt16() + p.ReadSByte());\r\n            m.Hue = p.ReadUInt16();\r\n            int ltHue = Config.GetInt(\"LTHilight\");\r\n            if (ltHue != 0 && Targeting.IsLastTarget(m))\r\n            {\r\n                p.Seek(-2, SeekOrigin.Current);\r\n                p.Write((ushort) (ltHue | 0x8000));\r\n            }\r\n\r\n            bool wasPoisoned = m.Poisoned;\r\n            m.ProcessPacketFlags(p.ReadByte());\r\n\r\n            ushort x = p.ReadUInt16();\r\n            ushort y = p.ReadUInt16();\r\n            p.ReadUInt16(); //always 0?\r\n            m.Direction = (Direction) p.ReadByte();\r\n            m.Position = new Point3D(x, y, p.ReadSByte());\r\n\r\n            if (m == World.Player)\r\n            {\r\n                Client.Instance.SetPosition((uint) m.Position.X, (uint) m.Position.Y, (uint) m.Position.Z,\r\n                    (byte) m.Direction);\r\n\r\n                if (!wasHidden && !m.Visible)\r\n                {\r\n                    if (Config.GetBool(\"CountStealthSteps\"))\r\n                        StealthSteps.Hide();\r\n                }\r\n                else if (wasHidden && m.Visible)\r\n                {\r\n                    StealthSteps.Unhide();\r\n                }\r\n\r\n                if (wasPoisoned != m.Poisoned)\r\n                    Client.Instance.RequestTitlebarUpdate();\r\n            }\r\n\r\n            Item.UpdateContainers();\r\n        }\r\n\r\n        private static void MobileIncoming(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            Serial serial = p.ReadUInt32();\r\n            ushort body = p.ReadUInt16();\r\n\r\n            Mobile m = World.FindMobile(serial);\r\n\r\n            if (m == null)\r\n            {\r\n                World.AddMobile(m = new Mobile(serial));\r\n\r\n                if (m != World.Player && Config.GetBool(\"ShowMobNames\"))\r\n                    Client.Instance.SendToServer(new SingleClick(m));\r\n\r\n                if (Config.GetBool(\"LastTargTextFlags\"))\r\n                    Targeting.CheckTextFlags(m);\r\n            }\r\n\r\n            MobileFilter.Apply(p, body);\r\n\r\n            Point3D position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadSByte());\r\n\r\n            bool wasHidden = !m.Visible;\r\n\r\n            int ltHue = Config.GetInt(\"LTHilight\");\r\n            bool isLT;\r\n            if (ltHue != 0)\r\n                isLT = Targeting.IsLastTarget(m);\r\n            else\r\n                isLT = false;\r\n\r\n            m.Body = body;\r\n            if (m != World.Player)\r\n                m.Position = position;\r\n            m.Direction = (Direction) p.ReadByte();\r\n            m.Hue = p.ReadUInt16();\r\n            if (isLT)\r\n            {\r\n                p.Seek(-2, SeekOrigin.Current);\r\n                p.Write((short) (ltHue | 0x8000));\r\n            }\r\n\r\n            bool wasPoisoned = m.Poisoned;\r\n            m.ProcessPacketFlags(p.ReadByte());\r\n            byte oldNoto = m.Notoriety;\r\n            m.Notoriety = p.ReadByte();\r\n\r\n            if (m == World.Player)\r\n            {\r\n                if (!wasHidden && !m.Visible)\r\n                {\r\n                    if (Config.GetBool(\"CountStealthSteps\"))\r\n                        StealthSteps.Hide();\r\n                }\r\n                else if (wasHidden && m.Visible)\r\n                {\r\n                    StealthSteps.Unhide();\r\n                }\r\n\r\n                if (wasPoisoned != m.Poisoned || (oldNoto != m.Notoriety && Config.GetBool(\"ShowNotoHue\")))\r\n                    Client.Instance.RequestTitlebarUpdate();\r\n            }\r\n\r\n            while (true)\r\n            {\r\n                serial = p.ReadUInt32();\r\n                if (!serial.IsItem)\r\n                    break;\r\n\r\n                Item item = World.FindItem(serial);\r\n                bool isNew = false;\r\n                if (item == null)\r\n                {\r\n                    isNew = true;\r\n                    World.AddItem(item = new Item(serial));\r\n                }\r\n\r\n                if (!DragDropManager.EndHolding(serial))\r\n                    continue;\r\n\r\n                item.Container = m;\r\n\r\n                ushort id = p.ReadUInt16();\r\n\r\n                if (Engine.UseNewMobileIncoming)\r\n                    item.ItemID = (ushort) (id & 0xFFFF);\r\n                else if (Engine.UsePostSAChanges)\r\n                    item.ItemID = (ushort) (id & 0x7FFF);\r\n                else\r\n                    item.ItemID = (ushort) (id & 0x3FFF);\r\n\r\n                item.Layer = (Layer) p.ReadByte();\r\n\r\n                if (Engine.UseNewMobileIncoming)\r\n                {\r\n                    item.Hue = p.ReadUInt16();\r\n                    if (isLT)\r\n                    {\r\n                        p.Seek(-2, SeekOrigin.Current);\r\n                        p.Write((short) (ltHue & 0x3FFF));\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    if ((id & 0x8000) != 0)\r\n                    {\r\n                        item.Hue = p.ReadUInt16();\r\n                        if (isLT)\r\n                        {\r\n                            p.Seek(-2, SeekOrigin.Current);\r\n                            p.Write((short) (ltHue & 0x3FFF));\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        item.Hue = 0;\r\n                        if (isLT)\r\n                            Client.Instance.SendToClient(new EquipmentItem(item, (ushort) (ltHue & 0x3FFF), m.Serial));\r\n                    }\r\n                }\r\n\r\n                if (item.Layer == Layer.Backpack && isNew && Config.GetBool(\"AutoSearch\") && m == World.Player &&\r\n                    m != null)\r\n                {\r\n                    _ignoreGumps.Add(item);\r\n                    PlayerData.DoubleClick(item);\r\n                }\r\n            }\r\n\r\n            Item.UpdateContainers();\r\n        }\r\n\r\n        private static void RemoveObject(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n\r\n            if (serial.IsMobile)\r\n            {\r\n                Mobile m = World.FindMobile(serial);\r\n                if (m != null && m != World.Player)\r\n                    m.Remove();\r\n            }\r\n            else if (serial.IsItem)\r\n            {\r\n                Item i = World.FindItem(serial);\r\n                if (i != null)\r\n                {\r\n                    if (DragDropManager.Holding == i)\r\n                    {\r\n                        Counter.SupressWarnings = true;\r\n                        i.Container = null;\r\n                        Counter.SupressWarnings = false;\r\n                    }\r\n                    else\r\n                    {\r\n                        i.RemoveRequest();\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void ServerChange(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player != null)\r\n                World.Player.Position = new Point3D(p.ReadUInt16(), p.ReadUInt16(), p.ReadInt16());\r\n        }\r\n\r\n        private static void WorldItem(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Item item;\r\n            uint serial = p.ReadUInt32();\r\n            item = World.FindItem(serial & 0x7FFFFFFF);\r\n            bool isNew = false;\r\n            if (item == null)\r\n            {\r\n                World.AddItem(item = new Item(serial & 0x7FFFFFFF));\r\n                isNew = true;\r\n            }\r\n            else\r\n            {\r\n                item.CancelRemove();\r\n            }\r\n\r\n            if (!DragDropManager.EndHolding(serial))\r\n                return;\r\n\r\n            item.Container = null;\r\n            Counter.Uncount(item);\r\n\r\n            ushort itemID = p.ReadUInt16();\r\n            item.ItemID = (ushort) (itemID & 0x7FFF);\r\n\r\n            if ((serial & 0x80000000) != 0)\r\n                item.Amount = p.ReadUInt16();\r\n            else\r\n                item.Amount = 1;\r\n\r\n            if ((itemID & 0x8000) != 0)\r\n                item.ItemID = (ushort) (item.ItemID + p.ReadSByte());\r\n\r\n            ushort x = p.ReadUInt16();\r\n            ushort y = p.ReadUInt16();\r\n\r\n            if ((x & 0x8000) != 0)\r\n                item.Direction = p.ReadByte();\r\n            else\r\n                item.Direction = 0;\r\n\r\n            short z = p.ReadSByte();\r\n\r\n            item.Position = new Point3D(x & 0x7FFF, y & 0x3FFF, z);\r\n\r\n            if ((y & 0x8000) != 0)\r\n                item.Hue = p.ReadUInt16();\r\n            else\r\n                item.Hue = 0;\r\n\r\n            byte flags = 0;\r\n            if ((y & 0x4000) != 0)\r\n                flags = p.ReadByte();\r\n\r\n            item.ProcessPacketFlags(flags);\r\n\r\n            if (isNew && World.Player != null)\r\n            {\r\n                if (item.ItemID == 0x2006) // corpse itemid = 0x2006\r\n                {\r\n                    if (Config.GetBool(\"ShowCorpseNames\"))\r\n                        Client.Instance.SendToServer(new SingleClick(item));\r\n\r\n                    if (Config.GetBool(\"AutoOpenCorpses\") &&\r\n                        Utility.InRange(item.Position, World.Player.Position, Config.GetInt(\"CorpseRange\")) &&\r\n                        World.Player != null && World.Player.Visible)\r\n                    {\r\n                        if (Config.GetBool(\"BlockOpenCorpsesTwice\"))\r\n                        {\r\n                            bool blockOpen = false;\r\n                            foreach (uint openedCorse in World.Player.OpenedCorpses)\r\n                            {\r\n                                if (openedCorse == serial)\r\n                                {\r\n                                    blockOpen = true;\r\n                                    break;\r\n                                }\r\n                            }\r\n\r\n                            if (World.Player.OpenedCorpses.Count > 2000)\r\n                            {\r\n                                World.Player.OpenedCorpses.RemoveRange(0, 500);\r\n                            }\r\n\r\n                            if (!blockOpen)\r\n                            {\r\n                                PlayerData.DoubleClick(item);\r\n                            }\r\n\r\n                            if (!World.Player.OpenedCorpses.Contains(serial))\r\n                            {\r\n                                World.Player.OpenedCorpses.Add(serial);\r\n                            }\r\n                        }\r\n                        else\r\n                        {\r\n                            PlayerData.DoubleClick(item);\r\n                        }\r\n                    }\r\n                }\r\n                else if (item.IsMulti)\r\n                {\r\n                    UOAssist.PostAddMulti(item.ItemID, item.Position);\r\n                }\r\n                else\r\n                {\r\n                    ScavengerAgent s = ScavengerAgent.Instance;\r\n                    int dist = Utility.Distance(item.GetWorldPosition(), World.Player.Position);\r\n                    if (!World.Player.IsGhost && World.Player.Visible && dist <= 2 && s.Enabled && item.Movable)\r\n                        s.Scavenge(item);\r\n                }\r\n            }\r\n\r\n            Item.UpdateContainers();\r\n\r\n            if (Config.GetBool(\"ShowStaticWalls\"))\r\n                args.Block = WallStaticFilter.MakeWallStatic(item);\r\n        }\r\n\r\n        private static void SAWorldItem(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            /*\r\n            New World Item Packet\r\n            PacketID: 0xF3\r\n            PacketLen: 24\r\n            Format:\r\n\r\n                 BYTE - 0xF3 packetId\r\n                 WORD - 0x01\r\n                 BYTE - ArtDataID: 0x00 if the item uses art from TileData table, 0x02 if the item uses art from MultiData table)\r\n                 DWORD - item Serial\r\n                 WORD - item ID\r\n                 BYTE - item direction (same as old)\r\n                 WORD - amount\r\n                 WORD - amount\r\n                 WORD - X\r\n                 WORD - Y\r\n                 SBYTE - Z\r\n                 BYTE - item light\r\n                 WORD - item Hue\r\n                 BYTE - item flags (same as old packet)\r\n            */\r\n\r\n            // Post-7.0.9.0\r\n            /*\r\n            New World Item Packet\r\n            PacketID: 0xF3\r\n            PacketLen: 26\r\n            Format:\r\n\r\n                 BYTE - 0xF3 packetId\r\n                 WORD - 0x01\r\n                 BYTE - ArtDataID: 0x00 if the item uses art from TileData table, 0x02 if the item uses art from MultiData table)\r\n                 DWORD - item Serial\r\n                 WORD - item ID\r\n                 BYTE - item direction (same as old)\r\n                 WORD - amount\r\n                 WORD - amount\r\n                 WORD - X\r\n                 WORD - Y\r\n                 SBYTE - Z\r\n                 BYTE - item light\r\n                 WORD - item Hue\r\n                 BYTE - item flags (same as old packet)\r\n                 WORD ???\r\n            */\r\n\r\n            ushort _unk1 = p.ReadUInt16();\r\n\r\n            byte _artDataID = p.ReadByte();\r\n\r\n            Item item;\r\n            uint serial = p.ReadUInt32();\r\n            item = World.FindItem(serial);\r\n            bool isNew = false;\r\n            if (item == null)\r\n            {\r\n                World.AddItem(item = new Item(serial));\r\n                isNew = true;\r\n            }\r\n            else\r\n            {\r\n                item.CancelRemove();\r\n            }\r\n\r\n            if (!DragDropManager.EndHolding(serial))\r\n                return;\r\n\r\n            item.Container = null;\r\n            Counter.Uncount(item);\r\n\r\n            ushort itemID = p.ReadUInt16();\r\n            item.ItemID = (ushort) (_artDataID == 0x02 ? itemID | 0x4000 : itemID);\r\n\r\n            item.Direction = p.ReadByte();\r\n\r\n            ushort _amount = p.ReadUInt16();\r\n            item.Amount = _amount = p.ReadUInt16();\r\n\r\n            ushort x = p.ReadUInt16();\r\n            ushort y = p.ReadUInt16();\r\n            short z = p.ReadSByte();\r\n\r\n            item.Position = new Point3D(x, y, z);\r\n\r\n            byte _light = p.ReadByte();\r\n\r\n            item.Hue = p.ReadUInt16();\r\n\r\n            byte flags = p.ReadByte();\r\n\r\n            item.ProcessPacketFlags(flags);\r\n\r\n            if (Engine.UsePostHSChanges)\r\n            {\r\n                p.ReadUInt16();\r\n            }\r\n\r\n            if (isNew && World.Player != null)\r\n            {\r\n                if (item.ItemID == 0x2006) // corpse itemid = 0x2006\r\n                {\r\n                    if (Config.GetBool(\"ShowCorpseNames\"))\r\n                        Client.Instance.SendToServer(new SingleClick(item));\r\n                    if (Config.GetBool(\"AutoOpenCorpses\") &&\r\n                        Utility.InRange(item.Position, World.Player.Position, Config.GetInt(\"CorpseRange\")) &&\r\n                        World.Player != null && World.Player.Visible)\r\n                        PlayerData.DoubleClick(item);\r\n                }\r\n                else if (item.IsMulti)\r\n                {\r\n                    UOAssist.PostAddMulti(item.ItemID, item.Position);\r\n                }\r\n                else\r\n                {\r\n                    ScavengerAgent s = ScavengerAgent.Instance;\r\n                    int dist = Utility.Distance(item.GetWorldPosition(), World.Player.Position);\r\n                    if (!World.Player.IsGhost && World.Player.Visible && dist <= 2 && s.Enabled && item.Movable)\r\n                        s.Scavenge(item);\r\n                }\r\n            }\r\n\r\n            Item.UpdateContainers();\r\n\r\n            if (Config.GetBool(\"ShowStaticWalls\"))\r\n                args.Block = WallStaticFilter.MakeWallStatic(item);\r\n        }\r\n\r\n        public static System.Text.StringBuilder SpellPowerwordsBuilder { get; set; } =\r\n            new System.Text.StringBuilder(Config.GetString(\"SpellFormat\"));\r\n\r\n        private static void ResetSpellPowerwordsBuilder()\r\n        {\r\n            SpellPowerwordsBuilder.Remove(0, SpellPowerwordsBuilder.Length);\r\n            SpellPowerwordsBuilder.Insert(0, Config.GetString(\"SpellFormat\"));\r\n        }\r\n\r\n        public static void AsciiSpeech(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            // 0, 1, 2\r\n            Serial serial = p.ReadUInt32(); // 3, 4, 5, 6\r\n            ushort body = p.ReadUInt16(); // 7, 8\r\n            MessageType type = (MessageType) p.ReadByte(); // 9\r\n            ushort hue = p.ReadUInt16(); // 10, 11\r\n            ushort font = p.ReadUInt16();\r\n            string name = p.ReadStringSafe(30);\r\n            string text = p.ReadStringSafe();\r\n\r\n            if (World.Player != null && serial == Serial.Zero && body == 0 && type == MessageType.Regular &&\r\n                hue == 0xFFFF && font == 0xFFFF && name == \"SYSTEM\")\r\n            {\r\n                args.Block = true;\r\n\r\n                Client.Instance.SendToServer(new ACKTalk());\r\n            }\r\n            else\r\n            {\r\n                MessageManager.HandleMessage(p, args, serial, body, type, hue, font, \"A\", name, text);\r\n            }\r\n        }\r\n\r\n        public static void UnicodeSpeech(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            // 0, 1, 2\r\n            Serial serial = p.ReadUInt32(); // 3, 4, 5, 6\r\n            ushort body = p.ReadUInt16(); // 7, 8\r\n            MessageType type = (MessageType) p.ReadByte(); // 9\r\n            ushort hue = p.ReadUInt16(); // 10, 11\r\n            ushort font = p.ReadUInt16();\r\n            string lang = p.ReadStringSafe(4);\r\n            string name = p.ReadStringSafe(30);\r\n            string text = p.ReadUnicodeStringSafe();\r\n\r\n            MessageManager.HandleMessage(p, args, serial, body, type, hue, font, lang, name, text);\r\n        }\r\n\r\n        private static void OnLocalizedMessage(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            // 0, 1, 2\r\n            Serial serial = p.ReadUInt32(); // 3, 4, 5, 6\r\n            ushort body = p.ReadUInt16(); // 7, 8\r\n            MessageType type = (MessageType) p.ReadByte(); // 9\r\n            ushort hue = p.ReadUInt16(); // 10, 11\r\n            ushort font = p.ReadUInt16();\r\n            int num = p.ReadInt32();\r\n            string name = p.ReadStringSafe(30);\r\n            string ext_str = p.ReadUnicodeStringLESafe();\r\n\r\n            if ((num >= 3002011 && num < 3002011 + 64) || // reg spells\r\n                (num >= 1060509 && num < 1060509 + 16) || // necro\r\n                (num >= 1060585 && num < 1060585 + 10) || // chiv\r\n                (num >= 1060493 && num < 1060493 + 10) || // chiv\r\n                (num >= 1060595 && num < 1060595 + 6) || // bush\r\n                (num >= 1060610 && num < 1060610 + 8)) // ninj\r\n            {\r\n                type = MessageType.Spell;\r\n            }\r\n            \r\n            try\r\n            {\r\n                string text = Language.ClilocFormat(num, ext_str);\r\n                MessageManager.HandleMessage(p, args, serial, body, type, hue, font, Language.CliLocName.ToUpper(),\r\n                    name, text);\r\n            }\r\n            catch (Exception e)\r\n            {\r\n                Engine.LogCrash(new Exception($\"Exception in Ultima.dll cliloc: {num}, {ext_str}\", e));\r\n            }\r\n        }\r\n\r\n        private static void OnLocalizedMessageAffix(Packet p, PacketHandlerEventArgs phea)\r\n        {\r\n            // 0, 1, 2\r\n            Serial serial = p.ReadUInt32(); // 3, 4, 5, 6\r\n            ushort body = p.ReadUInt16(); // 7, 8\r\n            MessageType type = (MessageType) p.ReadByte(); // 9\r\n            ushort hue = p.ReadUInt16(); // 10, 11\r\n            ushort font = p.ReadUInt16();\r\n            int num = p.ReadInt32();\r\n            byte affixType = p.ReadByte();\r\n            string name = p.ReadStringSafe(30);\r\n            string affix = p.ReadStringSafe();\r\n            string args = p.ReadUnicodeStringSafe();\r\n\r\n            if ((num >= 3002011 && num < 3002011 + 64) || // reg spells\r\n                (num >= 1060509 && num < 1060509 + 16) || // necro\r\n                (num >= 1060585 && num < 1060585 + 10) || // chiv\r\n                (num >= 1060493 && num < 1060493 + 10) || // chiv\r\n                (num >= 1060595 && num < 1060595 + 6) || // bush\r\n                (num >= 1060610 && num < 1060610 + 8) // ninj\r\n               )\r\n            {\r\n                type = MessageType.Spell;\r\n            }\r\n\r\n            string text;\r\n            if ((affixType & 1) != 0) // prepend\r\n            {\r\n                text = $\"{affix}{Language.ClilocFormat(num, args)}\";\r\n            }\r\n            else // 0 == append, 2 = system\r\n            {\r\n                text = $\"{Language.ClilocFormat(num, args)}{affix}\";\r\n            }\r\n\r\n            MessageManager.HandleMessage(p, phea, serial, body, type, hue, font, Language.CliLocName.ToUpper(), name,\r\n                text);\r\n        }\r\n\r\n        private static void SendGump(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            World.Player.CurrentGumpS = p.ReadUInt32();\r\n            World.Player.CurrentGumpI = p.ReadUInt32();\r\n            World.Player.HasGump = true;\r\n\r\n            if (!World.Player.GumpList.TryGetValue(World.Player.CurrentGumpI, out PlayerData.GumpInfo _))\r\n            {\r\n                World.Player.GumpList.Add(World.Player.CurrentGumpI, new PlayerData.GumpInfo(World.Player.CurrentGumpS, World.Player.CurrentGumpI));\r\n            }\r\n\r\n            if (Macros.MacroManager.AcceptActions &&\r\n                MacroManager.Action(new WaitForGumpAction(World.Player.CurrentGumpI)))\r\n                args.Block = true;\r\n\r\n            ScriptManager.AddToScript($\"waitforgump {World.Player.CurrentGumpI} 10000\");\r\n        }\r\n\r\n        private static void ClientGumpResponse(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            Serial ser = p.ReadUInt32();\r\n            uint gumpId = p.ReadUInt32();\r\n            int buttonId = p.ReadInt32();\r\n\r\n            World.Player.GumpList.Remove(gumpId);\r\n\r\n            World.Player.HasGump = false;\r\n            World.Player.HasCompressedGump = false;\r\n\r\n            int switchCount = p.ReadInt32();\r\n            if (switchCount < 0 || switchCount > 2000)\r\n                return;\r\n\r\n            int[] switches = new int[switchCount];\r\n            for (int i = 0; i < switchCount; i++)\r\n                switches[i] = p.ReadInt32();\r\n\r\n            int ec = p.ReadInt32();\r\n            if (ec < 0 || ec > 2000)\r\n                return;\r\n\r\n            GumpTextEntry[] entries = new GumpTextEntry[ec];\r\n            for (int i = 0; i < ec; i++)\r\n            {\r\n                ushort id = p.ReadUInt16();\r\n                ushort len = p.ReadUInt16();\r\n                if (len >= 240)\r\n                    return;\r\n                string text = p.ReadUnicodeStringSafe(len);\r\n                entries[i] = new GumpTextEntry(id, text);\r\n            }\r\n\r\n            if (World.Player.InternalGumps.GetGump(gumpId, out Gump gump))\r\n            {\r\n                World.Player.InternalGumps.Remove(gumpId, buttonId, switches, entries);\r\n            }\r\n\r\n            if (Macros.MacroManager.AcceptActions)\r\n                MacroManager.Action(new GumpResponseAction(buttonId, switches, entries));\r\n\r\n            ScriptManager.AddToScript(buttonId == 0 ? \"gumpclose\" : $\"gumpresponse {buttonId}\");\r\n\r\n\r\n            World.Player.LastGumpResponseAction = new GumpResponseAction(buttonId, switches, entries);\r\n        }\r\n\r\n        private static void ChangeSeason(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                byte season = p.ReadByte();\r\n                World.Player.SetSeason(season);\r\n            }\r\n        }\r\n\r\n        private static void OnAssistVersion(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            args.Block = true;\r\n\r\n            Client.Instance.ForceSendToServer(new AssistVersion());\r\n        }\r\n\r\n        private static void ExtendedPacket(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            ushort type = p.ReadUInt16();\r\n\r\n            switch (type)\r\n            {\r\n                case 0x04: // close gump\r\n                {\r\n                    // int serial, int tid\r\n                    if (World.Player != null)\r\n                    {\r\n                        uint gumpId = p.ReadUInt32();\r\n\r\n                        World.Player.GumpList.Remove(gumpId);\r\n                        World.Player.HasGump = false;\r\n                        World.Player.HasCompressedGump = false;\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x06: // party messages\r\n                {\r\n                    OnPartyMessage(p, args);\r\n                    break;\r\n                }\r\n\r\n                case 0x08: // map change\r\n                {\r\n                    if (World.Player != null)\r\n                        World.Player.Map = p.ReadByte();\r\n                    break;\r\n                }\r\n\r\n                case 0x14: // context menu\r\n                {\r\n                    p.ReadInt16(); // 0x01\r\n                    UOEntity ent = null;\r\n                    Serial ser = p.ReadUInt32();\r\n                    if (ser.IsMobile)\r\n                        ent = World.FindMobile(ser);\r\n                    else if (ser.IsItem)\r\n                        ent = World.FindItem(ser);\r\n\r\n                    if (ent != null)\r\n                    {\r\n                        byte count = p.ReadByte();\r\n\r\n                        try\r\n                        {\r\n                            ent.ContextMenu.Clear();\r\n\r\n                            for (int i = 0; i < count; i++)\r\n                            {\r\n                                ushort idx = p.ReadUInt16();\r\n                                ushort num = p.ReadUInt16();\r\n                                ushort flags = p.ReadUInt16();\r\n                                ushort color = 0;\r\n\r\n                                if ((flags & 0x02) != 0)\r\n                                    color = p.ReadUInt16();\r\n\r\n                                ent.ContextMenu.Add(idx, num);\r\n                            }\r\n                        }\r\n                        catch\r\n                        {\r\n                            // ignored\r\n                        }\r\n                    }\r\n\r\n                    if (ScriptManager.BlockPopupMenu)\r\n                    {\r\n                        args.Block = true;\r\n                        ScriptManager.BlockPopupMenu = false;\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x18: // map patches\r\n                {\r\n                    if (World.Player != null)\r\n                    {\r\n                        int count = p.ReadInt32() * 2;\r\n                        try\r\n                        {\r\n                            World.Player.MapPatches = new int[count];\r\n                            for (int i = 0; i < count; i++)\r\n                                World.Player.MapPatches[i] = p.ReadInt32();\r\n                        }\r\n                        catch\r\n                        {\r\n                        }\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x19: //  stat locks\r\n                {\r\n                    if (p.ReadByte() == 0x02)\r\n                    {\r\n                        Mobile m = World.FindMobile(p.ReadUInt32());\r\n                        if (World.Player == m && m != null)\r\n                        {\r\n                            p.ReadByte(); // 0?\r\n\r\n                            byte locks = p.ReadByte();\r\n\r\n                            World.Player.StrLock = (LockType) ((locks >> 4) & 3);\r\n                            World.Player.DexLock = (LockType) ((locks >> 2) & 3);\r\n                            World.Player.IntLock = (LockType) (locks & 3);\r\n                        }\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x1D: // Custom House \"General Info\"\r\n                {\r\n                    Item i = World.FindItem(p.ReadUInt32());\r\n                    if (i != null)\r\n                        i.HouseRevision = p.ReadInt32();\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        public static int SpecialPartySent = 0;\r\n        public static int SpecialPartyReceived = 0;\r\n\r\n        private static void RunUOProtocolExtention(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            // Only block this packet if they are using the OSI client\r\n            // since ClassicUO actually has support for it now\r\n            args.Block = Client.IsOSI;\r\n\r\n            switch (p.ReadByte())\r\n            {\r\n                case 1: // Custom Party information\r\n                {\r\n                    Serial serial;\r\n\r\n                    PacketHandlers.SpecialPartyReceived++;\r\n\r\n                    while ((serial = p.ReadUInt32()) > 0)\r\n                    {\r\n                        Mobile mobile = World.FindMobile(serial);\r\n\r\n                        short x = p.ReadInt16();\r\n                        short y = p.ReadInt16();\r\n                        byte map = p.ReadByte();\r\n\r\n                        if (mobile == null)\r\n                        {\r\n                            World.AddMobile(mobile = new Mobile(serial));\r\n                            mobile.Visible = false;\r\n                        }\r\n\r\n                        if (mobile.Name == null || mobile.Name.Length <= 0)\r\n                            mobile.Name = \"(Not Seen)\";\r\n\r\n                        if (!_party.Contains(serial))\r\n                            _party.Add(serial);\r\n\r\n                        if (map == World.Player.Map)\r\n                            mobile.Position = new Point3D(x, y, mobile.Position.Z);\r\n                        else\r\n                            mobile.Position = Point3D.Zero;\r\n                    }\r\n\r\n                    if (Engine.MainWindow.MapWindow != null)\r\n                        Engine.MainWindow.SafeAction(s => s.MapWindow.UpdateMap());\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0xFE: // Begin Handshake/Features Negotiation\r\n                {\r\n                    ulong features = ((ulong) p.ReadUInt32() << 32) | (ulong) p.ReadUInt32();\r\n\r\n                    Client.Instance.SetFeatures(features);\r\n                    Client.Instance.SendToServer(new RazorNegotiateResponse());\r\n                    Engine.MainWindow.SafeAction(s => s.UpdateControlLocks());\r\n\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private static List<Serial> _party = new List<Serial>();\r\n\r\n        public static List<Serial> Party => _party;\r\n\r\n        private static Timer _partyDeclineTimer = null;\r\n        public static Serial PartyLeader = Serial.Zero;\r\n\r\n        private static void OnPartyMessage(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            switch (p.ReadByte())\r\n            {\r\n                case 0x01: // List\r\n                {\r\n                    _party.Clear();\r\n\r\n                    int count = p.ReadByte();\r\n                    for (int i = 0; i < count; i++)\r\n                    {\r\n                        Serial s = p.ReadUInt32();\r\n                        if (World.Player == null || s != World.Player.Serial)\r\n                            _party.Add(s);\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x02: // Remove Member/Re-list\r\n                {\r\n                    _party.Clear();\r\n                    int count = p.ReadByte();\r\n                    Serial remSerial = p.ReadUInt32(); // the serial of who was removed\r\n\r\n                    if (World.Player != null)\r\n                    {\r\n                        Mobile rem = World.FindMobile(remSerial);\r\n                        if (rem != null && !Utility.InRange(World.Player.Position, rem.Position, World.Player.VisRange))\r\n                            rem.Remove();\r\n                    }\r\n\r\n                    for (int i = 0; i < count; i++)\r\n                    {\r\n                        Serial s = p.ReadUInt32();\r\n                        if (World.Player == null || s != World.Player.Serial)\r\n                            _party.Add(s);\r\n                    }\r\n\r\n                    break;\r\n                }\r\n\r\n                case 0x03: // text message\r\n\r\n                case 0x04: // 3 = private, 4 = public\r\n                {\r\n                    //Serial from = p.ReadUInt32();\r\n                    //string text = p.ReadUnicodeStringSafe();\r\n                    break;\r\n                }\r\n\r\n                case 0x07: // party invite\r\n                {\r\n                    //Serial leader = p.ReadUInt32();\r\n                    PartyLeader = p.ReadUInt32();\r\n\r\n                    if (Config.GetBool(\"BlockPartyInvites\"))\r\n                    {\r\n                        Client.Instance.SendToServer(new DeclineParty(PacketHandlers.PartyLeader));\r\n                    }\r\n\r\n                    if (Config.GetBool(\"AutoAcceptParty\"))\r\n                    {\r\n                        Mobile leaderMobile = World.FindMobile(PartyLeader);\r\n                        if (leaderMobile != null && FriendsManager.IsFriend(leaderMobile.Serial))\r\n                        {\r\n                            if (PartyLeader != Serial.Zero)\r\n                            {\r\n                                World.Player.SendMessage($\"Auto accepted party invite from: {leaderMobile.Name}\");\r\n\r\n                                Client.Instance.SendToServer(new AcceptParty(PartyLeader));\r\n                                PartyLeader = Serial.Zero;\r\n                            }\r\n                        }\r\n                    }\r\n                    else\r\n                    {\r\n                        if (_partyDeclineTimer == null)\r\n                            _partyDeclineTimer = Timer.DelayedCallback(TimeSpan.FromSeconds(10.0),\r\n                                new TimerCallback(PartyAutoDecline));\r\n                        _partyDeclineTimer.Start();\r\n                    }\r\n\r\n                    break;\r\n                }\r\n            }\r\n\r\n\r\n            if (Engine.MainWindow.MapWindow != null)\r\n                Engine.MainWindow.SafeAction(s => s.MapWindow.UpdateMap());\r\n        }\r\n\r\n        private static void PartyAutoDecline()\r\n        {\r\n            PartyLeader = Serial.Zero;\r\n        }\r\n\r\n        private static void PingResponse(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (Ping.Response(p.ReadByte()))\r\n                args.Block = true;\r\n        }\r\n\r\n        private static void ClientEncodedPacket(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n            ushort packetID = p.ReadUInt16();\r\n            switch (packetID)\r\n            {\r\n                case 0x19: // set ability\r\n                {\r\n                    int ability = 0;\r\n                    if (p.ReadByte() == 0)\r\n                        ability = p.ReadInt32();\r\n\r\n                    if (ability >= 0 && ability < (int) AOSAbility.Invalid && Macros.MacroManager.AcceptActions)\r\n                        MacroManager.Action(new SetAbilityAction((AOSAbility) ability));\r\n                    else if (ability >= 0 && ability < (int) AOSAbility.Invalid)\r\n                        ScriptManager.AddToScript($\"setability '{ability}'\");\r\n\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private static string _lastPassword = \"\";\r\n\r\n        private static void ServerListLogin(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            _lastPassword = \"\";\r\n            if (!Config.GetBool(\"RememberPwds\"))\r\n                return;\r\n\r\n            World.AccountName = p.ReadStringSafe(30);\r\n            string pass = p.ReadStringSafe(30);\r\n\r\n            if (pass == \"\")\r\n            {\r\n                pass = PasswordMemory.Find(World.AccountName, Client.Instance.LastConnection);\r\n                if (pass != null && pass != \"\")\r\n                {\r\n                    p.Seek(31, SeekOrigin.Begin);\r\n                    p.WriteAsciiFixed(pass, 30);\r\n                    _lastPassword = pass;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                PasswordMemory.Add(World.AccountName, pass, Client.Instance.LastConnection);\r\n            }\r\n        }\r\n\r\n        private static void GameLogin(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            int authID = p.ReadInt32();\r\n\r\n            World.AccountName = p.ReadString(30);\r\n            string password = p.ReadString(30);\r\n\r\n            if (password == \"\" && _lastPassword != \"\" && Config.GetBool(\"RememberPwds\"))\r\n            {\r\n                p.Seek(35, SeekOrigin.Begin);\r\n                p.WriteAsciiFixed(_lastPassword, 30);\r\n                _lastPassword = \"\";\r\n            }\r\n        }\r\n\r\n        private static void MenuResponse(PacketReader pvSrc, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            uint serial = pvSrc.ReadUInt32();\r\n            ushort menuID = pvSrc.ReadUInt16();\r\n            ushort index = pvSrc.ReadUInt16();\r\n            ushort itemID = pvSrc.ReadUInt16();\r\n            ushort hue = pvSrc.ReadUInt16();\r\n\r\n            World.Player.HasMenu = false;\r\n            if (MacroManager.AcceptActions)\r\n                MacroManager.Action(new MenuResponseAction(index, itemID, hue));\r\n\r\n            ScriptManager.AddToScript($\"menuresponse {index} {itemID} {hue}\");\r\n        }\r\n\r\n        private static void SendMenu(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            World.Player.CurrentMenuS = p.ReadUInt32();\r\n            World.Player.CurrentMenuI = p.ReadUInt16();\r\n            World.Player.HasMenu = true;\r\n            if (MacroManager.AcceptActions && MacroManager.Action(new WaitForMenuAction(World.Player.CurrentMenuI)))\r\n                args.Block = true;\r\n\r\n            if (ScriptManager.AddToScript($\"waitformenu {World.Player.CurrentMenuI}\"))\r\n                args.Block = true;\r\n        }\r\n\r\n        private static void HueResponse(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n            ushort iid = p.ReadUInt16();\r\n            ushort hue = p.ReadUInt16();\r\n\r\n            if (serial == Serial.MinusOne)\r\n            {\r\n                if (HueEntry.Callback != null)\r\n                    HueEntry.Callback(hue);\r\n                args.Block = true;\r\n            }\r\n        }\r\n\r\n        private static void ServerAddress(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            int port = Config.GetInt(\"ForcePort\");\r\n            if (port != 0)\r\n            {\r\n                try\r\n                {\r\n                    string[] parts = Config.GetString(\"ForceIP\").Split('.');\r\n                    p.Write((byte) Convert.ToInt16(parts[0]));\r\n                    p.Write((byte) Convert.ToInt16(parts[1]));\r\n                    p.Write((byte) Convert.ToInt16(parts[2]));\r\n                    p.Write((byte) Convert.ToInt16(parts[3]));\r\n\r\n                    p.Write((ushort) port);\r\n                }\r\n                catch\r\n                {\r\n                    System.Windows.Forms.MessageBox.Show(Engine.MainWindow, \"Error parsing Proxy Settings.\",\r\n                        \"Force Proxy Error.\");\r\n                }\r\n            }\r\n        }\r\n\r\n        private static void Features(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                if (p.Length > 3)\r\n                    World.Player.Features = p.ReadUInt32();\r\n                else\r\n                    World.Player.Features = p.ReadUInt16();\r\n            }\r\n        }\r\n\r\n        private static void PersonalLight(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player != null && !args.Block)\r\n            {\r\n                p.ReadUInt32(); // serial\r\n\r\n                World.Player.LocalLightLevel = p.ReadSByte();\r\n\r\n                if (EnforceLightLevels(World.Player.LocalLightLevel))\r\n                    args.Block = true;\r\n            }\r\n        }\r\n\r\n        private static void GlobalLight(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player != null && !args.Block)\r\n            {\r\n                World.Player.GlobalLightLevel = p.ReadByte();\r\n\r\n                if (EnforceLightLevels(World.Player.GlobalLightLevel))\r\n                    args.Block = true;\r\n            }\r\n        }\r\n\r\n        private static bool EnforceLightLevels(int lightLevel)\r\n        {\r\n            if (Client.Instance.AllowBit(FeatureBit.LightFilter) && Config.GetBool(\"MinMaxLightLevelEnabled\"))\r\n            {\r\n                // 0 bright, 30 is dark\r\n                if (lightLevel == -1)\r\n                {\r\n                    lightLevel = Convert.ToByte(Config.GetInt(\"MinLightLevel\"));\r\n                }\r\n                else if (lightLevel < Config.GetInt(\"MaxLightLevel\"))\r\n                {\r\n                    lightLevel = Convert.ToByte(Config.GetInt(\"MaxLightLevel\")); // light level is too light\r\n                }\r\n                else if (lightLevel > Config.GetInt(\"MinLightLevel\")) // light level is too dark\r\n                {\r\n                    lightLevel = Convert.ToByte(Config.GetInt(\"MinLightLevel\"));\r\n                }\r\n                else // No need to block or do anything special\r\n                {\r\n                    return false;\r\n                }\r\n\r\n                World.Player.LocalLightLevel = 0;\r\n                World.Player.GlobalLightLevel = (byte) lightLevel;\r\n\r\n                Client.Instance.SendToClient(new GlobalLightLevel(lightLevel));\r\n                Client.Instance.SendToClient(new PersonalLightLevel(World.Player));\r\n\r\n                return true;\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        private static void ServerSetWarMode(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            World.Player.Warmode = p.ReadBoolean();\r\n        }\r\n\r\n        private static void CustomHouseInfo(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            p.ReadByte(); // compression\r\n            p.ReadByte(); // Unknown\r\n\r\n            Item i = World.FindItem(p.ReadUInt32());\r\n            if (i != null)\r\n            {\r\n                i.HouseRevision = p.ReadInt32();\r\n                i.HousePacket = p.CopyBytes(0, p.Length);\r\n            }\r\n        }\r\n\r\n        /*\r\n        Packet Build\r\n        1.  BYTE[1] Cmd\r\n        2.  BYTE[2] len\r\n        3.  BYTE[4] Player Serial\r\n        4.  BYTE[4] Gump ID\r\n        5.  BYTE[4] x\r\n        6.  BYTE[4] y\r\n        7.  BYTE[4] Compressed Gump Layout Length (CLen)\r\n        8.  BYTE[4] Decompressed Gump Layout Length (DLen)\r\n        9.  BYTE[CLen-4] Gump Data, zlib compressed\r\n        10. BYTE[4] Number of text lines\r\n        11. BYTE[4] Compressed Text Line Length (CTxtLen)\r\n        12. BYTE[4] Decompressed Text Line Length (DTxtLen)\r\n        13. BYTE[CTxtLen-4] Gump's Compressed Text data, zlib compressed\r\n         */\r\n        private static void CompressedGump(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            World.Player.CurrentGumpS = p.ReadUInt32();\r\n            World.Player.CurrentGumpI = p.ReadUInt32();\r\n            World.Player.HasCompressedGump = true;\r\n\r\n            if (Macros.MacroManager.AcceptActions &&\r\n                MacroManager.Action(new WaitForGumpAction(World.Player.CurrentGumpI)))\r\n                args.Block = true;\r\n\r\n            ScriptManager.AddToScript($\"waitforgump {World.Player.CurrentGumpI}\");\r\n\r\n            List<string> gumpStrings = new List<string>();\r\n\r\n            try\r\n            {\r\n                int x = p.ReadInt32(), y = p.ReadInt32();\r\n\r\n                string layout = p.GetCompressedReader().ReadString();\r\n\r\n                int numStrings = p.ReadInt32();\r\n                if (numStrings < 0 || numStrings > 256)\r\n                    numStrings = 0;\r\n\r\n                // Split on one or more non-digit characters.\r\n                World.Player.CurrentGumpStrings.Clear();\r\n\r\n                string[] numbers = Regex.Split(layout, @\"\\D+\");\r\n\r\n                foreach (string value in numbers)\r\n                {\r\n                    if (!string.IsNullOrEmpty(value))\r\n                    {\r\n                        int i = int.Parse(value);\r\n                        if ((i >= 500000 && i <= 503405) || (i >= 1000000 && i <= 1155584) ||\r\n                            (i >= 3000000 && i <= 3011032))\r\n                            gumpStrings.Add(Language.GetString(i));\r\n                    }\r\n                }\r\n\r\n                PacketReader pComp = p.GetCompressedReader();\r\n                int len = 0;\r\n                int x1 = 0;\r\n                string[] stringlistparse = new string[numStrings];\r\n\r\n                while (!pComp.AtEnd && (len = pComp.ReadInt16()) > 0)\r\n                {\r\n                    string tempString = pComp.ReadUnicodeString(len);\r\n                    stringlistparse[x1] = tempString;\r\n                    x1++;\r\n                }\r\n\r\n                if (TryParseGump(layout, out string[] gumpPieces))\r\n                {\r\n                    gumpStrings.AddRange(ParseGumpString(gumpPieces, stringlistparse));\r\n                }\r\n\r\n                if (Config.GetBool(\"CaptureMibs\") && MessageInBottleCapture.IsMibGump(layout))\r\n                {\r\n                    switch (gumpStrings.Count)\r\n                    {\r\n                        //Classic, non-custom MIB\r\n                        case 3:\r\n                            MessageInBottleCapture.CaptureMibCoordinates(gumpStrings[2], false);\r\n                            break;\r\n                        case 4:\r\n                            MessageInBottleCapture.CaptureMibCoordinates(gumpStrings[2], true);\r\n                            break;\r\n                    }\r\n                }\r\n\r\n                if (World.Player.GumpList.ContainsKey(World.Player.CurrentGumpI))\r\n                {\r\n                    World.Player.GumpList.Remove(World.Player.CurrentGumpI);\r\n                }\r\n\r\n                World.Player.GumpList.Add(World.Player.CurrentGumpI, new PlayerData.GumpInfo(World.Player.CurrentGumpS, World.Player.CurrentGumpI, gumpStrings));\r\n\r\n                World.Player.CurrentGumpStrings.AddRange(gumpStrings);\r\n                World.Player.CurrentGumpRawData = layout; // Get raw data of current gump\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private static bool TryParseGump(string gumpData, out string[] pieces)\r\n        {\r\n            List<string> i = new List<string>();\r\n            int dataIndex = 0;\r\n            while (dataIndex < gumpData.Length)\r\n            {\r\n                if (gumpData.Substring(dataIndex) == \"\\0\")\r\n                {\r\n                    break;\r\n                }\r\n                else\r\n                {\r\n                    int begin = gumpData.IndexOf(\"{\", dataIndex);\r\n                    int end = gumpData.IndexOf(\"}\", dataIndex + 1);\r\n                    if ((begin != -1) && (end != -1))\r\n                    {\r\n                        string sub = gumpData.Substring(begin + 1, end - begin - 1).Trim();\r\n                        i.Add(sub);\r\n                        dataIndex = end;\r\n                    }\r\n                    else\r\n                    {\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n\r\n            pieces = i.ToArray();\r\n            return (pieces.Length > 0);\r\n        }\r\n\r\n        private static List<string> ParseGumpString(string[] gumpPieces, string[] gumpLines)\r\n        {\r\n            List<string> gumpText = new List<string>();\r\n            for (int i = 0; i < gumpPieces.Length; i++)\r\n            {\r\n                string[] gumpParams = Regex.Split(gumpPieces[i], @\"\\s+\");\r\n                switch (gumpParams[0].ToLower())\r\n                {\r\n                    case \"croppedtext\":\r\n                        gumpText.Add(gumpLines[int.Parse(gumpParams[6])]);\r\n                        // CroppedText [x] [y] [width] [height] [color] [text-id]\r\n                        // Adds a text field to the gump. gump is similar to the text command, but the text is cropped to the defined area.\r\n                        //gump.AddControl(new CroppedText(gump, gumpParams, gumpLines), currentGUMPPage);\r\n                        //(gump.LastControl as CroppedText).Hue = 1;\r\n                        break;\r\n\r\n                    case \"htmlgump\":\r\n                        gumpText.Add(gumpLines[int.Parse(gumpParams[5])]);\r\n                        // HtmlGump [x] [y] [width] [height] [text-id] [background] [scrollbar]\r\n                        // Defines a text-area where Html-commands are allowed.\r\n                        // [background] and [scrollbar] can be 0 or 1 and define whether the background is transparent and a scrollbar is displayed.\r\n                        //\tgump.AddControl(new HtmlGumpling(gump, gumpParams, gumpLines), currentGUMPPage);\r\n                        break;\r\n\r\n                    case \"text\":\r\n                        gumpText.Add(gumpLines[int.Parse(gumpParams[4])]);\r\n                        // Text [x] [y] [color] [text-id]\r\n                        // Defines the position and color of a text (data) entry.\r\n                        //gump.AddControl(new TextLabel(gump, gumpParams, gumpLines), currentGUMPPage);\r\n                        break;\r\n                }\r\n            }\r\n\r\n            return gumpText;\r\n        }\r\n\r\n        private static DateTime _lastSelfDeathScreenshot = DateTime.MinValue;\r\n\r\n        private static void ResurrectionGump(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (Config.GetBool(\"CaptureOwnDeath\") &&\r\n                _lastSelfDeathScreenshot + TimeSpan.FromMilliseconds(500) < DateTime.UtcNow)\r\n            {\r\n                ScreenCapManager.DeathCapture(Config.GetDouble(\"CaptureOwnDeathDelay\"));\r\n                _lastSelfDeathScreenshot = DateTime.UtcNow;\r\n            }\r\n\r\n            if (Config.GetBool(\"CreateWaypointOnDeath\") && World.Player != null)\r\n            {\r\n                WaypointManager.Waypoint waypoint = new WaypointManager.Waypoint\r\n                {\r\n                    X = World.Player.Position.X,\r\n                    Y = World.Player.Position.Y,\r\n                    Name = \"Your Body\"\r\n                };\r\n\r\n                WaypointManager.AddWaypoint(waypoint);\r\n                WaypointManager.ShowWaypoint(waypoint);\r\n            }\r\n        }\r\n        \r\n        private const ushort BUFF_ICON_START = 0x03E9;\r\n        private const ushort BUFF_ICON_START_NEW = 0x466;\r\n\r\n        private static void BuffDebuff(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            Serial serial = p.ReadUInt32();\r\n            ushort icon = p.ReadUInt16();\r\n            ushort action = p.ReadUInt16();\r\n\r\n            if (Enum.IsDefined(typeof(BuffIconType), icon))\r\n            {\r\n                BuffIconType buffType = (BuffIconType) icon;\r\n                \r\n                ushort iconId = (ushort) buffType >= BUFF_ICON_START_NEW ? (ushort) (buffType - (BUFF_ICON_START_NEW - 125)) : (ushort) ((ushort) buffType - BUFF_ICON_START);\r\n                \r\n                switch (action)\r\n                {\r\n                    case 0x01: // show\r\n\r\n                        p.ReadUInt32(); //0x000\r\n                        p.ReadUInt16(); //icon # again..?\r\n                        p.ReadUInt16(); //0x1 = show\r\n                        p.ReadUInt32(); //0x000\r\n                        ushort duration = p.ReadUInt16();\r\n                        p.ReadUInt16(); //0x0000\r\n                        p.ReadByte(); //0x0\r\n\r\n                        BuffDebuff buffInfo = new BuffDebuff\r\n                        {\r\n                            IconId = BuffDebuffManager.BuffTable[iconId],\r\n                            BuffIconType = (BuffIconType) icon,\r\n                            ClilocMessage1 = Language.GetCliloc((int) p.ReadUInt32()),\r\n                            ClilocMessage2 = Language.GetCliloc((int) p.ReadUInt32()),\r\n                            Duration = duration,\r\n                            Timestamp = DateTime.UtcNow\r\n                        };\r\n\r\n                        if (World.Player != null && World.Player.BuffsDebuffs.All(b => b.BuffIconType != buffType))\r\n                        {\r\n                            World.Player.BuffsDebuffs.Add(buffInfo);\r\n\r\n                            BuffDebuffManager.DisplayOverheadBuff(buffInfo);\r\n                        }\r\n\r\n                        break;\r\n\r\n                    case 0x0: // remove\r\n                        if (World.Player != null)\r\n                        {\r\n                            BuffDebuffManager.DisplayOverheadDebuff(buffType);\r\n\r\n                            World.Player.BuffsDebuffs.RemoveAll(b => b.BuffIconType == buffType);\r\n                        }\r\n\r\n                        break;\r\n                }\r\n\r\n                Client.Instance.RequestTitlebarUpdate();\r\n            }\r\n\r\n            if (World.Player != null && World.Player.BuffsDebuffs.Count > 0)\r\n            {\r\n                BuffDebuffManager.Start();\r\n            }\r\n            else\r\n            {\r\n                BuffDebuffManager.Stop();\r\n            }\r\n        }\r\n\r\n        private static void AttackRequest(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (Config.GetBool(\"ShowAttackTargetOverhead\"))\r\n            {\r\n                uint serial = p.ReadUInt32();\r\n\r\n                Mobile m = World.FindMobile(serial);\r\n\r\n                if (m == null) return;\r\n\r\n                World.Player.OverheadMessage(FriendsManager.IsFriend(m.Serial) ? 63 : m.GetNotorietyColorInt(),\r\n                    $\"Attack: {m.Name}\");\r\n            }\r\n        }\r\n\r\n        private static void TradeRequest(PacketReader p, PacketHandlerEventArgs args)\r\n        {\r\n            if (Config.GetBool(\"BlockTradeRequests\"))\r\n            {\r\n                args.Block = true;\r\n            }\r\n        }\r\n\r\n        private static void UnicodePromptSend(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            //uint serial = p.ReadUInt32();\r\n            //uint id = p.ReadUInt32();\r\n            //uint type = p.ReadUInt32();\r\n\r\n            uint serial = p.ReadUInt32();\r\n            uint id = p.ReadUInt32();\r\n            uint type = p.ReadUInt32();\r\n\r\n            string lang = p.ReadStringSafe(4);\r\n            string text = p.ReadUnicodeStringLESafe();\r\n\r\n            World.Player.HasPrompt = false;\r\n            World.Player.PromptSenderSerial = serial;\r\n            World.Player.PromptID = id;\r\n            World.Player.PromptType = type;\r\n            World.Player.PromptInputText = text;\r\n\r\n            if (MacroManager.AcceptActions && !string.IsNullOrEmpty(World.Player.PromptInputText))\r\n            {\r\n                MacroManager.Action(new PromptAction(World.Player.PromptInputText));\r\n            }\r\n\r\n            if (!string.IsNullOrEmpty(World.Player.PromptInputText))\r\n                ScriptManager.AddToScript($\"promptresponse '{World.Player.PromptInputText}'\");\r\n        }\r\n\r\n        private static void UnicodePromptReceived(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            uint serial = p.ReadUInt32();\r\n            uint id = p.ReadUInt32();\r\n            uint type = p.ReadUInt32();\r\n\r\n            World.Player.HasPrompt = true;\r\n            World.Player.PromptSenderSerial = serial;\r\n            World.Player.PromptID = id;\r\n            World.Player.PromptType = type;\r\n\r\n            if (MacroManager.AcceptActions)\r\n            {\r\n                MacroManager.Action(new WaitForPromptAction(id));\r\n            }\r\n\r\n            ScriptManager.AddToScript($\"waitforprompt {id}\");\r\n\r\n            //args.Block = true;\r\n\r\n            //string lang = p.ReadStringSafe(4);\r\n            //string message = p.ReadUnicodeStringSafe();\r\n        }\r\n\r\n        private static void PlaySoundEffect(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            byte type = p.ReadByte();\r\n            ushort sound = p.ReadUInt16();\r\n\r\n            if (Config.GetBool(\"SoundFilterEnabled\"))\r\n            {\r\n                bool blockSound = SoundMusicManager.IsFilteredSound(sound, out string name);\r\n\r\n                if (blockSound)\r\n                {\r\n                    args.Block = true;\r\n\r\n                    if (Config.GetBool(\"ShowFilteredSound\"))\r\n                    {\r\n                        World.Player.SendMessage(MsgLevel.Warning, $\"Blocked Sound: '{name}' (0x{sound:X})\");\r\n                        return;\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (Config.GetBool(\"ShowPlayingSoundInfo\"))\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Info,\r\n                    $\"Playing Sound: '{SoundMusicManager.GetSoundName(sound)}' (0x{sound:X})\");\r\n            }\r\n        }\r\n\r\n        private static void PlayMusic(Packet p, PacketHandlerEventArgs args)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            if (!Config.GetBool(\"ShowMusicInfo\"))\r\n                return;\r\n\r\n            ushort musicId = p.ReadUInt16();\r\n\r\n            World.Player.SendMessage(\r\n                $\"Playing Music: '{SoundMusicManager.GetMusicName(musicId, out bool loop)}' (id: '{musicId}' loop: '{loop}')\");\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Network/Loader.cs",
    "content": "using System;\r\nusing System.Diagnostics;\r\nusing System.Runtime.InteropServices;\r\n\r\nnamespace Assistant\r\n{\r\n\tpublic class Loader\r\n\t{\r\n\t\tpublic enum ERROR_TYPE : int\r\n\t\t{\r\n\t\t\tSUCCESS = 0,\r\n\t\t\tNO_OPEN_EXE,\r\n\t\t\tNO_READ_EXE_DATA,\r\n\r\n\t\t\tNO_RUN_EXE,\r\n\t\t\tNO_ALLOC_MEM,\r\n\r\n\t\t\tNO_WRITE,\r\n\t\t\tNO_VPROTECT,\r\n\t\t\tNO_READ,\r\n\t\t};\r\n\r\n\t\t[DllImport( \"Loader.dll\" )]\r\n\t\tpublic static unsafe extern ERROR_TYPE Load( string exe, string dll, string funcName, ref DLLParameters data, int dataSize, out int pid );\r\n\r\n\t\t[Flags]\r\n\t\tpublic enum DLLFlags  : uint\r\n\t\t{\r\n\t\t\tNone\t\t\t= 0x00000000,\r\n\r\n\t\t\tOSICryptEnabled = 0x00000001,\r\n\t\t\tSmartCPU\t\t= 0x00000002,\r\n\t\t\tTrees\t\t\t= 0x00000004,\r\n\t\t};\r\n\r\n\t\t[StructLayout( LayoutKind.Sequential )]\r\n\t\tpublic struct DLLParameters\r\n\t\t{\r\n\t\t\tpublic DLLFlags Flags;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "Razor/Network/Packet.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.IO;\r\nusing System.Text;\r\n\r\nnamespace Assistant\r\n{\r\n    public enum PacketPath\r\n    {\r\n        ClientToServer,\r\n        RazorToServer,\r\n        ServerToClient,\r\n        RazorToClient\r\n    }\r\n\r\n    public class Packet\r\n    {\r\n        private static bool m_Logging = false;\r\n\r\n        public static bool Logging\r\n        {\r\n            get { return m_Logging; }\r\n            set\r\n            {\r\n                if (value != m_Logging)\r\n                {\r\n                    m_Logging = value;\r\n                    if (m_Logging)\r\n                        BeginLog();\r\n                }\r\n            }\r\n        }\r\n\r\n        public static string PacketsLogFile\r\n        {\r\n            get { return Path.Combine(Config.GetInstallDirectory(), \"Razor_Packets.log\"); }\r\n        }\r\n\r\n        private static void BeginLog()\r\n        {\r\n            using (StreamWriter sw = new StreamWriter(PacketsLogFile, true))\r\n            {\r\n                sw.AutoFlush = true;\r\n                sw.WriteLine();\r\n                sw.WriteLine();\r\n                sw.WriteLine();\r\n                sw.WriteLine(\">>>>>>>>>> Logging started {0} <<<<<<<<<<\", DateTime.UtcNow);\r\n                sw.WriteLine();\r\n                sw.WriteLine();\r\n            }\r\n        }\r\n\r\n        private static byte[] m_Buffer = new byte[4]; // Internal format buffer.\r\n        private MemoryStream m_Stream;\r\n        private bool m_DynSize;\r\n        private byte m_PacketID;\r\n\r\n        public Packet()\r\n        {\r\n            m_Stream = new MemoryStream();\r\n        }\r\n\r\n        public Packet(byte packetID)\r\n        {\r\n            m_PacketID = packetID;\r\n            m_DynSize = true;\r\n        }\r\n\r\n        public Packet(byte packetID, int capacity)\r\n        {\r\n            m_Stream = new MemoryStream(capacity);\r\n\r\n            m_PacketID = packetID;\r\n            m_DynSize = false;\r\n\r\n            m_Stream.WriteByte(packetID);\r\n        }\r\n\r\n        public Packet(byte[] data, int len, bool dynLen)\r\n        {\r\n            m_Stream = new MemoryStream(len);\r\n            m_PacketID = data[0];\r\n            m_DynSize = dynLen;\r\n\r\n            m_Stream.Position = 0;\r\n            m_Stream.Write(data, 0, len);\r\n\r\n            MoveToData();\r\n        }\r\n\r\n\r\n        public void EnsureCapacity(int capacity)\r\n        {\r\n            m_Stream = new MemoryStream(capacity);\r\n            Write((byte) m_PacketID);\r\n            if (m_DynSize)\r\n                Write((short) 0);\r\n        }\r\n\r\n        public byte[] Compile()\r\n        {\r\n            if (m_DynSize)\r\n            {\r\n                m_Stream.Seek(1, SeekOrigin.Begin);\r\n                Write((ushort) m_Stream.Length);\r\n            }\r\n\r\n            return ToArray();\r\n        }\r\n\r\n        public void MoveToData()\r\n        {\r\n            m_Stream.Position = m_DynSize ? 3 : 1;\r\n        }\r\n\r\n        public void Copy(Packet p)\r\n        {\r\n            m_Stream = new MemoryStream((int) p.Length);\r\n            byte[] data = p.ToArray();\r\n            m_Stream.Write(data, 0, data.Length);\r\n\r\n            m_DynSize = p.m_DynSize;\r\n            m_PacketID = p.m_PacketID;\r\n\r\n            MoveToData();\r\n        }\r\n\r\n        /*public override int GetHashCode()\r\n        {\r\n             long oldPos = m_Stream.Position;\r\n\r\n             int code = 0;\r\n\r\n             m_Stream.Position = 0;\r\n\r\n             while ( m_Stream.Length - m_Stream.Position >= 4 )\r\n                  code ^= ReadInt32();\r\n             \r\n             code ^= ReadByte() | (ReadByte() << 8) | (ReadByte() << 16) | (ReadByte() << 24);\r\n\r\n             m_Stream.Position = oldPos;\r\n\r\n             return code;\r\n        }*/\r\n\r\n        public static void Log(string line, params object[] args)\r\n        {\r\n            Log(string.Format(line, args));\r\n        }\r\n\r\n        public static void Log(string line)\r\n        {\r\n            if (!m_Logging)\r\n                return;\r\n\r\n            try\r\n            {\r\n                using (StreamWriter sw = new StreamWriter(PacketsLogFile, true))\r\n                {\r\n                    sw.AutoFlush = true;\r\n                    sw.WriteLine(line);\r\n                    sw.WriteLine();\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public static unsafe void Log(PacketPath path, byte* buff, int len, bool blocked = false)\r\n        {\r\n            if (!m_Logging)\r\n                return;\r\n\r\n            try\r\n            {\r\n                using (StreamWriter sw = new StreamWriter(PacketsLogFile, true))\r\n                {\r\n                    sw.AutoFlush = true;\r\n\r\n                    string pathStr;\r\n                    switch (path)\r\n                    {\r\n                        case PacketPath.ClientToServer:\r\n                            pathStr = \"Client -> Server\";\r\n                            break;\r\n                        case PacketPath.RazorToServer:\r\n                            pathStr = \"Razor -> Server\";\r\n                            break;\r\n                        case PacketPath.ServerToClient:\r\n                            pathStr = \"Server -> Client\";\r\n                            break;\r\n                        case PacketPath.RazorToClient:\r\n                            pathStr = \"Razor -> Client\";\r\n                            break;\r\n                        default:\r\n                            pathStr = \"Unknown -> Unknown\";\r\n                            break;\r\n                    }\r\n\r\n                    sw.WriteLine(\"{0:HH:mm:ss.ffff}: {1}{2}0x{3:X2} (Length: {4})\", Engine.MistedDateTime,\r\n                        pathStr, blocked ? \" [BLOCKED] \" : \" \", buff[0], len);\r\n                    \r\n                    Utility.FormatBuffer(sw, buff, len);\r\n                    \r\n                    sw.WriteLine();\r\n                    sw.WriteLine();\r\n                }\r\n            }\r\n            catch\r\n            {\r\n                // ignored\r\n            }\r\n        }\r\n\r\n        public long Seek(int offset, SeekOrigin origin)\r\n        {\r\n            return m_Stream.Seek(offset, origin);\r\n        }\r\n\r\n        public int ReadInt32()\r\n        {\r\n            if (m_Stream.Position + 4 > m_Stream.Length)\r\n                return 0;\r\n\r\n            return (ReadByte() << 24)\r\n                   | (ReadByte() << 16)\r\n                   | (ReadByte() << 8)\r\n                   | ReadByte();\r\n        }\r\n\r\n        public short ReadInt16()\r\n        {\r\n            if (m_Stream.Position + 2 > m_Stream.Length)\r\n                return 0;\r\n            return (short) ((ReadByte() << 8) | ReadByte());\r\n        }\r\n\r\n        public byte ReadByte()\r\n        {\r\n            if (m_Stream.Position + 1 > m_Stream.Length)\r\n                return 0;\r\n            return (byte) m_Stream.ReadByte();\r\n        }\r\n\r\n        public uint ReadUInt32()\r\n        {\r\n            if (m_Stream.Position + 4 > m_Stream.Length)\r\n                return 0;\r\n            return (uint) ((ReadByte() << 24)\r\n                           | (ReadByte() << 16)\r\n                           | (ReadByte() << 8)\r\n                           | ReadByte());\r\n        }\r\n\r\n        public ushort ReadUInt16()\r\n        {\r\n            if (m_Stream.Position + 2 > m_Stream.Length)\r\n                return 0;\r\n            return (ushort) ((ReadByte() << 8) | ReadByte());\r\n        }\r\n\r\n        public sbyte ReadSByte()\r\n        {\r\n            if (m_Stream.Position + 1 > m_Stream.Length)\r\n                return 0;\r\n            return (sbyte) m_Stream.ReadByte();\r\n        }\r\n\r\n        public bool ReadBoolean()\r\n        {\r\n            if (m_Stream.Position + 1 > m_Stream.Length)\r\n                return false;\r\n            return (m_Stream.ReadByte() != 0);\r\n        }\r\n\r\n        public string ReadUnicodeStringLE()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Stream.Position + 1 < m_Stream.Length && (c = ReadByte() | (ReadByte() << 8)) != 0)\r\n                sb.Append((char) c);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUnicodeStringLESafe()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Stream.Position + 1 < m_Stream.Length && (c = ReadByte() | (ReadByte() << 8)) != 0)\r\n            {\r\n                if (IsSafeChar(c))\r\n                    sb.Append((char) c);\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUnicodeStringSafe()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Stream.Position + 1 < m_Stream.Length && (c = ReadUInt16()) != 0)\r\n            {\r\n                if (IsSafeChar(c))\r\n                    sb.Append((char) c);\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUnicodeString()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Stream.Position + 1 < m_Stream.Length && (c = ReadUInt16()) != 0)\r\n                sb.Append((char) c);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public bool IsSafeChar(int c)\r\n        {\r\n            return (c >= 0x20 && c < 0xFFFE);\r\n        }\r\n\r\n        public string ReadUTF8StringSafe(int fixedLength)\r\n        {\r\n            if (m_Stream.Position >= m_Stream.Length)\r\n                return String.Empty;\r\n\r\n            long bound = m_Stream.Position + fixedLength;\r\n            long end = bound;\r\n\r\n            if (bound > m_Stream.Length)\r\n                bound = m_Stream.Length;\r\n\r\n            int count = 0;\r\n            long index = m_Stream.Position;\r\n            long start = m_Stream.Position;\r\n\r\n            while (index < bound && ReadByte() != 0)\r\n                ++count;\r\n\r\n            m_Stream.Seek(start, SeekOrigin.Begin);\r\n\r\n            index = 0;\r\n\r\n            byte[] buffer = new byte[count];\r\n            int value = 0;\r\n\r\n            while (m_Stream.Position < bound && (value = ReadByte()) != 0)\r\n                buffer[index++] = (byte) value;\r\n\r\n            string s = Encoding.UTF8.GetString(buffer);\r\n\r\n            bool isSafe = true;\r\n\r\n            for (int i = 0; isSafe && i < s.Length; ++i)\r\n                isSafe = IsSafeChar((int) s[i]);\r\n\r\n            m_Stream.Seek(start + fixedLength, SeekOrigin.Begin);\r\n\r\n            if (isSafe)\r\n                return s;\r\n\r\n            StringBuilder sb = new StringBuilder(s.Length);\r\n\r\n            for (int i = 0; i < s.Length; ++i)\r\n            {\r\n                if (IsSafeChar((int) s[i]))\r\n                    sb.Append(s[i]);\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUTF8StringSafe()\r\n        {\r\n            if (m_Stream.Position >= m_Stream.Length)\r\n                return String.Empty;\r\n\r\n            int count = 0;\r\n            long index = m_Stream.Position;\r\n            long start = index;\r\n\r\n            while (index < m_Stream.Length && ReadByte() != 0)\r\n                ++count;\r\n\r\n            m_Stream.Seek(start, SeekOrigin.Begin);\r\n\r\n            index = 0;\r\n\r\n            byte[] buffer = new byte[count];\r\n            int value = 0;\r\n\r\n            while (m_Stream.Position < m_Stream.Length && (value = ReadByte()) != 0)\r\n                buffer[index++] = (byte) value;\r\n\r\n            string s = Encoding.UTF8.GetString(buffer);\r\n\r\n            bool isSafe = true;\r\n\r\n            for (int i = 0; isSafe && i < s.Length; ++i)\r\n                isSafe = IsSafeChar((int) s[i]);\r\n\r\n            if (isSafe)\r\n                return s;\r\n\r\n            StringBuilder sb = new StringBuilder(s.Length);\r\n\r\n            for (int i = 0; i < s.Length; ++i)\r\n            {\r\n                if (IsSafeChar((int) s[i]))\r\n                    sb.Append(s[i]);\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUTF8String()\r\n        {\r\n            if (m_Stream.Position >= m_Stream.Length)\r\n                return String.Empty;\r\n\r\n            int count = 0;\r\n            long index = m_Stream.Position;\r\n            long start = index;\r\n\r\n            while (index < m_Stream.Length && ReadByte() != 0)\r\n                ++count;\r\n\r\n            m_Stream.Seek(start, SeekOrigin.Begin);\r\n\r\n            index = 0;\r\n\r\n            byte[] buffer = new byte[count];\r\n            int value = 0;\r\n\r\n            while (m_Stream.Position < m_Stream.Length && (value = ReadByte()) != 0)\r\n                buffer[index++] = (byte) value;\r\n\r\n            return Encoding.UTF8.GetString(buffer);\r\n        }\r\n\r\n        public string ReadString()\r\n        {\r\n            return ReadStringSafe();\r\n        }\r\n\r\n        public string ReadStringSafe()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Stream.Position < m_Stream.Length && (c = ReadByte()) != 0)\r\n                sb.Append((char) c);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUnicodeStringSafe(int fixedLength)\r\n        {\r\n            return ReadUnicodeString(fixedLength);\r\n        }\r\n\r\n        public string ReadUnicodeString(int fixedLength)\r\n        {\r\n            long bound = m_Stream.Position + (fixedLength << 1);\r\n            long end = bound;\r\n\r\n            if (bound > m_Stream.Length)\r\n                bound = m_Stream.Length;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while ((m_Stream.Position + 1) < bound && (c = ReadUInt16()) != 0)\r\n                if (IsSafeChar(c))\r\n                    sb.Append((char) c);\r\n\r\n            m_Stream.Seek(end, SeekOrigin.Begin);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadStringSafe(int fixedLength)\r\n        {\r\n            return ReadString(fixedLength);\r\n        }\r\n\r\n        public string ReadString(int fixedLength)\r\n        {\r\n            long bound = m_Stream.Position + fixedLength;\r\n\r\n            if (bound > m_Stream.Length)\r\n                bound = m_Stream.Length;\r\n\r\n            long end = bound;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Stream.Position < bound && (c = ReadByte()) != 0)\r\n                sb.Append((char) c);\r\n\r\n            m_Stream.Seek(end, SeekOrigin.Begin);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n\r\n/////////////////////////////////////////////\r\n        ///Packet Writer/////////////////////////////\r\n/////////////////////////////////////////////\r\n        public void Write(bool value)\r\n        {\r\n            m_Stream.WriteByte((byte) (value ? 1 : 0));\r\n        }\r\n\r\n        public void Write(byte value)\r\n        {\r\n            m_Stream.WriteByte(value);\r\n        }\r\n\r\n        public void Write(sbyte value)\r\n        {\r\n            m_Stream.WriteByte((byte) value);\r\n        }\r\n\r\n        public void Write(short value)\r\n        {\r\n            m_Buffer[0] = (byte) (value >> 8);\r\n            m_Buffer[1] = (byte) value;\r\n\r\n            m_Stream.Write(m_Buffer, 0, 2);\r\n        }\r\n\r\n        public void Write(ushort value)\r\n        {\r\n            m_Buffer[0] = (byte) (value >> 8);\r\n            m_Buffer[1] = (byte) value;\r\n\r\n            m_Stream.Write(m_Buffer, 0, 2);\r\n        }\r\n\r\n        public void Write(int value)\r\n        {\r\n            m_Buffer[0] = (byte) (value >> 24);\r\n            m_Buffer[1] = (byte) (value >> 16);\r\n            m_Buffer[2] = (byte) (value >> 8);\r\n            m_Buffer[3] = (byte) value;\r\n\r\n            m_Stream.Write(m_Buffer, 0, 4);\r\n        }\r\n\r\n        public void Write(uint value)\r\n        {\r\n            m_Buffer[0] = (byte) (value >> 24);\r\n            m_Buffer[1] = (byte) (value >> 16);\r\n            m_Buffer[2] = (byte) (value >> 8);\r\n            m_Buffer[3] = (byte) value;\r\n\r\n            m_Stream.Write(m_Buffer, 0, 4);\r\n        }\r\n\r\n        public void Write(byte[] buffer, int offset, int size)\r\n        {\r\n            m_Stream.Write(buffer, offset, size);\r\n        }\r\n\r\n        public void WriteAsciiFixed(string value, int size)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            byte[] buffer = Encoding.ASCII.GetBytes(value);\r\n\r\n            if (buffer.Length >= size)\r\n            {\r\n                m_Stream.Write(buffer, 0, size);\r\n            }\r\n            else\r\n            {\r\n                m_Stream.Write(buffer, 0, buffer.Length);\r\n\r\n                byte[] pad = new byte[size - buffer.Length];\r\n\r\n                m_Stream.Write(pad, 0, pad.Length);\r\n            }\r\n        }\r\n\r\n        public void WriteAsciiNull(string value)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            byte[] buffer = Encoding.ASCII.GetBytes(value);\r\n\r\n            m_Stream.Write(buffer, 0, buffer.Length);\r\n            m_Stream.WriteByte(0);\r\n        }\r\n\r\n        public void WriteLittleUniNull(string value)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            byte[] buffer = Encoding.Unicode.GetBytes(value);\r\n\r\n            m_Stream.Write(buffer, 0, buffer.Length);\r\n\r\n            m_Buffer[0] = 0;\r\n            m_Buffer[1] = 0;\r\n            m_Stream.Write(m_Buffer, 0, 2);\r\n        }\r\n\r\n        public void WriteLittleUniFixed(string value, int size)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            size *= 2;\r\n\r\n            byte[] buffer = Encoding.Unicode.GetBytes(value);\r\n\r\n            if (buffer.Length >= size)\r\n            {\r\n                m_Stream.Write(buffer, 0, size);\r\n            }\r\n            else\r\n            {\r\n                m_Stream.Write(buffer, 0, buffer.Length);\r\n\r\n                byte[] pad = new byte[size - buffer.Length];\r\n\r\n                m_Stream.Write(pad, 0, pad.Length);\r\n            }\r\n        }\r\n\r\n        public void WriteBigUniNull(string value)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            byte[] buffer = Encoding.BigEndianUnicode.GetBytes(value);\r\n\r\n            m_Stream.Write(buffer, 0, buffer.Length);\r\n\r\n            m_Buffer[0] = 0;\r\n            m_Buffer[1] = 0;\r\n            m_Stream.Write(m_Buffer, 0, 2);\r\n        }\r\n\r\n        public void WriteBigUniFixed(string value, int size)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            size *= 2;\r\n\r\n            byte[] buffer = Encoding.BigEndianUnicode.GetBytes(value);\r\n\r\n            if (buffer.Length >= size)\r\n            {\r\n                m_Stream.Write(buffer, 0, size);\r\n            }\r\n            else\r\n            {\r\n                m_Stream.Write(buffer, 0, buffer.Length);\r\n\r\n                byte[] pad = new byte[size - buffer.Length];\r\n\r\n                m_Stream.Write(pad, 0, pad.Length);\r\n            }\r\n        }\r\n\r\n        public void WriteUTF8Fixed(string value, int size)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            size *= 2;\r\n\r\n            byte[] buffer = Encoding.UTF8.GetBytes(value);\r\n\r\n            if (buffer.Length >= size)\r\n            {\r\n                m_Stream.Write(buffer, 0, size);\r\n            }\r\n            else\r\n            {\r\n                m_Stream.Write(buffer, 0, buffer.Length);\r\n\r\n                byte[] pad = new byte[size - buffer.Length];\r\n\r\n                m_Stream.Write(pad, 0, pad.Length);\r\n            }\r\n        }\r\n\r\n        public void WriteUTF8Null(string value)\r\n        {\r\n            if (value == null)\r\n                value = String.Empty;\r\n\r\n            byte[] buffer = Encoding.UTF8.GetBytes(value);\r\n\r\n            m_Stream.Write(buffer, 0, buffer.Length);\r\n            m_Buffer[0] = 0;\r\n            m_Buffer[1] = 0;\r\n            m_Stream.Write(m_Buffer, 0, 2);\r\n        }\r\n\r\n        public void Fill()\r\n        {\r\n            byte[] buffer = new byte[m_Stream.Capacity - Position];\r\n            m_Stream.Write(buffer, 0, buffer.Length);\r\n        }\r\n\r\n        public void Fill(int length)\r\n        {\r\n            m_Stream.Write(new byte[length], 0, length);\r\n        }\r\n\r\n        public int PacketID\r\n        {\r\n            get { return m_PacketID; }\r\n        }\r\n\r\n        public long Length\r\n        {\r\n            get { return m_Stream.Length; }\r\n        }\r\n\r\n        public long Position\r\n        {\r\n            get { return m_Stream.Position; }\r\n            set { m_Stream.Position = value; }\r\n        }\r\n\r\n        public MemoryStream UnderlyingStream\r\n        {\r\n            get { return m_Stream; }\r\n        }\r\n\r\n        public long Seek(long offset, SeekOrigin origin)\r\n        {\r\n            return m_Stream.Seek(offset, origin);\r\n        }\r\n\r\n        public byte[] ToArray()\r\n        {\r\n            return m_Stream.ToArray();\r\n        }\r\n    }\r\n\r\n    public unsafe sealed class PacketReader\r\n    {\r\n        private byte* m_Data;\r\n        private int m_Pos;\r\n        private int m_Length;\r\n        private bool m_Dyn;\r\n\r\n        public PacketReader(byte* buff, int len, bool dyn)\r\n        {\r\n            m_Data = buff;\r\n            m_Length = len;\r\n            m_Pos = 0;\r\n            m_Dyn = dyn;\r\n        }\r\n\r\n        public PacketReader(byte[] buff, bool dyn)\r\n        {\r\n            fixed (byte* p = buff)\r\n                m_Data = p;\r\n            m_Length = buff.Length;\r\n            m_Pos = 0;\r\n            m_Dyn = dyn;\r\n        }\r\n\r\n        public void MoveToData()\r\n        {\r\n            m_Pos = m_Dyn ? 3 : 1;\r\n        }\r\n\r\n        public int Seek(int offset, SeekOrigin origin)\r\n        {\r\n            switch (origin)\r\n            {\r\n                case SeekOrigin.End:\r\n                    m_Pos = m_Length - offset;\r\n                    break;\r\n                case SeekOrigin.Current:\r\n                    m_Pos += offset;\r\n                    break;\r\n                case SeekOrigin.Begin:\r\n                    m_Pos = offset;\r\n                    break;\r\n            }\r\n\r\n            if (m_Pos < 0)\r\n                m_Pos = 0;\r\n            else if (m_Pos > m_Length)\r\n                m_Pos = m_Length;\r\n            return m_Pos;\r\n        }\r\n\r\n        public int Length\r\n        {\r\n            get { return m_Length; }\r\n        }\r\n\r\n        public bool DynamicLength\r\n        {\r\n            get { return m_Dyn; }\r\n        }\r\n\r\n        public byte[] CopyBytes(int offset, int count)\r\n        {\r\n            byte[] read = new byte[count];\r\n            for (m_Pos = offset; m_Pos < offset + count && m_Pos < m_Length; m_Pos++)\r\n                read[m_Pos - offset] = m_Data[m_Pos];\r\n            return read;\r\n        }\r\n\r\n        public PacketReader GetCompressedReader()\r\n        {\r\n            int fullLen = ReadInt32();\r\n            int destLen = 0;\r\n            byte[] buff;\r\n\r\n            if (fullLen >= 4)\r\n            {\r\n                int packLen = ReadInt32();\r\n                destLen = packLen;\r\n\r\n                if (destLen < 0)\r\n                    destLen = 0;\r\n\r\n                buff = new byte[destLen];\r\n\r\n                if (fullLen > 4 && destLen > 0)\r\n                {\r\n                    if (ZLib.uncompress(buff, ref destLen, CopyBytes(this.Position, fullLen - 4), fullLen - 4) !=\r\n                        ZLibError.Z_OK)\r\n                    {\r\n                        destLen = 0;\r\n                        buff = new byte[1];\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    destLen = 0;\r\n                    buff = new byte[1];\r\n                }\r\n            }\r\n            else\r\n            {\r\n                buff = new byte[1];\r\n            }\r\n\r\n            return new PacketReader(buff, false);\r\n        }\r\n\r\n        public byte ReadByte()\r\n        {\r\n            if (m_Pos + 1 > m_Length || m_Data == null)\r\n                return 0;\r\n            return m_Data[m_Pos++];\r\n        }\r\n\r\n        public int ReadInt32()\r\n        {\r\n            return (ReadByte() << 24)\r\n                   | (ReadByte() << 16)\r\n                   | (ReadByte() << 8)\r\n                   | ReadByte();\r\n        }\r\n\r\n        public short ReadInt16()\r\n        {\r\n            return (short) ((ReadByte() << 8) | ReadByte());\r\n        }\r\n\r\n        public uint ReadUInt32()\r\n        {\r\n            return (uint) (\r\n                (ReadByte() << 24)\r\n                | (ReadByte() << 16)\r\n                | (ReadByte() << 8)\r\n                | ReadByte());\r\n        }\r\n\r\n        public ulong ReadRawUInt64()\r\n        {\r\n            return (ulong)\r\n                (((ulong) ReadByte() << 0)\r\n                 | ((ulong) ReadByte() << 8)\r\n                 | ((ulong) ReadByte() << 16)\r\n                 | ((ulong) ReadByte() << 24)\r\n                 | ((ulong) ReadByte() << 32)\r\n                 | ((ulong) ReadByte() << 40)\r\n                 | ((ulong) ReadByte() << 48)\r\n                 | ((ulong) ReadByte() << 56));\r\n        }\r\n\r\n        public ushort ReadUInt16()\r\n        {\r\n            return (ushort) ((ReadByte() << 8) | ReadByte());\r\n        }\r\n\r\n        public sbyte ReadSByte()\r\n        {\r\n            if (m_Pos + 1 > m_Length)\r\n                return 0;\r\n            return (sbyte) m_Data[m_Pos++];\r\n        }\r\n\r\n        public bool ReadBoolean()\r\n        {\r\n            return (ReadByte() != 0);\r\n        }\r\n\r\n        public string ReadUnicodeStringLE()\r\n        {\r\n            return ReadUnicodeString();\r\n        }\r\n\r\n        public string ReadUnicodeStringLESafe()\r\n        {\r\n            return ReadUnicodeStringSafe();\r\n        }\r\n\r\n        public string ReadUnicodeStringSafe()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while ((c = ReadUInt16()) != 0)\r\n            {\r\n                if (IsSafeChar(c))\r\n                    sb.Append((char) c);\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUnicodeString()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while ((c = ReadUInt16()) != 0)\r\n                sb.Append((char) c);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public bool IsSafeChar(int c)\r\n        {\r\n            return (c >= 0x20 && c < 0xFFFE);\r\n        }\r\n\r\n        public string ReadUTF8StringSafe(int fixedLength)\r\n        {\r\n            if (m_Pos >= m_Length)\r\n                return String.Empty;\r\n\r\n            int bound = m_Pos + fixedLength;\r\n            int end = bound;\r\n\r\n            if (bound > m_Length)\r\n                bound = m_Length;\r\n\r\n            int count = 0;\r\n            int index = m_Pos;\r\n            int start = m_Pos;\r\n\r\n            while (index < bound && ReadByte() != 0)\r\n                ++count;\r\n\r\n            Seek(start, SeekOrigin.Begin);\r\n\r\n            index = 0;\r\n\r\n            byte[] buffer = new byte[count];\r\n            int value = 0;\r\n\r\n            while (m_Pos < bound && (value = ReadByte()) != 0)\r\n                buffer[index++] = (byte) value;\r\n\r\n            string s = Encoding.UTF8.GetString(buffer);\r\n\r\n            bool isSafe = true;\r\n\r\n            for (int i = 0; isSafe && i < s.Length; ++i)\r\n                isSafe = IsSafeChar((int) s[i]);\r\n\r\n            Seek(start + fixedLength, SeekOrigin.Begin);\r\n\r\n            if (isSafe)\r\n                return s;\r\n\r\n            StringBuilder sb = new StringBuilder(s.Length);\r\n\r\n            for (int i = 0; i < s.Length; ++i)\r\n            {\r\n                if (IsSafeChar((int) s[i]))\r\n                    sb.Append(s[i]);\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUTF8StringSafe()\r\n        {\r\n            if (m_Pos >= m_Length)\r\n                return String.Empty;\r\n\r\n            int count = 0;\r\n            int index = m_Pos;\r\n            int start = index;\r\n\r\n            while (index < m_Length && ReadByte() != 0)\r\n                ++count;\r\n\r\n            Seek(start, SeekOrigin.Begin);\r\n\r\n            index = 0;\r\n\r\n            byte[] buffer = new byte[count];\r\n            int value = 0;\r\n\r\n            while (m_Pos < m_Length && (value = ReadByte()) != 0)\r\n                buffer[index++] = (byte) value;\r\n\r\n            string s = Encoding.UTF8.GetString(buffer);\r\n\r\n            bool isSafe = true;\r\n\r\n            for (int i = 0; isSafe && i < s.Length; ++i)\r\n                isSafe = IsSafeChar((int) s[i]);\r\n\r\n            if (isSafe)\r\n                return s;\r\n\r\n            StringBuilder sb = new StringBuilder(s.Length);\r\n\r\n            for (int i = 0; i < s.Length; ++i)\r\n            {\r\n                if (IsSafeChar((int) s[i]))\r\n                    sb.Append(s[i]);\r\n            }\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUTF8String()\r\n        {\r\n            if (m_Pos >= m_Length)\r\n                return String.Empty;\r\n\r\n            int count = 0;\r\n            int index = m_Pos;\r\n            int start = index;\r\n\r\n            while (index < m_Length && ReadByte() != 0)\r\n                ++count;\r\n\r\n            Seek(start, SeekOrigin.Begin);\r\n\r\n            index = 0;\r\n\r\n            byte[] buffer = new byte[count];\r\n            int value = 0;\r\n\r\n            while (m_Pos < m_Length && (value = ReadByte()) != 0)\r\n                buffer[index++] = (byte) value;\r\n\r\n            return Encoding.UTF8.GetString(buffer);\r\n        }\r\n\r\n        public string ReadString()\r\n        {\r\n            return ReadStringSafe();\r\n        }\r\n\r\n        public string ReadStringSafe()\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Pos < m_Length && (c = ReadByte()) != 0)\r\n                sb.Append((char) c);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUnicodeStringSafe(int fixedLength)\r\n        {\r\n            return ReadUnicodeString(fixedLength);\r\n        }\r\n\r\n        public string ReadUnicodeString(int fixedLength)\r\n        {\r\n            int bound = m_Pos + (fixedLength << 1);\r\n            int end = bound;\r\n\r\n            if (bound > m_Length)\r\n                bound = m_Length;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while ((m_Pos + 1) < bound && (c = ReadUInt16()) != 0)\r\n                if (IsSafeChar(c))\r\n                    sb.Append((char) c);\r\n\r\n            Seek(end, SeekOrigin.Begin);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadUnicodeStringBE(int fixedLength)\r\n        {\r\n            int bound = m_Pos + (fixedLength << 1);\r\n            int end = bound;\r\n\r\n            if (bound > m_Length)\r\n                bound = m_Length;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while ((m_Pos + 1) < bound)\r\n            {\r\n                c = (ushort) (ReadByte() | (ReadByte() << 8));\r\n                sb.Append((char) c);\r\n            }\r\n\r\n            Seek(end, SeekOrigin.Begin);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public string ReadStringSafe(int fixedLength)\r\n        {\r\n            return ReadString(fixedLength);\r\n        }\r\n\r\n        public string ReadString(int fixedLength)\r\n        {\r\n            int bound = m_Pos + fixedLength;\r\n            int end = bound;\r\n\r\n            if (bound > m_Length)\r\n                bound = m_Length;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            int c;\r\n\r\n            while (m_Pos < bound && (c = ReadByte()) != 0)\r\n                sb.Append((char) c);\r\n\r\n            Seek(end, SeekOrigin.Begin);\r\n\r\n            return sb.ToString();\r\n        }\r\n\r\n        public byte PacketID\r\n        {\r\n            get { return *m_Data; }\r\n        }\r\n\r\n        public int Position\r\n        {\r\n            get { return m_Pos; }\r\n            set { m_Pos = value; }\r\n        }\r\n\r\n        public bool AtEnd\r\n        {\r\n            get { return m_Pos >= m_Length; }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Network/PacketHandler.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\n\r\nnamespace Assistant\r\n{\r\n    public delegate void PacketViewerCallback(PacketReader p, PacketHandlerEventArgs args);\r\n\r\n    public delegate void PacketFilterCallback(Packet p, PacketHandlerEventArgs args);\r\n\r\n    public class PacketHandlerEventArgs\r\n    {\r\n        private bool m_Block;\r\n\r\n        public bool Block\r\n        {\r\n            get { return m_Block; }\r\n            set { m_Block = value; }\r\n        }\r\n\r\n        public PacketHandlerEventArgs()\r\n        {\r\n            Reinit();\r\n        }\r\n\r\n        public void Reinit()\r\n        {\r\n            m_Block = false;\r\n        }\r\n    }\r\n\r\n    public class PacketHandler\r\n    {\r\n        private static Dictionary<int, List<PacketViewerCallback>> m_ClientViewers;\r\n        private static Dictionary<int, List<PacketViewerCallback>> m_ServerViewers;\r\n\r\n        private static Dictionary<int, List<PacketFilterCallback>> m_ClientFilters;\r\n        private static Dictionary<int, List<PacketFilterCallback>> m_ServerFilters;\r\n\r\n        static PacketHandler()\r\n        {\r\n            m_ClientViewers = new Dictionary<int, List<PacketViewerCallback>>();\r\n            m_ServerViewers = new Dictionary<int, List<PacketViewerCallback>>();\r\n\r\n            m_ClientFilters = new Dictionary<int, List<PacketFilterCallback>>();\r\n            m_ServerFilters = new Dictionary<int, List<PacketFilterCallback>>();\r\n        }\r\n\r\n        internal static void RegisterClientToServerViewer(int packetID, PacketViewerCallback callback)\r\n        {\r\n            List<PacketViewerCallback> list;\r\n            if (!m_ClientViewers.TryGetValue(packetID, out list) || list == null)\r\n                m_ClientViewers[packetID] = list = new List<PacketViewerCallback>();\r\n            list.Add(callback);\r\n        }\r\n\r\n        internal static void RegisterServerToClientViewer(int packetID, PacketViewerCallback callback)\r\n        {\r\n            List<PacketViewerCallback> list;\r\n            if (!m_ServerViewers.TryGetValue(packetID, out list) || list == null)\r\n                m_ServerViewers[packetID] = list = new List<PacketViewerCallback>();\r\n            list.Add(callback);\r\n        }\r\n\r\n        internal static void RemoveClientToServerViewer(int packetID, PacketViewerCallback callback)\r\n        {\r\n            List<PacketViewerCallback> list;\r\n            if (m_ClientViewers.TryGetValue(packetID, out list) && list != null)\r\n                list.Remove(callback);\r\n        }\r\n\r\n        internal static void RemoveServerToClientViewer(int packetID, PacketViewerCallback callback)\r\n        {\r\n            List<PacketViewerCallback> list;\r\n            if (m_ServerViewers.TryGetValue(packetID, out list) && list != null)\r\n                list.Remove(callback);\r\n        }\r\n\r\n        internal static void RegisterClientToServerFilter(int packetID, PacketFilterCallback callback)\r\n        {\r\n            List<PacketFilterCallback> list;\r\n            if (!m_ClientFilters.TryGetValue(packetID, out list) || list == null)\r\n                m_ClientFilters[packetID] = list = new List<PacketFilterCallback>();\r\n            list.Add(callback);\r\n        }\r\n\r\n        internal static void RegisterServerToClientFilter(int packetID, PacketFilterCallback callback)\r\n        {\r\n            List<PacketFilterCallback> list;\r\n            if (!m_ServerFilters.TryGetValue(packetID, out list) || list == null)\r\n                m_ServerFilters[packetID] = list = new List<PacketFilterCallback>();\r\n            list.Add(callback);\r\n        }\r\n\r\n        internal static void RemoveClientToServerFilter(int packetID, PacketFilterCallback callback)\r\n        {\r\n            List<PacketFilterCallback> list;\r\n            if (m_ClientFilters.TryGetValue(packetID, out list) && list != null)\r\n                list.Remove(callback);\r\n        }\r\n\r\n        internal static void RemoveServerToClientFilter(int packetID, PacketFilterCallback callback)\r\n        {\r\n            List<PacketFilterCallback> list;\r\n            if (m_ServerFilters.TryGetValue(packetID, out list) && list != null)\r\n                list.Remove(callback);\r\n        }\r\n\r\n        public static bool OnServerPacket(int id, PacketReader pr, Packet p)\r\n        {\r\n            bool result = false;\r\n            if (pr != null)\r\n            {\r\n                List<PacketViewerCallback> list;\r\n                if (m_ServerViewers.TryGetValue(id, out list) && list != null && list.Count > 0)\r\n                    result = ProcessViewers(list, pr);\r\n            }\r\n\r\n            if (p != null)\r\n            {\r\n                List<PacketFilterCallback> list;\r\n                if (m_ServerFilters.TryGetValue(id, out list) && list != null && list.Count > 0)\r\n                    result |= ProcessFilters(list, p);\r\n            }\r\n\r\n            return result;\r\n        }\r\n\r\n\r\n        public static bool OnClientPacket(int id, PacketReader pr, Packet p)\r\n        {\r\n            bool result = false;\r\n            if (pr != null)\r\n            {\r\n                List<PacketViewerCallback> list;\r\n                if (m_ClientViewers.TryGetValue(id, out list) && list != null && list.Count > 0)\r\n                    result = ProcessViewers(list, pr);\r\n            }\r\n\r\n            if (p != null)\r\n            {\r\n                List<PacketFilterCallback> list;\r\n                if (m_ClientFilters.TryGetValue(id, out list) && list != null && list.Count > 0)\r\n                    result |= ProcessFilters(list, p);\r\n            }\r\n\r\n            return result;\r\n        }\r\n\r\n        public static bool HasClientViewer(int packetID)\r\n        {\r\n            List<PacketViewerCallback> list;\r\n            return m_ClientViewers.TryGetValue(packetID, out list) && list != null && list.Count > 0;\r\n        }\r\n\r\n        public static bool HasServerViewer(int packetID)\r\n        {\r\n            List<PacketViewerCallback> list;\r\n            return m_ServerViewers.TryGetValue(packetID, out list) && list != null && list.Count > 0;\r\n        }\r\n\r\n        public static bool HasClientFilter(int packetID)\r\n        {\r\n            List<PacketFilterCallback> list;\r\n            return (m_ClientFilters.TryGetValue(packetID, out list) && list != null && list.Count > 0);\r\n        }\r\n\r\n        public static bool HasServerFilter(int packetID)\r\n        {\r\n            List<PacketFilterCallback> list;\r\n            return (m_ServerFilters.TryGetValue(packetID, out list) && list != null && list.Count > 0);\r\n        }\r\n\r\n        private static PacketHandlerEventArgs m_Args = new PacketHandlerEventArgs();\r\n\r\n        private static bool ProcessViewers(List<PacketViewerCallback> list, PacketReader p)\r\n        {\r\n            m_Args.Reinit();\r\n\r\n            if (list != null)\r\n            {\r\n                int count = list.Count;\r\n                for (int i = 0; i < count; i++)\r\n                {\r\n                    p.MoveToData();\r\n\r\n                    try\r\n                    {\r\n                        list[i](p, m_Args);\r\n                    }\r\n                    catch (Exception e)\r\n                    {\r\n                        Engine.LogCrash(e);\r\n                        new MessageDialog(\"WARNING: Packet viewer exception!\", true, e.ToString()).Show();\r\n                    }\r\n                }\r\n            }\r\n\r\n            return m_Args.Block;\r\n        }\r\n\r\n        private static bool ProcessFilters(List<PacketFilterCallback> list, Packet p)\r\n        {\r\n            m_Args.Reinit();\r\n\r\n            if (list != null)\r\n            {\r\n                for (int i = 0; i < list.Count; i++)\r\n                {\r\n                    p.MoveToData();\r\n\r\n                    try\r\n                    {\r\n                        list[i](p, m_Args);\r\n                    }\r\n                    catch (Exception e)\r\n                    {\r\n                        Engine.LogCrash(e);\r\n                        new MessageDialog(\"WARNING: Packet filter exception!\", true, e.ToString()).Show();\r\n                    }\r\n                }\r\n            }\r\n\r\n            return m_Args.Block;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Network/PacketTable.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\n\nnamespace Assistant\n{\n    public static class PacketsTable\n    {\n        private static readonly short[] _packetsTable = new short[255]\n        {\n            0x0068, // 0x00\n            0x0005, // 0x01\n            0x0007, // 0x02\n            -1, // 0x03\n            0x0002, // 0x04\n            0x0005, // 0x05\n            0x0005, // 0x06\n            0x0007, // 0x07\n            0x000E, // 0x08\n            0x0005, // 0x09\n            0x000B, // 0x0A\n            0x010A, // 0x0B\n            -1, // 0x0C\n            0x0003, // 0x0D\n            -1, // 0x0E\n            0x003D, // 0x0F\n            0x00D7, // 0x10\n            -1, // 0x11\n            -1, // 0x12\n            0x000A, // 0x13\n            0x0006, // 0x14\n            0x0009, // 0x15\n            0x0001, // 0x16\n            -1, // 0x17\n            -1, // 0x18\n            -1, // 0x19\n            -1, // 0x1A\n            0x0025, // 0x1B\n            -1, // 0x1C\n            0x0005, // 0x1D\n            0x0004, // 0x1E\n            0x0008, // 0x1F\n            0x0013, // 0x20\n            0x0008, // 0x21\n            0x0003, // 0x22\n            0x001A, // 0x23\n            0x0007, // 0x24\n            0x0014, // 0x25\n            0x0005, // 0x26\n            0x0002, // 0x27\n            0x0005, // 0x28\n            0x0001, // 0x29\n            0x0005, // 0x2A\n            0x0002, // 0x2B\n            0x0002, // 0x2C\n            0x0011, // 0x2D\n            0x000F, // 0x2E\n            0x000A, // 0x2F\n            0x0005, // 0x30\n            0x0001, // 0x31\n            0x0002, // 0x32\n            0x0002, // 0x33\n            0x000A, // 0x34\n            0x028D, // 0x35\n            -1, // 0x36\n            0x0008, // 0x37\n            0x0007, // 0x38\n            0x0009, // 0x39\n            -1, // 0x3A\n            -1, // 0x3B\n            -1, // 0x3C\n            0x0002, // 0x3D\n            0x0025, // 0x3E\n            -1, // 0x3F\n            0x00C9, // 0x40\n            -1, // 0x41\n            -1, // 0x42\n            0x0229, // 0x43\n            0x02C9, // 0x44\n            0x0005, // 0x45\n            -1, // 0x46\n            0x000B, // 0x47\n            0x0049, // 0x48\n            0x005D, // 0x49\n            0x0005, // 0x4A\n            0x0009, // 0x4B\n            -1, // 0x4C\n            -1, // 0x4D\n            0x0006, // 0x4E\n            0x0002, // 0x4F\n            -1, // 0x50\n            -1, // 0x51\n            -1, // 0x52\n            0x0002, // 0x53\n            0x000C, // 0x54\n            0x0001, // 0x55\n            0x000B, // 0x56\n            0x006E, // 0x57\n            0x006A, // 0x58\n            -1, // 0x59\n            -1, // 0x5A\n            0x0004, // 0x5B\n            0x0002, // 0x5C\n            0x0049, // 0x5D\n            -1, // 0x5E\n            0x0031, // 0x5F\n            0x0005, // 0x60\n            0x0009, // 0x61\n            0x000F, // 0x62\n            0x000D, // 0x63\n            0x0001, // 0x64\n            0x0004, // 0x65\n            -1, // 0x66\n            0x0015, // 0x67\n            -1, // 0x68\n            -1, // 0x69\n            0x0003, // 0x6A\n            0x0009, // 0x6B\n            0x0013, // 0x6C\n            0x0003, // 0x6D\n            0x000E, // 0x6E\n            -1, // 0x6F\n            0x001C, // 0x70\n            -1, // 0x71\n            0x0005, // 0x72\n            0x0002, // 0x73\n            -1, // 0x74\n            0x0023, // 0x75\n            0x0010, // 0x76\n            0x0011, // 0x77\n            -1, // 0x78\n            0x0009, // 0x79\n            -1, // 0x7A\n            0x0002, // 0x7B\n            -1, // 0x7C\n            0x000D, // 0x7D\n            0x0002, // 0x7E\n            -1, // 0x7F\n            0x003E, // 0x80\n            -1, // 0x81\n            0x0002, // 0x82\n            0x0027, // 0x83\n            0x0045, // 0x84\n            0x0002, // 0x85\n            -1, // 0x86\n            -1, // 0x87\n            0x0042, // 0x88\n            -1, // 0x89\n            -1, // 0x8A\n            -1, // 0x8B\n            0x000B, // 0x8C\n            -1, // 0x8D\n            -1, // 0x8E\n            -1, // 0x8F\n            0x0013, // 0x90\n            0x0041, // 0x91\n            -1, // 0x92\n            0x0063, // 0x93\n            -1, // 0x94\n            0x0009, // 0x95\n            -1, // 0x96\n            0x0002, // 0x97\n            -1, // 0x98\n            0x001A, // 0x99\n            -1, // 0x9A\n            0x0102, // 0x9B\n            0x0135, // 0x9C\n            0x0033, // 0x9D\n            -1, // 0x9E\n            -1, // 0x9F\n            0x0003, // 0xA0\n            0x0009, // 0xA1\n            0x0009, // 0xA2\n            0x0009, // 0xA3\n            0x0095, // 0xA4\n            -1, // 0xA5\n            -1, // 0xA6\n            0x0004, // 0xA7\n            -1, // 0xA8\n            -1, // 0xA9\n            0x0005, // 0xAA\n            -1, // 0xAB\n            -1, // 0xAC\n            -1, // 0xAD\n            -1, // 0xAE\n            0x000D, // 0xAF\n            -1, // 0xB0\n            -1, // 0xB1\n            -1, // 0xB2\n            -1, // 0xB3\n            -1, // 0xB4\n            0x0040, // 0xB5\n            0x0009, // 0xB6\n            -1, // 0xB7\n            -1, // 0xB8\n            0x0003, // 0xB9 //aggiornato da 3 a 5\n            0x0006, // 0xBA\n            0x0009, // 0xBB\n            0x0003, // 0xBC\n            -1, // 0xBD\n            -1, // 0xBE\n            -1, // 0xBF\n            0x0024, // 0xC0\n            -1, // 0xC1\n            -1, // 0xC2\n            -1, // 0xC3\n            0x0006, // 0xC4\n            0x00CB, // 0xC5\n            0x0001, // 0xC6\n            0x0031, // 0xC7\n            0x0002, // 0xC8\n            0x0006, // 0xC9\n            0x0006, // 0xCA\n            0x0007, // 0xCB\n            -1, // 0xCC\n            0x0001, // 0xCD\n            -1, // 0xCE\n            0x004E, // 0xCF\n            -1, // 0xD0\n            0x0002, // 0xD1\n            0x0019, // 0xD2\n            -1, // 0xD3\n            -1, // 0xD4\n            -1, // 0xD5\n            -1, // 0xD6\n            -1, // 0xD7\n            -1, // 0xD8\n            0x010C, // 0xD9\n            -1, // 0xDA\n            -1, // 0xDB\n            0x09, // dc\n            -1, // dd\n            -1, // de\n            -1, // df\n            -1, // e0\n            -1, // e1\n            0x0A, // e2\n            -1, // e3\n            -1, // e4\n            -1, // e5\n            0x05, // e6\n            0x0C, // e7\n            0x0D, // e8\n            0x4B, // e9\n            0x03, // ea\n            -1, // eb\n            -1, // ec\n            -1, // ed\n            0x0A, // ee\n            0x0015, // ef -> mortacci tua\n            -1, // f0\n            0x09, // f1\n            0x19, // f2\n            0x1A, // f3 -> altro mortacci tua\n            -1, // f4\n            0x15, // f5\n            -1, // f6\n            -1, // f7\n            0x6A, // f8\n            -1, // f9\n            0x01, // fa\n            0x02, // fb\n            -1, // fc\n            -1, // fd\n            -1 // ff\n        };\n\n        public static unsafe short GetPacketLength(byte* buff, int length)\n        {\n            if (length <= 0)\n            {\n                return 0;\n            }\n\n            short len = _packetsTable[buff[0]];\n\n            if (len >= 0)\n                return len;\n\n            if (length >= 3)\n            {\n                return (short) (buff[1] << 8 | buff[2]);\n            }\n\n            return 0;\n        }\n\n        public static bool IsDynLength(byte id)\n        {\n            return (_packetsTable[id] == -1);\n        }\n\n        public static void AdjustPacketSizeByVersion(Version version)\n        {\n            /* TODO: This should really be 5.0.0.a */\n            if (version >= new Version(5, 0, 0, 0))\n            {\n                _packetsTable[0x0B] = 0x07;\n                _packetsTable[0x16] = -1;\n                _packetsTable[0x31] = -1;\n            }\n            else\n            {\n                _packetsTable[0x0B] = 0x10A;\n                _packetsTable[0x16] = 0x01;\n                _packetsTable[0x31] = 0x01;\n            }\n\n            if (version >= new Version(5, 0, 9, 0))\n                _packetsTable[0xE1] = -1;\n            else\n                _packetsTable[0xE1] = 0x09;\n\n            if (version >= new Version(6, 0, 13, 0))\n            {\n                _packetsTable[0xE3] = -1;\n                _packetsTable[0xE6] = 0x05;\n                _packetsTable[0xE7] = 0x0C;\n                _packetsTable[0xE8] = 0x0D;\n                _packetsTable[0xE9] = 0x4B;\n                _packetsTable[0xEA] = 0x03;\n            }\n            else\n            {\n                _packetsTable[0xE3] = 0x4D;\n                _packetsTable[0xE6] = -1;\n                _packetsTable[0xE7] = -1;\n                _packetsTable[0xE8] = -1;\n                _packetsTable[0xE9] = -1;\n                _packetsTable[0xEA] = -1;\n            }\n\n            if (version >= new Version(6, 0, 17, 0))\n            {\n                _packetsTable[0x08] = 0x0F;\n                _packetsTable[0x25] = 0x15;\n            }\n            else\n            {\n                _packetsTable[0x08] = 0x0E;\n                _packetsTable[0x25] = 0x14;\n            }\n\n            if (version >= new Version(6, 0, 6, 0))\n            {\n                _packetsTable[0xEE] = 0x2000;\n                _packetsTable[0xEF] = 0x2000;\n                _packetsTable[0xF1] = 0x09;\n            }\n            else\n            {\n                _packetsTable[0xEE] = -1;\n                _packetsTable[0xEF] = 0x15;\n                _packetsTable[0xF1] = -1;\n            }\n\n            if (version >= new Version(6, 0, 14, 2))\n                _packetsTable[0xB9] = 0x05;\n            else\n                _packetsTable[0xB9] = 0x03;\n\n            if (version >= new Version(7, 0, 0, 0))\n            {\n                _packetsTable[0xEE] = 0x0A; //0x2000;\n                _packetsTable[0xEF] = 0x15; //0x2000;\n            }\n            else\n            {\n                _packetsTable[0xEE] = -1;\n                _packetsTable[0xEF] = 0x15;\n            }\n\n            if (version >= new Version(7, 0, 9, 0))\n            {\n                _packetsTable[0x24] = 0x09;\n                _packetsTable[0x99] = 0x1E;\n                _packetsTable[0xBA] = 0x0A;\n                _packetsTable[0xF3] = 0x1A;\n                _packetsTable[0xF1] = 0x09;\n                _packetsTable[0xF2] = 0x19;\n            }\n            else\n            {\n                _packetsTable[0x24] = 0x07;\n                _packetsTable[0x99] = 0x1A;\n                _packetsTable[0xBA] = 0x06;\n                _packetsTable[0xF3] = 0x18;\n                _packetsTable[0xF1] = -1;\n                _packetsTable[0xF2] = -1;\n            }\n\n            if (version >= new Version(7, 0, 18, 0))\n                _packetsTable[0x00] = 0x6A;\n            else\n                _packetsTable[0x00] = 0x68;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Network/PacketWriter.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\n/***************************************************************************\n *\n *   This program is free software; you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation; either version 2 of the License, or\n *   (at your option) any later version.\n *\n ***************************************************************************/\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text;\n\nnamespace Assistant.Network\n{\n    /// <summary>\n    ///     Provides functionality for writing primitive binary data.\n    /// </summary>\n    public class PacketWriter : IDisposable\n    {\n        private static readonly Stack<PacketWriter> Pool = new Stack<PacketWriter>();\n\n        /// <summary>\n        ///     Internal format buffer.\n        /// </summary>\n        private readonly byte[] _buffer = new byte[4];\n\n        /// <summary>\n        ///     Internal stream which holds the entire packet.\n        /// </summary>\n        private readonly MemoryStream _stream;\n\n        private int m_Capacity;\n\n        /// <summary>\n        ///     Instantiates a new PacketWriter instance with the default capacity of 4 bytes.\n        /// </summary>\n        public PacketWriter() : this( 32 )\n        {\n        }\n\n        /// <summary>\n        ///     Instantiates a new PacketWriter instance with a given capacity.\n        /// </summary>\n        /// <param name=\"capacity\">Initial capacity for the internal stream.</param>\n        public PacketWriter( int capacity )\n        {\n            _stream = new MemoryStream( capacity );\n            m_Capacity = capacity;\n        }\n\n        /// <summary>\n        ///     Gets the total stream length.\n        /// </summary>\n        public long Length => _stream.Length;\n\n        /// <summary>\n        ///     Gets or sets the current stream position.\n        /// </summary>\n        public long Position\n        {\n            get => _stream.Position;\n            set => _stream.Position = value;\n        }\n\n        /// <summary>\n        ///     The internal stream used by this PacketWriter instance.\n        /// </summary>\n        public MemoryStream UnderlyingStream => _stream;\n\n        public void Dispose()\n        {\n            Dispose( true );\n            GC.SuppressFinalize( this );\n        }\n\n        public static PacketWriter CreateInstance()\n        {\n            return CreateInstance( 32 );\n        }\n\n        public static PacketWriter CreateInstance( int capacity )\n        {\n            PacketWriter pw = null;\n\n            lock ( Pool )\n            {\n                if ( Pool.Count > 0 )\n                {\n                    pw = Pool.Pop();\n\n                    if ( pw != null )\n                    {\n                        pw.m_Capacity = capacity;\n                        pw._stream.SetLength( 0 );\n                    }\n                }\n            }\n\n            return pw ?? new PacketWriter( capacity );\n        }\n\n        public static void ReleaseInstance( PacketWriter pw )\n        {\n            lock ( Pool )\n            {\n                if ( !Pool.Contains( pw ) )\n                {\n                    Pool.Push( pw );\n                }\n                else\n                {\n                    try\n                    {\n                        using ( StreamWriter op = new StreamWriter( \"neterr.log\" ) )\n                        {\n                            op.WriteLine( \"{0}\\tInstance pool contains writer\", DateTime.UtcNow );\n                        }\n                    }\n                    catch\n                    {\n                        Console.WriteLine( @\"net error\" );\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        ///     Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1.\n        /// </summary>\n        public void Write( bool value )\n        {\n            _stream.WriteByte( (byte) ( value ? 1 : 0 ) );\n        }\n\n        /// <summary>\n        ///     Writes a 1-byte unsigned integer value to the underlying stream.\n        /// </summary>\n        public void Write( byte value )\n        {\n            _stream.WriteByte( value );\n        }\n\n        /// <summary>\n        ///     Writes a 1-byte signed integer value to the underlying stream.\n        /// </summary>\n        public void Write( sbyte value )\n        {\n            _stream.WriteByte( (byte) value );\n        }\n\n        /// <summary>\n        ///     Writes a 2-byte signed integer value to the underlying stream.\n        /// </summary>\n        public void Write( short value )\n        {\n            _buffer[0] = (byte) ( value >> 8 );\n            _buffer[1] = (byte) value;\n\n            _stream.Write( _buffer, 0, 2 );\n        }\n\n        /// <summary>\n        ///     Writes a 2-byte unsigned integer value to the underlying stream.\n        /// </summary>\n        public void Write( ushort value )\n        {\n            _buffer[0] = (byte) ( value >> 8 );\n            _buffer[1] = (byte) value;\n\n            _stream.Write( _buffer, 0, 2 );\n        }\n\n        /// <summary>\n        ///     Writes a 4-byte signed integer value to the underlying stream.\n        /// </summary>\n        public void Write( int value )\n        {\n            _buffer[0] = (byte) ( value >> 24 );\n            _buffer[1] = (byte) ( value >> 16 );\n            _buffer[2] = (byte) ( value >> 8 );\n            _buffer[3] = (byte) value;\n\n            _stream.Write( _buffer, 0, 4 );\n        }\n\n        /// <summary>\n        ///     Writes a 4-byte unsigned integer value to the underlying stream.\n        /// </summary>\n        public void Write( uint value )\n        {\n            _buffer[0] = (byte) ( value >> 24 );\n            _buffer[1] = (byte) ( value >> 16 );\n            _buffer[2] = (byte) ( value >> 8 );\n            _buffer[3] = (byte) value;\n\n            _stream.Write( _buffer, 0, 4 );\n        }\n\n        /// <summary>\n        ///     Writes a sequence of bytes to the underlying stream\n        /// </summary>\n        public void Write( byte[] buffer, int offset, int size )\n        {\n            _stream.Write( buffer, offset, size );\n        }\n\n        /// <summary>\n        ///     Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is\n        ///     either truncated or padded with null characters.\n        /// </summary>\n        public void WriteAsciiFixed( string value, int size )\n        {\n            if ( value == null )\n            {\n                Console.WriteLine( @\"Network: Attempted to WriteAsciiFixed() with null value\" );\n                value = string.Empty;\n            }\n\n            int length = value.Length;\n\n            _stream.SetLength( _stream.Length + size );\n\n            if ( length >= size )\n            {\n                _stream.Position +=\n                    Encoding.ASCII.GetBytes( value, 0, size, _stream.GetBuffer(), (int) _stream.Position );\n            }\n            else\n            {\n                Encoding.ASCII.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n                _stream.Position += size;\n            }\n\n            /*byte[] buffer = Encoding.ASCII.GetBytes( value );\n\n\t\t\tif ( buffer.Length >= size )\n\t\t\t{\n\t\t\t\tm_Stream.Write( buffer, 0, size );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tm_Stream.Write( buffer, 0, buffer.Length );\n\t\t\t\tFill( size - buffer.Length );\n\t\t\t}*/\n        }\n\n        /// <summary>\n        ///     Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character.\n        /// </summary>\n        public void WriteAsciiNull( string value )\n        {\n            if ( value == null )\n            {\n                Console.WriteLine( @\"Network: Attempted to WriteAsciiNull() with null value\" );\n                value = string.Empty;\n            }\n\n            int length = value.Length;\n\n            _stream.SetLength( _stream.Length + length + 1 );\n\n            Encoding.ASCII.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n            _stream.Position += length + 1;\n\n            /*byte[] buffer = Encoding.ASCII.GetBytes( value );\n\n\t\t\tm_Stream.Write( buffer, 0, buffer.Length );\n\t\t\tm_Stream.WriteByte( 0 );*/\n        }\n\n        /// <summary>\n        ///     Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null\n        ///     character.\n        /// </summary>\n        public void WriteLittleUniNull( string value )\n        {\n            if ( value == null )\n            {\n                Console.WriteLine( @\"Network: Attempted to WriteLittleUniNull() with null value\" );\n                value = string.Empty;\n            }\n\n            int length = value.Length;\n\n            _stream.SetLength( _stream.Length + ( length + 1 ) * 2 );\n\n            _stream.Position +=\n                Encoding.Unicode.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n            _stream.Position += 2;\n\n            /*byte[] buffer = Encoding.Unicode.GetBytes( value );\n\n\t\t\tm_Stream.Write( buffer, 0, buffer.Length );\n\n\t\t\tm_Buffer[0] = 0;\n\t\t\tm_Buffer[1] = 0;\n\t\t\tm_Stream.Write( m_Buffer, 0, 2 );*/\n        }\n\n        /// <summary>\n        ///     Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string\n        ///     content is either truncated or padded with null characters.\n        /// </summary>\n        public void WriteLittleUniFixed( string value, int size )\n        {\n            if ( value == null )\n            {\n                Console.WriteLine( @\"Network: Attempted to WriteLittleUniFixed() with null value\" );\n                value = string.Empty;\n            }\n\n            size *= 2;\n\n            int length = value.Length;\n\n            _stream.SetLength( _stream.Length + size );\n\n            if ( length * 2 >= size )\n            {\n                _stream.Position +=\n                    Encoding.Unicode.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n            }\n            else\n            {\n                Encoding.Unicode.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n                _stream.Position += size;\n            }\n\n            /*size *= 2;\n\n\t\t\tbyte[] buffer = Encoding.Unicode.GetBytes( value );\n\n\t\t\tif ( buffer.Length >= size )\n\t\t\t{\n\t\t\t\tm_Stream.Write( buffer, 0, size );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tm_Stream.Write( buffer, 0, buffer.Length );\n\t\t\t\tFill( size - buffer.Length );\n\t\t\t}*/\n        }\n\n        /// <summary>\n        ///     Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null\n        ///     character.\n        /// </summary>\n        public void WriteBigUniNull( string value )\n        {\n            if ( value == null )\n            {\n                Console.WriteLine( @\"Network: Attempted to WriteBigUniNull() with null value\" );\n                value = string.Empty;\n            }\n\n            int length = value.Length;\n\n            _stream.SetLength( _stream.Length + ( length + 1 ) * 2 );\n\n            _stream.Position +=\n                Encoding.BigEndianUnicode.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n            _stream.Position += 2;\n\n            /*byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );\n\n\t\t\tm_Stream.Write( buffer, 0, buffer.Length );\n\n\t\t\tm_Buffer[0] = 0;\n\t\t\tm_Buffer[1] = 0;\n\t\t\tm_Stream.Write( m_Buffer, 0, 2 );*/\n        }\n\n        /// <summary>\n        ///     Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content\n        ///     is either truncated or padded with null characters.\n        /// </summary>\n        public void WriteBigUniFixed( string value, int size )\n        {\n            if ( value == null )\n            {\n                Console.WriteLine( @\"Network: Attempted to WriteBigUniFixed() with null value\" );\n                value = string.Empty;\n            }\n\n            size *= 2;\n\n            int length = value.Length;\n\n            _stream.SetLength( _stream.Length + size );\n\n            if ( length * 2 >= size )\n            {\n                _stream.Position +=\n                    Encoding.BigEndianUnicode.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n            }\n            else\n            {\n                Encoding.BigEndianUnicode.GetBytes( value, 0, length, _stream.GetBuffer(), (int) _stream.Position );\n                _stream.Position += size;\n            }\n\n            /*size *= 2;\n\n\t\t\tbyte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );\n\n\t\t\tif ( buffer.Length >= size )\n\t\t\t{\n\t\t\t\tm_Stream.Write( buffer, 0, size );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tm_Stream.Write( buffer, 0, buffer.Length );\n\t\t\t\tFill( size - buffer.Length );\n\t\t\t}*/\n        }\n\n        /// <summary>\n        ///     Fills the stream from the current position up to (capacity) with 0x00's\n        /// </summary>\n        public void Fill()\n        {\n            Fill( (int) ( m_Capacity - _stream.Length ) );\n        }\n\n        /// <summary>\n        ///     Writes a number of 0x00 byte values to the underlying stream.\n        /// </summary>\n        public void Fill( int length )\n        {\n            if ( _stream.Position == _stream.Length )\n            {\n                _stream.SetLength( _stream.Length + length );\n                _stream.Seek( 0, SeekOrigin.End );\n            }\n            else\n            {\n                _stream.Write( new byte[length], 0, length );\n            }\n        }\n\n        /// <summary>\n        ///     Offsets the current position from an origin.\n        /// </summary>\n        public long Seek( long offset, SeekOrigin origin )\n        {\n            return _stream.Seek( offset, origin );\n        }\n\n        /// <summary>\n        ///     Gets the entire stream content as a byte array.\n        /// </summary>\n        public byte[] ToArray()\n        {\n            return _stream.ToArray();\n        }\n\n        protected virtual void Dispose( bool isDisposing )\n        {\n            if ( isDisposing )\n            {\n                _stream.Dispose();\n            }\n\n            GC.SuppressFinalize( this );\n        }\n    }\n}"
  },
  {
    "path": "Razor/Network/Packets.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing Assistant.Agents;\r\nusing Ultima;\r\n\r\nnamespace Assistant\r\n{\r\n    public enum MessageType\r\n    {\r\n        Regular = 0x00,\r\n        System = 0x01,\r\n        Emote = 0x02,\r\n        Label = 0x06,\r\n        Focus = 0x07,\r\n        Whisper = 0x08,\r\n        Yell = 0x09,\r\n        Spell = 0x0A,\r\n        Guild = 0x0D,\r\n        Alliance = 0x0E,\r\n        Encoded = 0xC0,\r\n\r\n        Special = 0x20\r\n    }\r\n\r\n    public sealed class QueryPartyLocs : Packet\r\n    {\r\n        public QueryPartyLocs() : base(0xF0)\r\n        {\r\n            EnsureCapacity(4);\r\n            Write((byte) 0x00);\r\n        }\r\n    }\r\n\r\n    public sealed class SendPartyMessage : Packet\r\n    {\r\n        public SendPartyMessage(string message) : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 1 + 4);\r\n\r\n            Write((ushort) 0x06); // party command\r\n            Write((byte) 0x04); // tell party\r\n            WriteBigUniNull(message);\r\n        }\r\n    }\r\n\r\n    public sealed class AcceptParty : Packet\r\n    {\r\n        public AcceptParty(Serial leader) : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 1 + 4);\r\n\r\n            Write((ushort) 0x06); // party command\r\n            Write((byte) 0x08); // accept\r\n            Write((uint) leader);\r\n        }\r\n    }\r\n\r\n    public sealed class DeclineParty : Packet\r\n    {\r\n        public DeclineParty(Serial leader) : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 1 + 4);\r\n\r\n            Write((ushort) 0x06); // party command\r\n            Write((byte) 0x09); // decline\r\n            Write((uint) leader);\r\n        }\r\n    }\r\n\r\n    public sealed class AddParty : Packet\r\n    {\r\n        public AddParty() : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 1 + 4);\r\n\r\n            Write((ushort)0x06); // party command\r\n            Write((byte)0x01); // add party\r\n            Write(0);\r\n        }\r\n    }\r\n\r\n    public sealed class SendMessageParty : Packet\r\n    {\r\n        public SendMessageParty(string message) : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 1 + 4);\r\n\r\n            Write((ushort) 0x06); // party command\r\n            Write((byte) 0x04); // tell party\r\n            WriteBigUniNull(message);\r\n        }\r\n    }\r\n\r\n    public sealed class ContainerContent : Packet\r\n    {\r\n        public ContainerContent(List<Item> items) : this(items, Engine.UsePostKRPackets)\r\n        {\r\n        }\r\n\r\n        public ContainerContent(List<Item> items, bool useKR) : base(0x3C)\r\n        {\r\n            Write((ushort) items.Count);\r\n\r\n            foreach (Item item in items)\r\n            {\r\n                Write((uint) item.Serial);\r\n                Write((ushort) item.ItemID);\r\n                Write((sbyte) 0);\r\n                Write((ushort) item.Amount);\r\n                Write((ushort) item.Position.X);\r\n                Write((ushort) item.Position.Y);\r\n\r\n                if (useKR)\r\n                    Write((byte) item.GridNum);\r\n\r\n                if (item.Container is Item)\r\n                    Write((uint) ((Item) item.Container).Serial);\r\n                else\r\n                    Write((uint) 0);\r\n                Write((ushort) item.Hue);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class ContainerItem : Packet\r\n    {\r\n        public ContainerItem(Item item) : this(item, Engine.UsePostKRPackets)\r\n        {\r\n        }\r\n\r\n        public ContainerItem(Item item, bool isKR) : base(0x25, 20)\r\n        {\r\n            if (isKR)\r\n                EnsureCapacity(21);\r\n\r\n            Write(item.Serial);\r\n\r\n            Write(item.ItemID);\r\n            Write((byte) 0);\r\n            Write(item.Amount);\r\n            Write((ushort) item.Position.X);\r\n            Write((ushort) item.Position.Y);\r\n\r\n            if (isKR)\r\n                Write(item.GridNum);\r\n\r\n            object cont = item.Container;\r\n            if (cont is UOEntity)\r\n                Write((uint) ((UOEntity) item.Container).Serial);\r\n            else if (cont is uint)\r\n                Write((uint) cont);\r\n            else if (cont is Serial)\r\n                Write((Serial) item.Container);\r\n            else\r\n                Write((uint) 0x7FFFFFFF);\r\n\r\n            if (SearchExemptionAgent.Contains(item))\r\n                Write((ushort) Config.GetInt(\"ExemptColor\"));\r\n            else\r\n                Write(item.Hue);\r\n        }\r\n    }\r\n\r\n    public sealed class SingleClick : Packet\r\n    {\r\n        public SingleClick(object clicked) : base(0x09, 5)\r\n        {\r\n            if (clicked is Mobile)\r\n                Write(((Mobile) clicked).Serial);\r\n            else if (clicked is Item)\r\n                Write(((Item) clicked).Serial);\r\n            else if (clicked is Serial)\r\n                Write(((Serial) clicked).Value);\r\n            else\r\n                Write((uint) 0);\r\n        }\r\n    }\r\n\r\n    public sealed class DoubleClick : Packet\r\n    {\r\n        public DoubleClick(Serial clicked) : base(0x06, 5)\r\n        {\r\n            Write((uint) clicked.Value);\r\n        }\r\n    }\r\n\r\n    public sealed class Target : Packet\r\n    {\r\n        public Target(uint tid) : this(tid, false, 0)\r\n        {\r\n        }\r\n\r\n        public Target(uint tid, byte flags) : this(tid, false, flags)\r\n        {\r\n        }\r\n\r\n        public Target(uint tid, bool ground) : this(tid, ground, 0)\r\n        {\r\n        }\r\n\r\n        public Target(uint tid, bool ground, byte flags) : base(0x6C, 19)\r\n        {\r\n            Write(ground);\r\n            Write(tid);\r\n            Write(flags);\r\n            Fill();\r\n        }\r\n    }\r\n\r\n    public sealed class TargetResponse : Packet\r\n    {\r\n        public TargetResponse(TargetInfo info) : base(0x6C, 19)\r\n        {\r\n            Write((byte) info.Type);\r\n            Write((uint) info.TargID);\r\n            Write((byte) info.Flags);\r\n            Write((uint) info.Serial);\r\n            Write((ushort) info.X);\r\n            Write((ushort) info.Y);\r\n            Write((short) info.Z);\r\n            Write((ushort) info.Gfx);\r\n        }\r\n\r\n        public TargetResponse(uint id, Mobile m) : base(0x6C, 19)\r\n        {\r\n            Write((byte) 0x00); // target object\r\n            Write((uint) id);\r\n            Write((byte) 0); // flags\r\n            Write((uint) m.Serial);\r\n            Write((ushort) m.Position.X);\r\n            Write((ushort) m.Position.Y);\r\n            Write((short) m.Position.Z);\r\n            Write((ushort) m.Body);\r\n        }\r\n\r\n        public TargetResponse(uint id, Item item) : base(0x6C, 19)\r\n        {\r\n            Write((byte) 0x00); // target object\r\n            Write((uint) id);\r\n            Write((byte) 0); // flags\r\n            Write((uint) item.Serial);\r\n            Write((ushort) item.Position.X);\r\n            Write((ushort) item.Position.Y);\r\n            Write((short) item.Position.Z);\r\n            Write((ushort) item.ItemID);\r\n        }\r\n        \r\n    }\r\n\r\n    public sealed class TargetCancelResponse : Packet\r\n    {\r\n        public TargetCancelResponse(uint id) : base(0x6C, 19)\r\n        {\r\n            Write((byte) 0);\r\n            Write((uint) id);\r\n            Write((byte) 0);\r\n            Write((uint) 0);\r\n            Write((ushort) 0xFFFF);\r\n            Write((ushort) 0xFFFF);\r\n            Write((short) 0);\r\n            Write((ushort) 0);\r\n        }\r\n    }\r\n\r\n    public sealed class AttackReq : Packet\r\n    {\r\n        public AttackReq(Serial serial) : base(0x05, 5)\r\n        {\r\n            Write((uint) serial);\r\n        }\r\n    }\r\n\r\n    public sealed class SetWeather : Packet\r\n    {\r\n        public SetWeather(int type, int num) : base(0x65, 4)\r\n        {\r\n            Write((byte) type); //types: 0x00 - \"It starts to rain\", 0x01 - \"A fierce storm approaches.\", 0x02 - \"It begins to snow\", 0x03 - \"A storm is brewing.\", 0xFF - None (turns off sound effects), 0xFE (no effect?? Set temperature?)\r\n            Write((byte) num); //number of weather effects on screen\r\n            Write((byte) 0xFE);\r\n        }\r\n    }\r\n\r\n    public sealed class PlayMusic : Packet\r\n    {\r\n        public PlayMusic(ushort num) : base(0x6D, 3)\r\n        {\r\n            Write(num);\r\n        }\r\n    }\r\n\r\n    public sealed class CancelTarget : Packet\r\n    {\r\n        public CancelTarget(uint id) : base(0x6C, 19)\r\n        {\r\n            Write((byte) 0);\r\n            Write((uint) id);\r\n            Write((byte) 3);\r\n            Fill();\r\n        }\r\n    }\r\n\r\n    public sealed class SkillsQuery : Packet\r\n    {\r\n        public SkillsQuery(Mobile m) : base(0x34, 10)\r\n        {\r\n            Write((uint) 0xEDEDEDED); // que el fuck, osi\r\n            Write((byte) 0x05);\r\n            Write(m.Serial);\r\n        }\r\n    }\r\n\r\n    public sealed class StatusQuery : Packet\r\n    {\r\n        public StatusQuery(Mobile m) : base(0x34, 10)\r\n        {\r\n            Write((uint) 0xEDEDEDED);\r\n            Write((byte) 0x04);\r\n            Write(m.Serial);\r\n        }\r\n    }\r\n\r\n    public sealed class StatLockInfo : Packet\r\n    {\r\n        public StatLockInfo(PlayerData m) : base(0xBF)\r\n        {\r\n            this.EnsureCapacity(12);\r\n\r\n            Write((short) 0x19);\r\n            Write((byte) 2);\r\n            Write((int) m.Serial);\r\n            Write((byte) 0);\r\n\r\n            int lockBits = 0;\r\n\r\n            lockBits |= (int) m.StrLock << 4;\r\n            lockBits |= (int) m.DexLock << 2;\r\n            lockBits |= (int) m.IntLock;\r\n\r\n            Write((byte) lockBits);\r\n        }\r\n    }\r\n\r\n    public sealed class SkillsList : Packet\r\n    {\r\n        public SkillsList() : base(0x3A)\r\n        {\r\n            EnsureCapacity(3 + 1 + Skills.TotalSkills() * 9 + 2);\r\n\r\n            Write((byte) 0x02);\r\n            for (int i = 0; i < Skills.TotalSkills(); i++)\r\n            {\r\n                Write((short) (i + 1));\r\n                Write(World.Player.Skills[i].FixedValue);\r\n                Write(World.Player.Skills[i].FixedBase);\r\n                Write((byte) World.Player.Skills[i].Lock);\r\n                Write(World.Player.Skills[i].FixedCap);\r\n            }\r\n\r\n            Write((short) 0);\r\n        }\r\n    }\r\n\r\n    public sealed class SkillUpdate : Packet\r\n    {\r\n        public SkillUpdate(Skill s) : base(0x3A)\r\n        {\r\n            EnsureCapacity(3 + 1 + 9);\r\n\r\n            Write((byte) 0xDF);\r\n\r\n            Write((short) s.Index);\r\n            Write((ushort) s.FixedValue);\r\n            Write((ushort) s.FixedBase);\r\n            Write((byte) s.Lock);\r\n            Write((ushort) s.FixedCap);\r\n        }\r\n    }\r\n\r\n    public sealed class SetSkillLock : Packet\r\n    {\r\n        public SetSkillLock(int skill, LockType type) : base(0x3A)\r\n        {\r\n            EnsureCapacity(6);\r\n            Write((short) skill);\r\n            Write((byte) type);\r\n        }\r\n    }\r\n\r\n    public sealed class AsciiMessage : Packet\r\n    {\r\n        public AsciiMessage(Serial serial, int graphic, MessageType type, int hue, int font, string name,\r\n            string text) : base(0x1C)\r\n        {\r\n            if (name == null) name = \"\";\r\n            if (text == null) text = \"\";\r\n\r\n            if (hue == 0)\r\n                hue = 0x3B2;\r\n\r\n            this.EnsureCapacity(45 + text.Length);\r\n\r\n            Write((uint) serial);\r\n            Write((short) graphic);\r\n            Write((byte) type);\r\n            Write((short) hue);\r\n            Write((short) font);\r\n            WriteAsciiFixed(name, 30);\r\n            WriteAsciiNull(text);\r\n        }\r\n    }\r\n\r\n    public sealed class ClientAsciiMessage : Packet\r\n    {\r\n        public ClientAsciiMessage(MessageType type, int hue, int font, string str) : base(0x03)\r\n        {\r\n            EnsureCapacity(1 + 2 + 1 + 2 + 2 + str.Length + 1);\r\n\r\n            Write((byte) type);\r\n            Write((short) hue);\r\n            Write((short) font);\r\n            WriteAsciiNull(str);\r\n        }\r\n    }\r\n\r\n    public sealed class UnicodeMessage : Packet\r\n    {\r\n        public UnicodeMessage(Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name,\r\n            string text) : base(0xAE)\r\n        {\r\n            if (lang == null || lang == \"\") lang = \"ENU\";\r\n            if (name == null) name = \"\";\r\n            if (text == null) text = \"\";\r\n\r\n            if (hue == 0)\r\n                hue = 0x3B2;\r\n\r\n            this.EnsureCapacity(50 + (text.Length * 2));\r\n\r\n            Write((uint) serial);\r\n            Write((ushort) graphic);\r\n            Write((byte) type);\r\n            Write((ushort) hue);\r\n            Write((ushort) font);\r\n            WriteAsciiFixed(lang.ToUpper(), 4);\r\n            WriteAsciiFixed(name, 30);\r\n            WriteBigUniNull(text);\r\n        }\r\n    }\r\n\r\n    public sealed class ClientUniMessage : Packet\r\n    {\r\n        public ClientUniMessage(MessageType type, int hue, int font, string lang, ArrayList keys, string text) :\r\n            base(0xAD)\r\n        {\r\n            if (lang == null || lang == \"\") lang = \"ENU\";\r\n            if (text == null) text = \"\";\r\n\r\n            this.EnsureCapacity(50 + (text.Length * 2) + (keys == null ? 0 : keys.Count + 1));\r\n            if (keys == null || keys.Count <= 1)\r\n                Write((byte) type);\r\n            else\r\n                Write((byte) (type | MessageType.Encoded));\r\n            Write((short) hue);\r\n            Write((short) font);\r\n            WriteAsciiFixed(lang, 4);\r\n            if (keys != null && keys.Count > 1)\r\n            {\r\n                Write((ushort) keys[0]);\r\n                for (int i = 1; i < keys.Count; i++)\r\n                    Write((byte) keys[i]);\r\n                WriteUTF8Null(text);\r\n            }\r\n            else\r\n            {\r\n                WriteBigUniNull(text);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class ClientUniEncodedCommandMessage : Packet\r\n    {\r\n        public ClientUniEncodedCommandMessage(MessageType type, int hue, int font, string lang, List<ushort> keys,\r\n            string text) : base(0xAD)\r\n        {\r\n            if (lang == null || lang == \"\") lang = \"ENU\";\r\n            if (text == null) text = \"\";\r\n\r\n            this.EnsureCapacity(50 + (text.Length * 2) + (keys == null ? 0 : keys.Count + 1));\r\n            if (keys == null || keys.Count <= 1)\r\n                Write((byte) type);\r\n            else\r\n                Write((byte) (type | MessageType.Encoded));\r\n            Write((short) hue);\r\n            Write((short) font);\r\n            WriteAsciiFixed(lang, 4);\r\n            if (keys != null && keys.Count > 1)\r\n            {\r\n                Write(keys[0]);\r\n                for (int i = 1; i < keys.Count; i++)\r\n                    Write((byte) keys[i]);\r\n                WriteUTF8Null(text);\r\n            }\r\n            else\r\n            {\r\n                WriteBigUniNull(text);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class LiftRequest : Packet\r\n    {\r\n        public LiftRequest(Serial ser, int amount) : base(0x07, 7)\r\n        {\r\n            this.Write(ser.Value);\r\n            this.Write((ushort) amount);\r\n        }\r\n\r\n        public LiftRequest(Item i, int amount) : this(i.Serial, amount)\r\n        {\r\n        }\r\n\r\n        public LiftRequest(Item i) : this(i.Serial, i.Amount)\r\n        {\r\n        }\r\n    }\r\n\r\n    public sealed class LiftRej : Packet\r\n    {\r\n        public LiftRej() : this(5) // reason = Inspecific\r\n        {\r\n        }\r\n\r\n        public LiftRej(byte reason) : base(0x27, 2)\r\n        {\r\n            Write(reason);\r\n        }\r\n    }\r\n\r\n    public sealed class EquipRequest : Packet\r\n    {\r\n        public EquipRequest(Serial item, Mobile to, Layer layer) : base(0x13, 10)\r\n        {\r\n            Write(item);\r\n            Write((byte) layer);\r\n            Write(to.Serial);\r\n        }\r\n\r\n        public EquipRequest(Serial item, Serial to, Layer layer) : base(0x13, 10)\r\n        {\r\n            Write(item);\r\n            Write((byte) layer);\r\n            Write(to);\r\n        }\r\n    }\r\n\r\n    public sealed class DropRequest : Packet\r\n    {\r\n        public DropRequest(Item item, Serial destSer) : base(0x08, 14)\r\n        {\r\n            if (Engine.UsePostKRPackets)\r\n                EnsureCapacity(15);\r\n\r\n            Write(item.Serial);\r\n            Write((short) (-1));\r\n            Write((short) (-1));\r\n            Write((sbyte) 0);\r\n            if (Engine.UsePostKRPackets)\r\n                Write((byte) 0);\r\n            Write(destSer);\r\n        }\r\n\r\n        public DropRequest(Item item, Item to) : this(item, to.Serial)\r\n        {\r\n        }\r\n\r\n        public DropRequest(Serial item, Point3D pt, Serial dest) : base(0x08, 14)\r\n        {\r\n            if (Engine.UsePostKRPackets)\r\n                EnsureCapacity(15);\r\n\r\n            Write(item);\r\n            Write((ushort) pt.X);\r\n            Write((ushort) pt.Y);\r\n            Write((sbyte) pt.Z);\r\n            if (Engine.UsePostKRPackets)\r\n                Write((byte) 0);\r\n            Write(dest);\r\n        }\r\n\r\n        public DropRequest(Item item, Point3D pt, Serial destSer) : this(item.Serial, pt, destSer)\r\n        {\r\n        }\r\n    }\r\n\r\n    public class SellListItem\r\n    {\r\n        public Serial Serial;\r\n        public ushort Amount;\r\n\r\n        public SellListItem(Serial s, ushort a)\r\n        {\r\n            Serial = s;\r\n            Amount = a;\r\n        }\r\n    }\r\n\r\n    public sealed class VendorSellResponse : Packet\r\n    {\r\n        public VendorSellResponse(Mobile vendor, List<SellListItem> list) : base(0x9F)\r\n        {\r\n            EnsureCapacity(1 + 2 + 4 + 2 + list.Count * 6);\r\n\r\n            Write((uint) vendor.Serial);\r\n            Write((ushort) list.Count);\r\n\r\n            for (int i = 0; i < list.Count; i++)\r\n            {\r\n                SellListItem sli = list[i];\r\n                Write((uint) sli.Serial);\r\n                Write((ushort) sli.Amount);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class MobileStatusExtended : Packet\r\n    {\r\n        public MobileStatusExtended(PlayerData m) : base(0x11)\r\n        {\r\n            string name = m.Name;\r\n            if (name == null) name = \"\";\r\n\r\n            this.EnsureCapacity(88);\r\n\r\n            Write((uint) m.Serial);\r\n            WriteAsciiFixed(name, 30);\r\n\r\n            Write((short) m.Hits);\r\n            Write((short) m.HitsMax);\r\n\r\n            Write(false); // cannot edit name\r\n\r\n            Write((byte) 0x03); // no aos info\r\n\r\n            Write(m.Female);\r\n\r\n            Write((short) m.Str);\r\n            Write((short) m.Dex);\r\n            Write((short) m.Int);\r\n\r\n            Write((short) m.Stam);\r\n            Write((short) m.StamMax);\r\n\r\n            Write((short) m.Mana);\r\n            Write((short) m.ManaMax);\r\n\r\n            Write((int) m.Gold);\r\n            Write((short) m.AR);\r\n            Write((short) m.Weight);\r\n            Write((short) m.StatCap);\r\n            Write((byte) m.Followers);\r\n            Write((byte) m.FollowersMax);\r\n        }\r\n    }\r\n\r\n    public sealed class MobileStatusCompact : Packet\r\n    {\r\n        public MobileStatusCompact(Mobile m) : base(0x11)\r\n        {\r\n            string name = m.Name;\r\n            if (name == null) name = \"\";\r\n\r\n            this.EnsureCapacity(88);\r\n\r\n            Write((uint) m.Serial);\r\n            WriteAsciiFixed(name, 30);\r\n\r\n            Write((short) m.Hits);\r\n            Write((short) m.HitsMax);\r\n\r\n            Write(false); // cannot edit name\r\n\r\n            Write((byte) 0x00); // no aos info\r\n        }\r\n    }\r\n\r\n    public sealed class GumpTextEntry\r\n    {\r\n        public GumpTextEntry(ushort id, string s)\r\n        {\r\n            EntryID = id;\r\n            Text = s;\r\n        }\r\n\r\n        public ushort EntryID;\r\n        public string Text;\r\n    }\r\n\r\n    public sealed class GumpResponse : Packet\r\n    {\r\n        public GumpResponse(uint serial, uint tid, int bid, int[] switches, GumpTextEntry[] entries) : base(0xB1)\r\n        {\r\n            EnsureCapacity(3 + 4 + 4 + 4 + 4 + switches.Length * 4 + 4 + entries.Length * 4);\r\n\r\n            Write((uint) serial);\r\n            Write((uint) tid);\r\n\r\n            Write((int) bid);\r\n\r\n            Write((int) switches.Length);\r\n            for (int i = 0; i < switches.Length; i++)\r\n                Write((int) switches[i]);\r\n            Write((int) entries.Length);\r\n            for (int i = 0; i < entries.Length; i++)\r\n            {\r\n                GumpTextEntry gte = (GumpTextEntry) entries[i];\r\n                Write((ushort) gte.EntryID);\r\n                Write((ushort) (gte.Text.Length * 2));\r\n                WriteBigUniFixed(gte.Text, gte.Text.Length);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class CompressedGump : Packet\r\n    {\r\n        public CompressedGump(uint serial, uint tid, int bid, int[] switches, GumpTextEntry[] entries) : base(0xDD)\r\n        {\r\n            EnsureCapacity(3 + 4 + 4 + 4 + 4 + switches.Length * 4 + 4 + entries.Length * 4);\r\n\r\n            Write((uint) serial);\r\n            Write((uint) tid);\r\n\r\n            Write((int) bid);\r\n\r\n            Write((int) switches.Length);\r\n            for (int i = 0; i < switches.Length; i++)\r\n                Write((int) switches[i]);\r\n            Write((int) entries.Length);\r\n            for (int i = 0; i < entries.Length; i++)\r\n            {\r\n                GumpTextEntry gte = (GumpTextEntry) entries[i];\r\n                Write((ushort) gte.EntryID);\r\n                Write((ushort) (gte.Text.Length * 2));\r\n                WriteBigUniFixed(gte.Text, gte.Text.Length);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class UseSkill : Packet\r\n    {\r\n        public UseSkill(int sk) : base(0x12)\r\n        {\r\n            string cmd = $\"{sk} 0\";\r\n            EnsureCapacity(4 + cmd.Length + 1);\r\n            Write((byte) 0x24);\r\n            WriteAsciiNull(cmd);\r\n        }\r\n    }\r\n\r\n    public sealed class ExtCastSpell : Packet\r\n    {\r\n        public ExtCastSpell(Serial book, ushort spell) : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 2 + 4 + 2);\r\n            Write((short) 0x1C);\r\n            Write((short) (book.IsItem ? 1 : 2));\r\n            if (book.IsItem)\r\n                Write((uint) book);\r\n            Write((short) spell);\r\n        }\r\n    }\r\n\r\n    public sealed class CastSpellFromBook : Packet\r\n    {\r\n        public CastSpellFromBook(Serial book, ushort spell) : base(0x12)\r\n        {\r\n            string cmd;\r\n            if (book.IsItem)\r\n                cmd = $\"{spell} {book.Value}\";\r\n            else\r\n                cmd = $\"{spell}\";\r\n            EnsureCapacity(3 + 1 + cmd.Length + 1);\r\n            Write((byte) 0x27);\r\n            WriteAsciiNull(cmd);\r\n        }\r\n    }\r\n\r\n    public sealed class CastSpellFromMacro : Packet\r\n    {\r\n        public CastSpellFromMacro(ushort spell) : base(0x12)\r\n        {\r\n            string cmd = spell.ToString();\r\n            EnsureCapacity(3 + 1 + cmd.Length + 1);\r\n            Write((byte) 0x56);\r\n            WriteAsciiNull(cmd);\r\n        }\r\n    }\r\n\r\n    public sealed class DisarmRequest : Packet\r\n    {\r\n        public DisarmRequest() : base(0xBF)\r\n        {\r\n            EnsureCapacity(3);\r\n            Write((ushort) 0x09);\r\n        }\r\n    }\r\n\r\n    public sealed class StunRequest : Packet\r\n    {\r\n        public StunRequest() : base(0xBF)\r\n        {\r\n            EnsureCapacity(3);\r\n            Write((ushort) 0x0A);\r\n        }\r\n    }\r\n\r\n    public sealed class CloseGump : Packet\r\n    {\r\n        public CloseGump(uint typeID, uint buttonID) : base(0xBF)\r\n        {\r\n            EnsureCapacity(13);\r\n\r\n            Write((short) 0x04);\r\n            Write((int) typeID);\r\n            Write((int) buttonID);\r\n        }\r\n\r\n        public CloseGump(uint typeID) : base(0xBF)\r\n        {\r\n            EnsureCapacity(13);\r\n\r\n            Write((short) 0x04);\r\n            Write((int) typeID);\r\n            Write((int) 0);\r\n        }\r\n    }\r\n\r\n    public sealed class ChangeCombatant : Packet\r\n    {\r\n        public ChangeCombatant(Serial ser) : base(0xAA, 5)\r\n        {\r\n            Write((uint) ser);\r\n        }\r\n\r\n        public ChangeCombatant(Mobile m) : this(m.Serial)\r\n        {\r\n        }\r\n    }\r\n\r\n    public sealed class UseAbility : Packet\r\n    {\r\n        // ints are 'encoded' with a leading bool, if true then the number is 0, if flase then followed by all 4 bytes (lame :-)\r\n        public UseAbility(AOSAbility a) : base(0xD7)\r\n        {\r\n            EnsureCapacity(1 + 2 + 4 + 2 + 4);\r\n\r\n            Write((uint) World.Player.Serial);\r\n            Write((ushort) 0x19);\r\n            if (a == AOSAbility.Clear)\r\n            {\r\n                Write(true);\r\n            }\r\n            else\r\n            {\r\n                Write(false);\r\n                Write((int) a);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class ClearAbility : Packet\r\n    {\r\n        public static readonly Packet Instance = new ClearAbility();\r\n\r\n        public ClearAbility() : base(0xBF)\r\n        {\r\n            EnsureCapacity(5);\r\n\r\n            Write((short) 0x21);\r\n        }\r\n    }\r\n\r\n    public sealed class PingPacket : Packet\r\n    {\r\n        public PingPacket(byte seq) : base(0x73, 2)\r\n        {\r\n            Write(seq);\r\n        }\r\n    }\r\n\r\n    public sealed class MobileUpdate : Packet\r\n    {\r\n        public MobileUpdate(Mobile m) : base(0x20, 19)\r\n        {\r\n            Write((int) m.Serial);\r\n            Write((short) m.Body);\r\n            Write((byte) 0);\r\n            int ltHue = Config.GetInt(\"LTHilight\");\r\n            if (ltHue != 0 && Targeting.IsLastTarget(m))\r\n                Write((short) (ltHue | 0x8000));\r\n            else\r\n                Write((short) m.Hue);\r\n            Write((byte) m.GetPacketFlags());\r\n            Write((short) m.Position.X);\r\n            Write((short) m.Position.Y);\r\n            Write((short) 0);\r\n            Write((byte) m.Direction);\r\n            Write((sbyte) m.Position.Z);\r\n        }\r\n    }\r\n\r\n    public sealed class MobileIncoming : Packet\r\n    {\r\n        public MobileIncoming(Mobile m) : base(0x78)\r\n        {\r\n            int count = m.Contains.Count;\r\n            int ltHue = Config.GetInt(\"LTHilight\");\r\n            bool isLT;\r\n            if (ltHue != 0)\r\n                isLT = Targeting.IsLastTarget(m);\r\n            else\r\n                isLT = false;\r\n\r\n            EnsureCapacity(3 + 4 + 2 + 2 + 2 + 1 + 1 + 2 + 1 + 1 + 4 + count * (4 + 2 + 1 + 2));\r\n            Write((uint) m.Serial);\r\n            Write((ushort) m.Body);\r\n            Write((ushort) m.Position.X);\r\n            Write((ushort) m.Position.Y);\r\n            Write((sbyte) m.Position.Z);\r\n            Write((byte) m.Direction);\r\n            Write((ushort) (isLT ? ltHue | 0x8000 : m.Hue));\r\n            Write((byte) m.GetPacketFlags());\r\n            Write((byte) m.Notoriety);\r\n\r\n            for (int i = 0; i < count; ++i)\r\n            {\r\n                Item item = (Item) m.Contains[i];\r\n\r\n                int itemID = item.ItemID & 0x3FFF;\r\n                bool writeHue = (item.Hue != 0);\r\n                if (writeHue || isLT)\r\n                    itemID |= 0x8000;\r\n\r\n                Write((uint) item.Serial);\r\n                Write((ushort) itemID);\r\n                Write((byte) item.Layer);\r\n                if (isLT)\r\n                    Write((ushort) (ltHue & 0x3FFF));\r\n                else if (writeHue)\r\n                    Write((ushort) item.Hue);\r\n            }\r\n\r\n            Write((uint) 0); // terminate\r\n        }\r\n    }\r\n\r\n    public class VendorBuyItem\r\n    {\r\n        public VendorBuyItem(Serial ser, int amount, int price)\r\n        {\r\n            Serial = ser;\r\n            Amount = amount;\r\n            Price = price;\r\n        }\r\n\r\n        public readonly Serial Serial;\r\n        public int Amount;\r\n        public int Price;\r\n\r\n        public int TotalCost\r\n        {\r\n            get { return Amount * Price; }\r\n        }\r\n    }\r\n\r\n    public sealed class VendorBuyResponse : Packet\r\n    {\r\n        public VendorBuyResponse(Serial vendor, IList<VendorBuyItem> list) : base(0x3B)\r\n        {\r\n            EnsureCapacity(1 + 2 + 4 + 1 + list.Count * 7);\r\n\r\n            Write(vendor);\r\n            Write((byte) 0x02); // flag\r\n\r\n            for (int i = 0; i < list.Count; i++)\r\n            {\r\n                VendorBuyItem vbi = list[i];\r\n                Write((byte) 0x1A); // layer?\r\n                Write(vbi.Serial);\r\n                Write((ushort) vbi.Amount);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class MenuResponse : Packet\r\n    {\r\n        public MenuResponse(uint serial, ushort menuid, ushort index, ushort itemid, ushort hue) : base(0x7D, 13)\r\n        {\r\n            Write((uint) serial);\r\n            Write(menuid);\r\n            Write(index);\r\n            Write(itemid);\r\n            Write(hue);\r\n        }\r\n    }\r\n\r\n    public sealed class HuePicker : Packet\r\n    {\r\n        public HuePicker() : this(Serial.MinusOne, 0x0FAB)\r\n        {\r\n        }\r\n\r\n        public HuePicker(ItemID itemid) : this(Serial.MinusOne, itemid)\r\n        {\r\n        }\r\n\r\n        public HuePicker(Serial serial, ItemID itemid) : base(0x95, 9)\r\n        {\r\n            Write((uint) serial);\r\n            Write((ushort) 0);\r\n            Write((ushort) itemid);\r\n        }\r\n    }\r\n\r\n    public sealed class WalkRequest : Packet\r\n    {\r\n        public WalkRequest(Direction dir, byte seq) : base(0x02, 7)\r\n        {\r\n            Write((byte) dir);\r\n            Write(seq);\r\n            Write((int) -1); // key\r\n        }\r\n    }\r\n\r\n    public sealed class ResyncReq : Packet\r\n    {\r\n        public ResyncReq() : base(0x22, 3)\r\n        {\r\n            Write((ushort) 0);\r\n        }\r\n    }\r\n\r\n    public sealed class ACKTalk : Packet\r\n    {\r\n        public ACKTalk() : base(0x03)\r\n        {\r\n            EnsureCapacity(40);\r\n            Write((byte) 0x20);\r\n            Write((byte) 0x00);\r\n            Write((byte) 0x34);\r\n            Write((byte) 0x00);\r\n            Write((byte) 0x03);\r\n            Write((byte) 0xdb);\r\n            Write((byte) 0x13);\r\n            Write((byte) 0x14);\r\n            Write((byte) 0x3f);\r\n            Write((byte) 0x45);\r\n            Write((byte) 0x2c);\r\n            Write((byte) 0x58);\r\n            Write((byte) 0x0f);\r\n            Write((byte) 0x5d);\r\n            Write((byte) 0x44);\r\n            Write((byte) 0x2e);\r\n            Write((byte) 0x50);\r\n            Write((byte) 0x11);\r\n            Write((byte) 0xdf);\r\n            Write((byte) 0x75);\r\n            Write((byte) 0x5c);\r\n            Write((byte) 0xe0);\r\n            Write((byte) 0x3e);\r\n            Write((byte) 0x71);\r\n            Write((byte) 0x4f);\r\n            Write((byte) 0x31);\r\n            Write((byte) 0x34);\r\n            Write((byte) 0x05);\r\n            Write((byte) 0x4e);\r\n            Write((byte) 0x18);\r\n            Write((byte) 0x1e);\r\n            Write((byte) 0x72);\r\n            Write((byte) 0x0f);\r\n            Write((byte) 0x59);\r\n            Write((byte) 0xad);\r\n            Write((byte) 0xf5);\r\n            Write((byte) 0x00);\r\n        }\r\n    }\r\n\r\n    public sealed class WorldItem : Packet\r\n    {\r\n        public WorldItem(Item item) : base(0x1A)\r\n        {\r\n            this.EnsureCapacity(20);\r\n\r\n            // 14 base length\r\n            // +2 - Amount\r\n            // +2 - Hue\r\n            // +1 - Flags\r\n\r\n            uint serial = (uint) item.Serial;\r\n            ushort itemID = item.ItemID;\r\n            ushort amount = item.Amount;\r\n            int x = item.Position.X;\r\n            int y = item.Position.Y;\r\n            ushort hue = item.Hue;\r\n            byte flags = item.GetPacketFlags();\r\n            byte direction = item.Direction;\r\n\r\n            if (amount != 0)\r\n                serial |= 0x80000000;\r\n            else\r\n                serial &= 0x7FFFFFFF;\r\n            Write((uint) serial);\r\n            Write((ushort) (itemID & 0x7FFF));\r\n            if (amount != 0)\r\n                Write((ushort) amount);\r\n\r\n            x &= 0x7FFF;\r\n            if (direction != 0)\r\n                x |= 0x8000;\r\n            Write((ushort) x);\r\n\r\n            y &= 0x3FFF;\r\n            if (hue != 0)\r\n                y |= 0x8000;\r\n            if (flags != 0)\r\n                y |= 0x4000;\r\n\r\n            Write((ushort) y);\r\n            if (direction != 0)\r\n                Write((byte) direction);\r\n            Write((sbyte) item.Position.Z);\r\n            if (hue != 0)\r\n                Write((ushort) hue);\r\n            if (flags != 0)\r\n                Write((byte) flags);\r\n        }\r\n    }\r\n\r\n    public sealed class EquipmentItem : Packet\r\n    {\r\n        public EquipmentItem(Item item, Serial owner) : this(item, item.Hue, owner)\r\n        {\r\n        }\r\n\r\n        public EquipmentItem(Item item, ushort hue, Serial owner) : base(0x2E, 15)\r\n        {\r\n            Write((uint) item.Serial);\r\n            Write((ushort) item.ItemID);\r\n            Write((sbyte) 0);\r\n            Write((byte) item.Layer);\r\n            Write((uint) owner);\r\n            Write((ushort) hue);\r\n        }\r\n    }\r\n\r\n    public sealed class ForceWalk : Packet\r\n    {\r\n        public ForceWalk(Direction d) : base(0x97, 2)\r\n        {\r\n            Write((byte) d);\r\n        }\r\n    }\r\n\r\n    public sealed class PathFindTo : Packet\r\n    {\r\n        public PathFindTo(Point3D loc) : base(0x38, 7 * 20)\r\n        {\r\n            for (int i = 0; i < 20; i++)\r\n            {\r\n                if (i != 0)\r\n                    Write((byte) 0x38);\r\n                Write((ushort) loc.X);\r\n                Write((ushort) loc.Y);\r\n                Write((short) loc.Z);\r\n            }\r\n        }\r\n    }\r\n\r\n    public sealed class LoginConfirm : Packet\r\n    {\r\n        public LoginConfirm(Mobile m) : base(0x1B, 37)\r\n        {\r\n            Write((int) m.Serial);\r\n            Write((int) 0);\r\n            Write((short) m.Body);\r\n            Write((short) m.Position.X);\r\n            Write((short) m.Position.Y);\r\n            Write((short) m.Position.Z);\r\n            Write((byte) m.Direction);\r\n            Write((byte) 0);\r\n            Write((int) -1);\r\n\r\n            Write((short) 0);\r\n            Write((short) 0);\r\n            Write((short) 6144);\r\n            Write((short) 4096);\r\n        }\r\n    }\r\n\r\n    public sealed class LoginComplete : Packet\r\n    {\r\n        public LoginComplete() : base(0x55, 1)\r\n        {\r\n        }\r\n    }\r\n\r\n    public sealed class DeathStatus : Packet\r\n    {\r\n        public DeathStatus(bool dead) : base(0x2C, 2)\r\n        {\r\n            Write((byte) (dead ? 0 : 2));\r\n        }\r\n    }\r\n\r\n    public sealed class CurrentTime : Packet\r\n    {\r\n        public CurrentTime() : base(0x5B, 4)\r\n        {\r\n            DateTime now = DateTime.UtcNow;\r\n\r\n            Write((byte) now.Hour);\r\n            Write((byte) now.Minute);\r\n            Write((byte) now.Second);\r\n        }\r\n    }\r\n\r\n    public sealed class MapChange : Packet\r\n    {\r\n        public MapChange(byte map) : base(0xBF)\r\n        {\r\n            this.EnsureCapacity(6);\r\n\r\n            Write((short) 0x08);\r\n            Write((byte) map);\r\n        }\r\n    }\r\n\r\n    public sealed class SeasonChange : Packet\r\n    {\r\n        public SeasonChange(int season, bool playSound) : base(0xBC, 3)\r\n        {\r\n            Write((byte) season);\r\n            Write((bool) playSound);\r\n        }\r\n    }\r\n\r\n    public sealed class SupportedFeatures : Packet\r\n    {\r\n        //private static int m_Value = 0x801F;\r\n        public SupportedFeatures(ushort val) : base(0xB9, 3)\r\n        {\r\n            Write((ushort) val); // 0x01 = T2A, 0x02 = LBR\r\n        }\r\n    }\r\n\r\n    public sealed class MapPatches : Packet\r\n    {\r\n        public MapPatches(int[] patches) : base(0xBF)\r\n        {\r\n            EnsureCapacity(9 + (4 * patches.Length));\r\n\r\n            Write((short) 0x0018);\r\n\r\n            Write((int) (patches.Length / 2));\r\n\r\n            for (int i = 0; i < patches.Length; i++)\r\n                Write((int) patches[i]);\r\n            /*Write( (int) Ultima.Map.Felucca.Tiles.Patch.StaticBlocks );\r\n            Write( (int) Ultima.Map.Felucca.Tiles.Patch.LandBlocks );\r\n\r\n            Write( (int) Ultima.Map.Trammel.Tiles.Patch.StaticBlocks );\r\n            Write( (int) Ultima.Map.Trammel.Tiles.Patch.LandBlocks );\r\n\r\n            Write( (int) Ultima.Map.Ilshenar.Tiles.Patch.StaticBlocks );\r\n            Write( (int) Ultima.Map.Ilshenar.Tiles.Patch.LandBlocks );\r\n\r\n            Write( (int) Ultima.Map.Malas.Tiles.Patch.StaticBlocks );\r\n            Write( (int) Ultima.Map.Malas.Tiles.Patch.LandBlocks );*/\r\n        }\r\n    }\r\n\r\n    public sealed class MobileAttributes : Packet\r\n    {\r\n        public MobileAttributes(PlayerData m) : base(0x2D, 17)\r\n        {\r\n            Write(m.Serial);\r\n\r\n            Write((short) m.HitsMax);\r\n            Write((short) m.Hits);\r\n\r\n            Write((short) m.ManaMax);\r\n            Write((short) m.Mana);\r\n\r\n            Write((short) m.StamMax);\r\n            Write((short) m.Stam);\r\n        }\r\n    }\r\n\r\n    public sealed class SetWarMode : Packet\r\n    {\r\n        public SetWarMode(bool mode) : base(0x72, 5)\r\n        {\r\n            Write(mode);\r\n            Write((byte) 0x00);\r\n            Write((byte) 0x32);\r\n            Write((byte) 0x00);\r\n            //Fill();\r\n        }\r\n    }\r\n\r\n    public sealed class OpenDoorMacro : Packet\r\n    {\r\n        public OpenDoorMacro() : base(0x12)\r\n        {\r\n            EnsureCapacity(5);\r\n            Write((byte) 0x58);\r\n            Write((byte) 0);\r\n        }\r\n    }\r\n\r\n    public sealed class PersonalLightLevel : Packet\r\n    {\r\n        public PersonalLightLevel(PlayerData m) : base(0x4E, 6)\r\n        {\r\n            Write((int) m.Serial);\r\n            Write((sbyte) m.LocalLightLevel);\r\n        }\r\n    }\r\n\r\n    public sealed class GlobalLightLevel : Packet\r\n    {\r\n        public GlobalLightLevel(int level) : base(0x4F, 2)\r\n        {\r\n            Write((sbyte) level);\r\n        }\r\n    }\r\n\r\n    public sealed class DisplayPaperdoll : Packet\r\n    {\r\n        public DisplayPaperdoll(Mobile m, string text) : base(0x88, 66)\r\n        {\r\n            Write((int) m.Serial);\r\n            WriteAsciiFixed(text, 60);\r\n            Write((byte) (m.Warmode ? 1 : 0));\r\n        }\r\n    }\r\n\r\n    public sealed class RemoveObject : Packet\r\n    {\r\n        public RemoveObject(UOEntity ent) : base(0x1D, 5)\r\n        {\r\n            Write((uint) ent.Serial);\r\n        }\r\n\r\n        public RemoveObject(Serial s) : base(0x1D, 5)\r\n        {\r\n            Write((uint) s);\r\n        }\r\n    }\r\n\r\n    public sealed class ContextMenuRequest : Packet\r\n    {\r\n        public ContextMenuRequest(Serial entity) : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 4);\r\n            Write((ushort) 0x13);\r\n            Write((uint) entity);\r\n        }\r\n    }\r\n\r\n    public sealed class ContextMenuResponse : Packet\r\n    {\r\n        public ContextMenuResponse(Serial entity, ushort idx) : base(0xBF)\r\n        {\r\n            EnsureCapacity(1 + 2 + 2 + 4 + 2);\r\n\r\n            Write((ushort) 0x15);\r\n            Write((uint) entity);\r\n            Write((ushort) idx);\r\n        }\r\n    }\r\n\r\n    public sealed class SetUpdateRange : Packet\r\n    {\r\n        public SetUpdateRange(int range) : base(0xC8, 2)\r\n        {\r\n            Write((byte) range);\r\n        }\r\n    }\r\n\r\n    public sealed class PlaySound : Packet\r\n    {\r\n        public PlaySound(int sound) : base(0x54, 12)\r\n        {\r\n            Write((byte) 0x01); //(0x00=quiet, repeating, 0x01=single normally played sound effect)\r\n            Write((ushort) sound);\r\n            Write((ushort) 0);\r\n            Write((ushort) World.Player.Position.X);\r\n            Write((ushort) World.Player.Position.Y);\r\n            Write((ushort) World.Player.Position.Z);\r\n        }\r\n    }\r\n\r\n    public sealed class RazorNegotiateResponse : Packet\r\n    {\r\n        public RazorNegotiateResponse() : base(0xF0)\r\n        {\r\n            EnsureCapacity(1 + 2 + 1);\r\n\r\n            Write((byte) 0xFF);\r\n        }\r\n    }\r\n\r\n    public sealed class DesignStateGeneral : Packet\r\n    {\r\n        public DesignStateGeneral(Item house) : base(0xBF)\r\n        {\r\n            EnsureCapacity(13);\r\n\r\n            Write((ushort) 0x1D);\r\n            Write((uint) house.Serial);\r\n            Write((int) house.HouseRevision);\r\n        }\r\n    }\r\n\r\n    public sealed class StringQueryResponse : Packet\r\n    {\r\n        public StringQueryResponse(int serial, byte type, byte index, bool ok, string resp) : base(0xAC)\r\n        {\r\n            if (resp == null)\r\n                resp = String.Empty;\r\n\r\n            this.EnsureCapacity(1 + 2 + 4 + 1 + 1 + 1 + 2 + resp.Length + 1);\r\n\r\n            Write((int) serial);\r\n            Write((byte) type);\r\n            Write((byte) index);\r\n            Write((bool) ok);\r\n            Write((short) (resp.Length + 1));\r\n            WriteAsciiNull(resp);\r\n        }\r\n    }\r\n\r\n    public class DesignStateDetailed : Packet\r\n    {\r\n        public const int MaxItemsPerStairBuffer = 750;\r\n\r\n        private static byte[][] m_PlaneBuffers;\r\n        private static bool[] m_PlaneUsed;\r\n\r\n        private static byte[][] m_StairBuffers;\r\n\r\n        private static byte[] m_InflatedBuffer = new byte[0x2000];\r\n        private static byte[] m_DeflatedBuffer = new byte[0x2000];\r\n\r\n        /*private static byte[] m_PrimBuffer = new byte[4];\r\n\r\n        public override void Write( int value )\r\n        {\r\n             m_PrimBuffer[0] = (byte)(value >> 24);\r\n             m_PrimBuffer[1] = (byte)(value >> 16);\r\n             m_PrimBuffer[2] = (byte)(value >>  8);\r\n             m_PrimBuffer[3] = (byte) value;\r\n\r\n             UnderlyingStream.Write( m_PrimBuffer, 0, 4 );\r\n        }\r\n\r\n        public override void Write( short value )\r\n        {\r\n             m_PrimBuffer[0] = (byte)(value >> 8);\r\n             m_PrimBuffer[1] = (byte) value;\r\n\r\n             UnderlyingStream.Write( m_PrimBuffer, 0, 2 );\r\n        }\r\n\r\n        public override void Write( byte value )\r\n        {\r\n             UnderlyingStream.WriteByte( value );\r\n        }\r\n\r\n        public void Write( byte[] buffer, int offset, int size )\r\n        {\r\n             UnderlyingStream.Write( buffer, offset, size );\r\n        }*/\r\n\r\n        public static void Clear(byte[] buffer, int size)\r\n        {\r\n            for (int i = 0; i < size; ++i)\r\n                buffer[i] = 0;\r\n        }\r\n\r\n        public DesignStateDetailed(Serial serial, int revision, int xMin, int yMin, int xMax, int yMax,\r\n            MultiTileEntry[] tiles) : base(0xD8)\r\n        {\r\n            EnsureCapacity(17 + (tiles.Length * 5));\r\n\r\n            Write((byte) 0x03); // Compression Type\r\n            Write((byte) 0x00); // Unknown\r\n            Write((uint) serial);\r\n            Write((int) revision);\r\n            Write((short) tiles.Length);\r\n            Write((short) 0); // Buffer length : reserved\r\n            Write((byte) 0); // Plane count : reserved\r\n\r\n            int totalLength = 1; // includes plane count\r\n\r\n            int width = (xMax - xMin) + 1;\r\n            int height = (yMax - yMin) + 1;\r\n\r\n            if (m_PlaneBuffers == null)\r\n            {\r\n                m_PlaneBuffers = new byte[9][];\r\n                m_PlaneUsed = new bool[9];\r\n\r\n                for (int i = 0; i < m_PlaneBuffers.Length; ++i)\r\n                    m_PlaneBuffers[i] = new byte[0x400];\r\n\r\n                m_StairBuffers = new byte[6][];\r\n\r\n                for (int i = 0; i < m_StairBuffers.Length; ++i)\r\n                    m_StairBuffers[i] = new byte[MaxItemsPerStairBuffer * 5];\r\n            }\r\n            else\r\n            {\r\n                for (int i = 0; i < m_PlaneUsed.Length; ++i)\r\n                    m_PlaneUsed[i] = false;\r\n\r\n                Clear(m_PlaneBuffers[0], width * height * 2);\r\n\r\n                for (int i = 0; i < 4; ++i)\r\n                {\r\n                    Clear(m_PlaneBuffers[1 + i], (width - 1) * (height - 2) * 2);\r\n                    Clear(m_PlaneBuffers[5 + i], width * (height - 1) * 2);\r\n                }\r\n            }\r\n\r\n            int totalStairsUsed = 0;\r\n\r\n            for (int i = 0; i < tiles.Length; ++i)\r\n            {\r\n                MultiTileEntry mte = tiles[i];\r\n                int x = mte.m_OffsetX - xMin;\r\n                int y = mte.m_OffsetY - yMin;\r\n                int z = mte.m_OffsetZ;\r\n                int plane, size;\r\n                bool floor = false;\r\n                try\r\n                {\r\n                    floor = (Ultima.TileData.ItemTable[mte.m_ItemID & 0x3FFF].Height <= 0);\r\n                }\r\n                catch\r\n                {\r\n                }\r\n\r\n                switch (z)\r\n                {\r\n                    case 0:\r\n                        plane = 0;\r\n                        break;\r\n                    case 7:\r\n                        plane = 1;\r\n                        break;\r\n                    case 27:\r\n                        plane = 2;\r\n                        break;\r\n                    case 47:\r\n                        plane = 3;\r\n                        break;\r\n                    case 67:\r\n                        plane = 4;\r\n                        break;\r\n                    default:\r\n                    {\r\n                        int stairBufferIndex = (totalStairsUsed / MaxItemsPerStairBuffer);\r\n                        byte[] stairBuffer = m_StairBuffers[stairBufferIndex];\r\n\r\n                        int byteIndex = (totalStairsUsed % MaxItemsPerStairBuffer) * 5;\r\n\r\n                        stairBuffer[byteIndex++] = (byte) ((mte.m_ItemID >> 8) & 0x3F);\r\n                        stairBuffer[byteIndex++] = (byte) mte.m_ItemID;\r\n\r\n                        stairBuffer[byteIndex++] = (byte) mte.m_OffsetX;\r\n                        stairBuffer[byteIndex++] = (byte) mte.m_OffsetY;\r\n                        stairBuffer[byteIndex++] = (byte) mte.m_OffsetZ;\r\n\r\n                        ++totalStairsUsed;\r\n\r\n                        continue;\r\n                    }\r\n                }\r\n\r\n                if (plane == 0)\r\n                {\r\n                    size = height;\r\n                }\r\n                else if (floor)\r\n                {\r\n                    size = height - 2;\r\n                    x -= 1;\r\n                    y -= 1;\r\n                }\r\n                else\r\n                {\r\n                    size = height - 1;\r\n                    plane += 4;\r\n                }\r\n\r\n                int index = ((x * size) + y) * 2;\r\n\r\n                m_PlaneUsed[plane] = true;\r\n                m_PlaneBuffers[plane][index] = (byte) ((mte.m_ItemID >> 8) & 0x3F);\r\n                m_PlaneBuffers[plane][index + 1] = (byte) mte.m_ItemID;\r\n            }\r\n\r\n            int planeCount = 0;\r\n\r\n            for (int i = 0; i < m_PlaneBuffers.Length; ++i)\r\n            {\r\n                if (!m_PlaneUsed[i])\r\n                    continue;\r\n\r\n                ++planeCount;\r\n\r\n                int size = 0;\r\n\r\n                if (i == 0)\r\n                    size = width * height * 2;\r\n                else if (i < 5)\r\n                    size = (width - 1) * (height - 2) * 2;\r\n                else\r\n                    size = width * (height - 1) * 2;\r\n\r\n                byte[] inflatedBuffer = m_PlaneBuffers[i];\r\n\r\n                int deflatedLength = m_DeflatedBuffer.Length;\r\n                ZLibError ce = ZLib.compress2(m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size,\r\n                    ZLibCompressionLevel.Z_DEFAULT_COMPRESSION);\r\n\r\n                if (ce != ZLibError.Z_OK)\r\n                {\r\n                    Console.WriteLine(\"ZLib error: {0} (#{1})\", ce, (int) ce);\r\n                    deflatedLength = 0;\r\n                    size = 0;\r\n                }\r\n\r\n                Write((byte) (0x20 | i));\r\n                Write((byte) size);\r\n                Write((byte) deflatedLength);\r\n                Write((byte) (((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));\r\n                Write(m_DeflatedBuffer, 0, deflatedLength);\r\n\r\n                totalLength += 4 + deflatedLength;\r\n            }\r\n\r\n            int totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer;\r\n\r\n            for (int i = 0; i < totalStairBuffersUsed; ++i)\r\n            {\r\n                ++planeCount;\r\n\r\n                int count = (totalStairsUsed - (i * MaxItemsPerStairBuffer));\r\n\r\n                if (count > MaxItemsPerStairBuffer)\r\n                    count = MaxItemsPerStairBuffer;\r\n\r\n                int size = count * 5;\r\n\r\n                byte[] inflatedBuffer = m_StairBuffers[i];\r\n\r\n                int deflatedLength = m_DeflatedBuffer.Length;\r\n                ZLibError ce = ZLib.compress2(m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size,\r\n                    ZLibCompressionLevel.Z_DEFAULT_COMPRESSION);\r\n\r\n                if (ce != ZLibError.Z_OK)\r\n                {\r\n                    Console.WriteLine(\"ZLib error: {0} (#{1})\", ce, (int) ce);\r\n                    deflatedLength = 0;\r\n                    size = 0;\r\n                }\r\n\r\n                Write((byte) (9 + i));\r\n                Write((byte) size);\r\n                Write((byte) deflatedLength);\r\n                Write((byte) (((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)));\r\n                Write(m_DeflatedBuffer, 0, deflatedLength);\r\n\r\n                totalLength += 4 + deflatedLength;\r\n            }\r\n\r\n            Seek(15, System.IO.SeekOrigin.Begin);\r\n\r\n            Write((short) totalLength); // Buffer length\r\n            Write((byte) planeCount); // Plane count\r\n\r\n            /*int planes = (tiles.Length + (MaxItemsPerPlane - 1)) / MaxItemsPerPlane;\r\n\r\n            if ( planes > 255 )\r\n                 planes = 255;\r\n\r\n            int totalLength = 0;\r\n\r\n            Write( (byte) planes );\r\n            ++totalLength;\r\n\r\n            int itemIndex = 0;\r\n\r\n            for ( int i = 0; i < planes; ++i )\r\n            {\r\n                 int byteIndex = 0;\r\n\r\n                 for ( int j = 0; j < MaxItemsPerPlane && itemIndex < tiles.Length; ++j, ++itemIndex )\r\n                 {\r\n                      MultiTileEntry e = tiles[itemIndex];\r\n\r\n                      m_InflatedBuffer[byteIndex++] = (byte)((e.m_ItemID >> 8) & 0x3F);\r\n                      m_InflatedBuffer[byteIndex++] = (byte)e.m_ItemID;\r\n                      m_InflatedBuffer[byteIndex++] = (byte)e.m_OffsetX;\r\n                      m_InflatedBuffer[byteIndex++] = (byte)e.m_OffsetY;\r\n                      m_InflatedBuffer[byteIndex++] = (byte)e.m_OffsetZ;\r\n                 }\r\n\r\n                 int deflatedLength = m_DeflatedBuffer.Length;\r\n                 ZLibError ce = ZLib.compress2( m_DeflatedBuffer, ref deflatedLength, m_InflatedBuffer, byteIndex, ZLibCompressionLevel.Z_DEFAULT_COMPRESSION );\r\n\r\n                 if ( ce != ZLibError.Z_OK )\r\n                 {\r\n                      Console.WriteLine( \"ZLib error: {0} (#{1})\", ce, (int)ce );\r\n                      deflatedLength = 0;\r\n                      byteIndex = 0;\r\n                 }\r\n\r\n                 Write( (byte) 0x00 );\r\n                 Write( (byte) byteIndex );\r\n                 Write( (byte) deflatedLength );\r\n                 Write( (byte) (((byteIndex >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)) );\r\n                 Write( m_DeflatedBuffer, 0, deflatedLength );\r\n\r\n                 totalLength += 4 + deflatedLength;\r\n            }\r\n\r\n            Seek( 15, System.IO.SeekOrigin.Begin );\r\n            Write( (short) totalLength ); // Buffer length*/\r\n        }\r\n    }\r\n\r\n    internal sealed class PromptResponse : Packet\r\n    {\r\n        internal PromptResponse(uint serial, uint promptid, uint operation, string lang, string text)\r\n            : base(0xC2)\r\n        {\r\n            if (text != \"\")\r\n                EnsureCapacity(2 + 4 + 4 + 4 + 4 + (text.Length * 2));\r\n            else\r\n            {\r\n                EnsureCapacity(18);\r\n            }\r\n\r\n            Write((uint) serial);\r\n            Write((uint) promptid);\r\n            Write((uint) operation);\r\n\r\n            if (string.IsNullOrEmpty(lang))\r\n                lang = \"ENU\";\r\n\r\n            WriteAsciiFixed(lang.ToUpper(), 4);\r\n\r\n            if (text != \"\")\r\n                WriteLittleUniNull(text);\r\n        }\r\n    }\r\n\r\n    internal sealed class AssistVersion : Packet\r\n    {\r\n        internal AssistVersion()\r\n            : base(0xBE)\r\n        {\r\n            var assistVersion = $\"Razor {(typeof(AssistVersion).Assembly.GetName().Version)}\";\r\n\r\n            EnsureCapacity(3 + assistVersion.Length);\r\n\r\n            WriteAsciiNull(assistVersion);\r\n        }\r\n    }\r\n\r\n    internal sealed class QuestArrow : Packet\r\n    {\r\n        internal QuestArrow(bool active, int x, int y)\r\n            : base(0xBA, 10)\r\n        {\r\n            Write((byte) (active ? 1 : 0));\r\n            Write((ushort) x);\r\n            Write((ushort) y);\r\n        }\r\n    }\r\n\r\n    internal sealed class VirtueRequest : Packet\r\n    {\r\n        internal VirtueRequest(byte id) : base(0x12)\r\n        {\r\n            EnsureCapacity(1 + id.ToString().Length + 1);\r\n\r\n            Write((byte)0xF4);\r\n            WriteAsciiNull(id.ToString());\r\n        }\r\n    }\r\n    \r\n    public sealed class RenamePacket : Packet\r\n    {\r\n        public RenamePacket(uint serial, string newName) : base(0x75, 35)\r\n        {\r\n            Write(serial);\r\n            WriteAsciiFixed(newName, 30);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Razor/Platform.cs",
    "content": "﻿#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\nusing System.Text;\r\n\r\nnamespace Assistant\r\n{\r\n    internal static unsafe class Win32Platform\r\n    {\r\n        static Dictionary<int, int> m_KeyMap = new Dictionary<int, int>()\r\n        {\r\n            {1073741979, 3},\r\n            {8, 8},\r\n            {9, 9},\r\n            {1073741980, 12},\r\n            {13, 13},\r\n            {1073741942, 165},\r\n            {1073741896, 19},\r\n            {1073741881, 20},\r\n            {27, 27},\r\n            {1073742081, 31},\r\n            {32, 32},\r\n            {1073741899, 33},\r\n            {1073741902, 34},\r\n            {1073741901, 35},\r\n            {1073741898, 36},\r\n            {1073741904, 37},\r\n            {1073741906, 38},\r\n            {1073741903, 39},\r\n            {1073741905, 40},\r\n            {1073741943, 41},\r\n            {1073741940, 43},\r\n            {1073741897, 45},\r\n            {127, 46},\r\n            {1073741941, 47},\r\n            {97, 65},\r\n            {98, 66},\r\n            {99, 67},\r\n            {100, 68},\r\n            {101, 69},\r\n            {102, 70},\r\n            {103, 71},\r\n            {104, 72},\r\n            {105, 73},\r\n            {106, 74},\r\n            {107, 75},\r\n            {108, 76},\r\n            {109, 77},\r\n            {110, 78},\r\n            {111, 79},\r\n            {112, 80},\r\n            {113, 81},\r\n            {114, 82},\r\n            {115, 83},\r\n            {116, 84},\r\n            {117, 85},\r\n            {118, 86},\r\n            {119, 87},\r\n            {120, 88},\r\n            {121, 89},\r\n            {122, 90},\r\n            {1073742051, 91},\r\n            {1073742055, 92},\r\n            {1073741925, 93},\r\n            {1073742106, 95},\r\n            {1073741922, 96},\r\n            {1073741913, 97},\r\n            {1073741914, 98},\r\n            {1073741915, 99},\r\n            {1073741916, 100},\r\n            {1073741917, 101},\r\n            {1073741918, 102},\r\n            {1073741919, 103},\r\n            {1073741920, 104},\r\n            {1073741921, 105},\r\n            {1073741909, 106},\r\n            {1073741911, 107},\r\n            {1073741910, 109},\r\n            {1073741923, 110},\r\n            {1073741908, 111},\r\n            {1073741882, 112},\r\n            {1073741883, 113},\r\n            {1073741884, 114},\r\n            {1073741885, 115},\r\n            {1073741886, 116},\r\n            {1073741887, 117},\r\n            {1073741888, 118},\r\n            {1073741889, 119},\r\n            {1073741890, 120},\r\n            {1073741891, 121},\r\n            {1073741892, 122},\r\n            {1073741893, 123},\r\n            {1073741928, 124},\r\n            {1073741929, 125},\r\n            {1073741930, 126},\r\n            {1073741931, 127},\r\n            {1073741932, 128},\r\n            {1073741933, 129},\r\n            {1073741934, 130},\r\n            {1073741935, 131},\r\n            {1073741936, 132},\r\n            {1073741937, 133},\r\n            {1073741938, 134},\r\n            {1073741939, 135},\r\n            {1073741907, 144},\r\n            {1073741895, 145},\r\n            {1073742086, 173},\r\n            {1073741953, 174},\r\n            {1073741952, 175},\r\n            {1073742082, 176},\r\n            {1073742083, 177},\r\n            {1073742084, 178},\r\n            {1073742085, 179},\r\n            {1073742089, 180},\r\n            {1073742087, 181},\r\n            {48, 48},\r\n            {49, 49},\r\n            {50, 50},\r\n            {51, 51},\r\n            {52, 52},\r\n            {53, 53},\r\n            {54, 54},\r\n            {55, 55},\r\n            {56, 56},\r\n            {57, 57},\r\n        };\r\n\r\n        internal static int MapKey(int key)\r\n        {\r\n            int keycode;\r\n\r\n            if (!m_KeyMap.TryGetValue(key, out keycode))\r\n            {\r\n                keycode = 0;\r\n            }\r\n\r\n            return keycode;\r\n        }\r\n\r\n        static Dictionary<int, int> m_KeyModMap = new Dictionary<int, int>()\r\n        {\r\n            {3, 512},\r\n            {192, 1024},\r\n            {195, 1536},\r\n            {768, 2048},\r\n            {771, 2560},\r\n            {960, 3072},\r\n            {963, 3584},\r\n        };\r\n\r\n        internal static int MapKeyMod(int key)\r\n        {\r\n            int keycode;\r\n\r\n            if (!m_KeyModMap.TryGetValue(key, out keycode))\r\n            {\r\n                keycode = 0;\r\n            }\r\n\r\n            return keycode;\r\n        }\r\n\r\n        [DllImport(\"Platform.dll\")]\r\n        internal static unsafe extern IntPtr CaptureScreen(IntPtr handle, bool isFullScreen, string msgStr);\r\n\r\n        [DllImport(\"Platform.dll\")]\r\n        internal static unsafe extern void BringToFront(IntPtr hWnd);\r\n\r\n        [DllImport(\"user32.dll\")]\r\n        internal static extern ushort GetAsyncKeyState(int key);\r\n\r\n        [DllImport(\"user32.dll\")]\r\n        internal static extern bool SetForegroundWindow(IntPtr hWnd);\r\n    }\r\n\r\n    internal static unsafe class LinuxPlatform\r\n    {\r\n        [DllImport(\"libX11\")]\r\n        private static extern IntPtr XOpenDisplay(IntPtr display);\r\n\r\n        [DllImport(\"libX11\")]\r\n        private static extern IntPtr XCloseDisplay(IntPtr display);\r\n\r\n        [DllImport(\"libX11\")]\r\n        private static extern int XRaiseWindow(IntPtr display, IntPtr window);\r\n\r\n        [DllImport(\"libX11\")]\r\n        private static extern int XGetInputFocus(IntPtr display, IntPtr window, IntPtr focus_return);\r\n\r\n        [DllImport(\"libX11\")]\r\n        private static extern int XQueryKeymap(IntPtr display, byte[] keys);\r\n\r\n        [DllImport(\"libX11\")]\r\n        private static extern int XKeysymToKeycode(IntPtr display, int key);\r\n\r\n        private static IntPtr m_Display;\r\n\r\n        private static IntPtr Display\r\n        {\r\n            get\r\n            {\r\n                if (m_Display == IntPtr.Zero)\r\n                    m_Display = XOpenDisplay(IntPtr.Zero);\r\n                return m_Display;\r\n            }\r\n        }\r\n\r\n        internal static void BringToFront(IntPtr window)\r\n        {\r\n            XRaiseWindow(Display, window);\r\n        }\r\n        \r\n        /* List of mappings between:\r\n         * Windows 'Virtual Key Codes' (https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)\r\n         * and\r\n         * Unix X11 Keysyms (https://cgit.freedesktop.org/xorg/proto/x11proto/tree/keysymdef.h)\r\n         *\r\n         * Testing was done on Gentoo Linux with an Unicomp New Model M, standard ANSI 104-key layout. (https://www.pckeyboard.com/page/product/NEW_M)\r\n         * The keyboard used may affect the results for some of the more ambiguous keysyms and keycodes. Hopefully this works for most folks.\r\n         */\r\n        static Dictionary<int, int> m_MapX11Key = new Dictionary<int, int>()\r\n        {\r\n            // Utility keys.\r\n            // For many of these, Windows lists one keycode while unix has a separate keysym for each symbol on the key.\r\n            // In such cases, the primary symbol is used for the mapping.\r\n            {0x08, 0xFF08}, // Backspace\r\n            {0x09, 0xFF09}, // Tab\r\n            {0x0C, 0xFF0B}, // Clear\r\n            {0x0D, 0xFF0D}, // Return\r\n            {0x20, 0x0020}, // Space\r\n            {0xDE, 0x0027}, // Single/Double quote key\r\n            {0xDB, 0x005B}, // Bracket left\r\n            {0xDD, 0x005D}, // Bracket right\r\n            {0xBC, 0x002C}, // Comma / Less than (<)\r\n            {0xBE, 0x002E}, // Period / Greater than (>)\r\n            {0xDC, 0x005C}, // Backslash\r\n            {0xBB, 0x003D}, // Addition / Equals\r\n            {0xBF, 0x002F}, // Forward slash\r\n            {0xBD, 0x002D}, // Dash / Minus\r\n            {0xC0, 0x0060}, // Grave / Tilde\r\n            {0xBA, 0x003B}, // Semi-Colon / Colon\r\n            {0x13, 0xFF13}, // Pause\r\n            {0x1B, 0xFF1B}, // Escape\r\n            {0x26, 0xFF52}, // Up arrow\r\n            {0x28, 0xFF54}, // Down arrow\r\n            {0x25, 0xFF51}, // Left arrow\r\n            {0x27, 0xFF53}, // Right arrow\r\n            {0x2D, 0xFF63}, // Insert\r\n            {0x2E, 0xFFFF}, // Delete\r\n            {0x24, 0xFF50}, // Home\r\n            {0x23, 0xFF57}, // End\r\n            {0x21, 0xFF55}, // Page Up\r\n            {0x22, 0xFF56}, // Page Down\r\n            {0x14, 0xFFE5}, // Caps Lock\r\n            {0x91, 0xFF14}, // Scroll Lock\r\n            // Same physical key as scroll lock, unlikely to be needed for UO\r\n            //{0x91, 0xFF15}, // SysRq\r\n\r\n            // Modifier keys\r\n            // Unix has no combined keysym for these, handled separately in GetAsyncKeyState() below.\r\n            //{0x10, 0xFF??}, // Shift\r\n            //{0x11, 0xFF??}, // Control\r\n            //{0x12, 0xFF??}, // Alt\r\n            {0xA0, 0xFFE1}, // LSHIFT\r\n            {0xA1, 0xFFE2}, // RSHIFT\r\n            {0xA2, 0xFFE3}, // LCONTROL\r\n            {0xA3, 0xFFE4}, // RCONTROL\r\n            {0xA4, 0xFFE9}, // LALT\r\n            {0xA5, 0xFFEA}, // RALT\r\n            // These are pretty ambiguous and I don't have a windows machine handy to verify them.\r\n            //{0x5B, 0x00EB}, // Super L / Windows key L\r\n            //{0x5C, 0x00EC}, // Super R / Windows key R\r\n            //{0x5D, 0x0067}, // Menu\r\n\r\n            // Numeric Keypad\r\n            {0x90, 0xFFBE}, // Num lock\r\n            {0x60, 0xFFB0}, // Numpad0\r\n            {0x61, 0xFFB1},\r\n            {0x62, 0xFFB2},\r\n            {0x63, 0xFFB3},\r\n            {0x64, 0xFFB4},\r\n            {0x65, 0xFFB5},\r\n            {0x66, 0xFFB6},\r\n            {0x67, 0xFFB7},\r\n            {0x68, 0xFFB8},\r\n            {0x69, 0xFFB0}, // Numpad9\r\n            {0x6F, 0xFFAF}, // Divide\r\n            {0x6A, 0xFFAA}, // Multiply\r\n            {0x6D, 0xFFAD}, // Subtract\r\n            {0x6B, 0xFFAB}, // Add\r\n            {0x6C, 0xFFAE}, // Decimal\r\n            // Windows has no separate keycode for these, so ignore them for now.\r\n            // Should probably be handled similar to how Shift/Control/Alt are, below.\r\n            //{0x, 0xFF95}, // KP_Home\r\n            //{0x, 0xFF97}, // KP_Up\r\n            //{0x, 0xFF9A}, // KP_PageUp\r\n            //{0x, 0xFF96}, // KP_Left\r\n            //{0x, 0xFF98}, // KP_Right\r\n            //{0x, 0xFF9C}, // KP_End\r\n            //{0x, 0xFF99}, // KP_Down\r\n            //{0x, 0xFF9B}, // KP_PageDown\r\n            //{0x, 0xFF8D}, // KP_Enter\r\n\r\n            // F1-F24\r\n            {0x70, 0xFFBE},\r\n            {0x71, 0xFFBF},\r\n            {0x72, 0xFFC0},\r\n            {0x73, 0xFFC1},\r\n            {0x74, 0xFFC2},\r\n            {0x75, 0xFFC3},\r\n            {0x76, 0xFFC4},\r\n            {0x77, 0xFFC5},\r\n            {0x78, 0xFFC6},\r\n            {0x79, 0xFFC7},\r\n            {0x7A, 0xFFC8},\r\n            {0x7B, 0xFFC9},\r\n            {0x7C, 0xFFCA},\r\n            {0x7D, 0xFFCB},\r\n            {0x7E, 0xFFCC},\r\n            {0x7F, 0xFFCD},\r\n            {0x80, 0xFFCE},\r\n            {0x81, 0xFFCF},\r\n            {0x82, 0xFFD0},\r\n            {0x83, 0xFFD1},\r\n            {0x84, 0xFFD2},\r\n            {0x85, 0xFFD3},\r\n            {0x86, 0xFFD4},\r\n            {0x87, 0xFFD5},\r\n\r\n            // 0-9 map directly\r\n            {0x30, 0x0030},\r\n            {0x31, 0x0031},\r\n            {0x32, 0x0032},\r\n            {0x33, 0x0033},\r\n            {0x34, 0x0034},\r\n            {0x35, 0x0035},\r\n            {0x36, 0x0036},\r\n            {0x37, 0x0037},\r\n            {0x38, 0x0038},\r\n            {0x39, 0x0039},\r\n\r\n            // Captial A-Z map directly.\r\n            {0x41, 0x0041},\r\n            {0x42, 0x0042},\r\n            {0x43, 0x0043},\r\n            {0x44, 0x0044},\r\n            {0x45, 0x0045},\r\n            {0x46, 0x0046},\r\n            {0x47, 0x0047},\r\n            {0x48, 0x0048},\r\n            {0x49, 0x0049},\r\n            {0x4A, 0x004A},\r\n            {0x4B, 0x004B},\r\n            {0x4C, 0x004C},\r\n            {0x4D, 0x004D},\r\n            {0x4E, 0x004E},\r\n            {0x4F, 0x004F},\r\n            {0x50, 0x0050},\r\n            {0x51, 0x0051},\r\n            {0x52, 0x0052},\r\n            {0x53, 0x0053},\r\n            {0x54, 0x0054},\r\n            {0x55, 0x0055},\r\n            {0x56, 0x0056},\r\n            {0x57, 0x0057},\r\n            {0x58, 0x0058},\r\n            {0x59, 0x0059},\r\n            {0x5A, 0x005A},\r\n\r\n            // Windows doesn't have lowercase A-Z keycodes.\r\n        };\r\n        \r\n        internal static int MapX11Key(int key)\r\n        {\r\n            int keycode;\r\n\r\n            // If no mapping is found, pass the unmapped code back out.\r\n            // Can't be any worse than the way it used to work.\r\n            if (!m_MapX11Key.TryGetValue(key, out keycode))\r\n                keycode = key;\r\n\r\n            return keycode;\r\n        }\r\n\r\n        // A linux-version of WinUser.dll's GetAsyncKeyState()\r\n        // Take the (Windows) Virtual Key Code, convert it to an X11 KeySym, then back to the X11 Keycode, then check if it's pressed.\r\n        internal static ushort GetAsyncKeyState(int winkey)\r\n        {\r\n            try\r\n            {\r\n                int key = 0; int key2 = 0;\r\n                bool pressed = false; bool pressed2 = false;\r\n\r\n                // Convert Windows Virtual Key Code to an X11 Keysym.\r\n                // Code elsewhere distills Left/Right modifier keys to Window's single keycode. Un-distill them here\r\n                if (winkey == 0x10)      { key = 0xFFE1; key2 = 0xFFE2; }               // Any shift key\r\n                else if (winkey == 0x11) { key = 0xFFE3; key2 = 0xFFE4; }               // Any ctrl key\r\n                else if (winkey == 0x12) { key = 0xFFE9; key2 = 0xFFEA; }               // Any alt key\r\n                else                     { key = LinuxPlatform.MapX11Key (winkey); }    // Any other key, map the keycode to a keysym\r\n\r\n                // Get physical keyboard state - every key being pressed is listed in the byte array\r\n                var szKey = new byte[32];\r\n                int res = XQueryKeymap(Display, szKey);\r\n\r\n                // Convert X11 Keysym to X11 Keycode\r\n                int code = XKeysymToKeycode(Display, (int) key);\r\n\r\n                // Check if keycode is included in the keyboard state.\r\n                var r = szKey[code / 8];\r\n                var s = (1 << (code % 8));\r\n                pressed = Convert.ToBoolean(r & s);\r\n\r\n                // Check the second modifier key if required\r\n                if (key2 > 0)\r\n                {\r\n                    int code2 = XKeysymToKeycode(Display, (int) key2);\r\n                    var r2 = szKey[code2 / 8];\r\n                    var s2 = (1 << (code2 % 8));\r\n                    pressed2 = Convert.ToBoolean(r2 & s2);\r\n                }\r\n\r\n                if (pressed || pressed2)\r\n                    return (ushort) 0xFF00;\r\n                else\r\n                    return (ushort) 0;\r\n            }\r\n            catch\r\n            {\r\n                return (ushort) 0;\r\n            }\r\n        }\r\n\r\n        internal static bool SetForegroundWindow(IntPtr hWnd)\r\n        {\r\n            XRaiseWindow(Display, hWnd);\r\n            return true;\r\n        }\r\n    }\r\n\r\n    internal static unsafe class Platform\r\n    {\r\n        internal static ushort GetAsyncKeyState(int key)\r\n        {\r\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\r\n                return Win32Platform.GetAsyncKeyState(key);\r\n            else if (Environment.OSVersion.Platform == PlatformID.Unix)\r\n                return LinuxPlatform.GetAsyncKeyState(key);\r\n            else\r\n                return 0;\r\n        }\r\n\r\n        internal static IntPtr CaptureScreen(IntPtr handle, bool isFullScreen, string msgStr)\r\n        {\r\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\r\n                return Win32Platform.CaptureScreen(handle, isFullScreen, msgStr);\r\n            else\r\n                return IntPtr.Zero;\r\n        }\r\n\r\n        internal static void BringToFront(IntPtr window)\r\n        {\r\n            try\r\n            {\r\n                if (Environment.OSVersion.Platform == PlatformID.Win32NT)\r\n                    Win32Platform.BringToFront(window);\r\n                else\r\n                    LinuxPlatform.BringToFront(window);\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        internal static bool SetForegroundWindow(IntPtr hWnd)\r\n        {\r\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\r\n                return Win32Platform.SetForegroundWindow(hWnd);\r\n            else if (Environment.OSVersion.Platform == PlatformID.Unix)\r\n                return LinuxPlatform.SetForegroundWindow(hWnd);\r\n            else\r\n                return false;\r\n        }\r\n\r\n        [DllImport(\"User32.dll\")]\r\n        private static extern IntPtr GetSystemMenu(IntPtr wnd, bool reset);\r\n\r\n        [DllImport(\"User32.dll\")]\r\n        private static extern IntPtr EnableMenuItem(IntPtr menu, uint item, uint options);\r\n\r\n\r\n        [DllImport(\"msvcrt.dll\")]\r\n        internal static unsafe extern void memcpy(void* to, void* from, int len);\r\n\r\n        [DllImport(\"user32.dll\")]\r\n        internal static extern uint PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);\r\n\r\n\r\n        [DllImport(\"kernel32.dll\")]\r\n        internal static extern uint GlobalGetAtomName(ushort atom, StringBuilder buff, int bufLen);\r\n\r\n        [DllImport(\"Advapi32.dll\")]\r\n        internal static extern int GetUserNameA(StringBuilder buff, int* len);\r\n\r\n        [DllImport(\"user32.dll\")]\r\n        internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);\r\n\r\n\r\n        public static string GetWindowsUserName()\r\n        {\r\n            int len = 1024;\r\n            StringBuilder sb = new StringBuilder(len);\r\n            if (GetUserNameA(sb, &len) != 0)\r\n                return sb.ToString();\r\n            else\r\n                return \"\";\r\n        }\r\n\r\n        internal static void DisableCloseButton(IntPtr handle)\r\n        {\r\n            if (Environment.OSVersion.Platform == PlatformID.Win32NT)\r\n            {\r\n                IntPtr menu = GetSystemMenu(handle, false);\r\n                EnableMenuItem(menu, 0xF060, 0x00000002); //menu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Razor/Properties/AssemblyInfo.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System.Reflection;\r\nusing System.Runtime.InteropServices;\r\n\r\n//\r\n// General Information about an assembly is controlled through the following\r\n// set of attributes. Change these attribute values to modify the information\r\n// associated with an assembly.\r\n//\r\n[assembly: AssemblyTitle(\"Razor\")]\r\n[assembly: AssemblyDescription(\"Ultima Online Assistant Tool\")]\r\n[assembly: AssemblyConfiguration(\"\")]\r\n[assembly: AssemblyCompany(\"https://github.com/markdwags/Razor\")]\r\n[assembly: AssemblyProduct(\"Razor\")]\r\n[assembly: AssemblyCopyright(\"\")]\r\n[assembly: AssemblyTrademark(\"\")]\r\n[assembly: AssemblyCulture(\"\")]\r\n\r\n//\r\n// Version information for an assembly consists of the following four values:\r\n//\r\n//      Major Version\r\n//      Minor Version\r\n//      Build Number\r\n//      Revision\r\n//\r\n// You can specify all the values or you can default the Revision and Build Numbers\r\n// by using the '*' as shown below:\r\n\r\n[assembly: AssemblyVersion(\"1.10.0.0\")]\r\n[assembly: AssemblyFileVersion(\"1.10.0.0\")]\r\n[assembly: AssemblyInformationalVersion(\"1.10.0.0\")]\r\n\r\n//\r\n// In order to sign your assembly you must specify a key to use. Refer to the\r\n// Microsoft .NET Framework documentation for more information on assembly signing.\r\n//\r\n// Use the attributes below to control which key is used for signing.\r\n//\r\n// Notes:\r\n//   (*) If no key is specified, the assembly is not signed.\r\n//   (*) KeyName refers to a key that has been installed in the Crypto Service\r\n//       Provider (CSP) on your machine. KeyFile refers to a file which contains\r\n//       a key.\r\n//   (*) If the KeyFile and the KeyName values are both specified, the\r\n//       following processing occurs:\r\n//       (1) If the KeyName can be found in the CSP, that key is used.\r\n//       (2) If the KeyName does not exist and the KeyFile does exist, the key\r\n//           in the KeyFile is installed into the CSP and used.\r\n//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.\r\n//       When specifying the KeyFile, the location of the KeyFile should be\r\n//       relative to the project output directory which is\r\n//       %Project Directory%\\obj\\<configuration>. For example, if your KeyFile is\r\n//       located in the project directory, you would specify the AssemblyKeyFile\r\n//       attribute as [assembly: AssemblyKeyFile(\"..\\\\..\\\\mykey.snk\")]\r\n//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework\r\n//       documentation for more information on this.\r\n//\r\n[assembly: AssemblyDelaySign(false)]\r\n//[assembly: AssemblyKeyFile(\"\")]\r\n//[assembly: AssemblyKeyName(\"\")]\r\n[assembly: ComVisibleAttribute(false)]"
  },
  {
    "path": "Razor/Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\r\n// <auto-generated>\r\n//     This code was generated by a tool.\r\n//     Runtime Version:4.0.30319.42000\r\n//\r\n//     Changes to this file may cause incorrect behavior and will be lost if\r\n//     the code is regenerated.\r\n// </auto-generated>\r\n//------------------------------------------------------------------------------\r\n\r\nnamespace Assistant.Properties {\r\n    using System;\r\n    \r\n    \r\n    /// <summary>\r\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\r\n    /// </summary>\r\n    // This class was auto-generated by the StronglyTypedResourceBuilder\r\n    // class via a tool like ResGen or Visual Studio.\r\n    // To add or remove a member, edit your .ResX file then rerun ResGen\r\n    // with the /str option, or rebuild your VS project.\r\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"16.0.0.0\")]\r\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\r\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\r\n    internal class Resources {\r\n        \r\n        private static global::System.Resources.ResourceManager resourceMan;\r\n        \r\n        private static global::System.Globalization.CultureInfo resourceCulture;\r\n        \r\n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\r\n        internal Resources() {\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   Returns the cached ResourceManager instance used by this class.\r\n        /// </summary>\r\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r\n        internal static global::System.Resources.ResourceManager ResourceManager {\r\n            get {\r\n                if (object.ReferenceEquals(resourceMan, null)) {\r\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"Assistant.Properties.Resources\", typeof(Resources).Assembly);\r\n                    resourceMan = temp;\r\n                }\r\n                return resourceMan;\r\n            }\r\n        }\r\n        \r\n        /// <summary>\r\n        ///   Overrides the current thread's CurrentUICulture property for all\r\n        ///   resource lookups using this strongly typed resource class.\r\n        /// </summary>\r\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r\n        internal static global::System.Globalization.CultureInfo Culture {\r\n            get {\r\n                return resourceCulture;\r\n            }\r\n            set {\r\n                resourceCulture = value;\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Razor/Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n</root>"
  },
  {
    "path": "Razor/Razor.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" ToolsVersion=\"12.0\">\r\n  <PropertyGroup>\r\n    <ProjectType>Local</ProjectType>\r\n    <ProductVersion>8.0.50727</ProductVersion>\r\n    <SchemaVersion>2.0</SchemaVersion>\r\n    <ProjectGuid>{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}</ProjectGuid>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ApplicationIcon>UI\\App.ico</ApplicationIcon>\r\n    <AssemblyName>Razor</AssemblyName>\r\n    <DefaultClientScript>JScript</DefaultClientScript>\r\n    <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>\r\n    <DefaultTargetSchema>IE50</DefaultTargetSchema>\r\n    <DelaySign>false</DelaySign>\r\n    <OutputType>WinExe</OutputType>\r\n    <RootNamespace>Assistant</RootNamespace>\r\n    <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>\r\n    <StartupObject>Assistant.Engine</StartupObject>\r\n    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>\r\n    <OldToolsVersion>2.0</OldToolsVersion>\r\n    <TargetFrameworkProfile>\r\n    </TargetFrameworkProfile>\r\n    <PublishUrl>E:\\Programming\\razor-markdwags\\Build\\</PublishUrl>\r\n    <Install>true</Install>\r\n    <InstallFrom>Disk</InstallFrom>\r\n    <UpdateEnabled>false</UpdateEnabled>\r\n    <UpdateMode>Foreground</UpdateMode>\r\n    <UpdateInterval>7</UpdateInterval>\r\n    <UpdateIntervalUnits>Days</UpdateIntervalUnits>\r\n    <UpdatePeriodically>false</UpdatePeriodically>\r\n    <UpdateRequired>false</UpdateRequired>\r\n    <MapFileExtensions>true</MapFileExtensions>\r\n    <AutorunEnabled>true</AutorunEnabled>\r\n    <ApplicationRevision>0</ApplicationRevision>\r\n    <ApplicationVersion>1.5.1.%2a</ApplicationVersion>\r\n    <UseApplicationTrust>false</UseApplicationTrust>\r\n    <PublishWizardCompleted>true</PublishWizardCompleted>\r\n    <BootstrapperEnabled>true</BootstrapperEnabled>\r\n  </PropertyGroup>\r\n  <PropertyGroup />\r\n  <PropertyGroup>\r\n    <SignAssembly>false</SignAssembly>\r\n  </PropertyGroup>\r\n  <PropertyGroup />\r\n  <PropertyGroup />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x86'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>..\\bin\\Win32\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <BaseAddress>285212672</BaseAddress>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <FileAlignment>4096</FileAlignment>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>\r\n    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x86'\">\r\n    <OutputPath>..\\bin\\Win32\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <BaseAddress>285212672</BaseAddress>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <Optimize>true</Optimize>\r\n    <FileAlignment>4096</FileAlignment>\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup />\r\n  <PropertyGroup>\r\n    <ApplicationManifest>Razor.manifest</ApplicationManifest>\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <ManifestCertificateThumbprint>0212178022788294553B69C3C9C642E8834CB0DB</ManifestCertificateThumbprint>\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <ManifestKeyFile>Razor_TemporaryKey.pfx</ManifestKeyFile>\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <GenerateManifests>false</GenerateManifests>\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <SignManifests>false</SignManifests>\r\n  </PropertyGroup>\r\n  <PropertyGroup>\r\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>bin\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <BaseAddress>285212672</BaseAddress>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <FileAlignment>4096</FileAlignment>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>AnyCPU</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>\r\n    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|AnyCPU'\">\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <BaseAddress>285212672</BaseAddress>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <Optimize>true</Optimize>\r\n    <FileAlignment>4096</FileAlignment>\r\n    <PlatformTarget>AnyCPU</PlatformTarget>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Debug|x64'\">\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <OutputPath>..\\bin\\x64\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <BaseAddress>285212672</BaseAddress>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <FileAlignment>4096</FileAlignment>\r\n    <DebugType>full</DebugType>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <UseVSHostingProcess>false</UseVSHostingProcess>\r\n    <LangVersion>7.3</LangVersion>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>\r\n    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)' == 'Release|x64'\">\r\n    <OutputPath>..\\bin\\x64\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <BaseAddress>285212672</BaseAddress>\r\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r\n    <Optimize>true</Optimize>\r\n    <FileAlignment>4096</FileAlignment>\r\n    <PlatformTarget>x64</PlatformTarget>\r\n    <LangVersion>7.3</LangVersion>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\r\n    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"cuoapi, Version=1.3.0.0, Culture=neutral, processorArchitecture=AMD64\">\r\n      <SpecificVersion>False</SpecificVersion>\r\n      <HintPath>.\\cuoapi.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"mscorlib\" />\r\n    <Reference Include=\"System\">\r\n      <Name>System</Name>\r\n    </Reference>\r\n    <Reference Include=\"System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\System.Buffers.4.5.1\\lib\\net461\\System.Buffers.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System.Configuration\" />\r\n    <Reference Include=\"System.Data\">\r\n      <Name>System.Data</Name>\r\n    </Reference>\r\n    <Reference Include=\"System.Drawing\">\r\n      <Name>System.Drawing</Name>\r\n    </Reference>\r\n    <Reference Include=\"System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\System.Memory.4.5.5\\lib\\net461\\System.Memory.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System.Numerics\" />\r\n    <Reference Include=\"System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\System.Numerics.Vectors.4.5.0\\lib\\net46\\System.Numerics.Vectors.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\r\n      <HintPath>..\\packages\\System.Runtime.CompilerServices.Unsafe.4.5.3\\lib\\net461\\System.Runtime.CompilerServices.Unsafe.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System.Windows.Forms\">\r\n      <Name>System.Windows.Forms</Name>\r\n    </Reference>\r\n    <Reference Include=\"System.Xml\">\r\n      <Name>System.XML</Name>\r\n    </Reference>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Agents\\BuyAgent.cs\" />\r\n    <Compile Include=\"Agents\\IgnoreAgent.cs\" />\r\n    <Compile Include=\"Agents\\OrganizerAgent.cs\" />\r\n    <Compile Include=\"Agents\\RestockAgent.cs\" />\r\n    <Compile Include=\"Agents\\SearchExemptionAgent.cs\" />\r\n    <Compile Include=\"Agents\\SellAgent.cs\" />\r\n    <Compile Include=\"Agents\\UseOnceAgent.cs\" />\r\n    <Compile Include=\"Boat\\BoatWindow.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Boat\\BoatWindow.Designer.cs\">\r\n      <DependentUpon>BoatWindow.cs</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"Client\\ClassicUO.cs\" />\r\n    <Compile Include=\"Client\\OSI.cs\" />\r\n    <Compile Include=\"Core\\ActionQueue.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Agents\\Agents.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\BuffDebuffManager.cs\" />\r\n    <Compile Include=\"Core\\BodCapture.cs\" />\r\n    <Compile Include=\"Core\\ClassicUOManager.cs\" />\r\n    <Compile Include=\"Core\\CooldownManager.cs\" />\r\n    <Compile Include=\"Core\\Dress.cs\" />\r\n    <Compile Include=\"Core\\EncodedSpeech.cs\" />\r\n    <Compile Include=\"Core\\DamageTracker.cs\" />\r\n    <Compile Include=\"Core\\StaffToolsManager.cs\" />\r\n    <Compile Include=\"Core\\MessageManager.cs\" />\r\n    <Compile Include=\"Core\\Overrides.cs\" />\r\n    <Compile Include=\"Core\\SystemMessages.cs\" />\r\n    <Compile Include=\"Core\\TextFilterManager.cs\" />\r\n    <Compile Include=\"Gumps\\Gump.cs\" />\r\n    <Compile Include=\"Gumps\\GumpButtonType.cs\" />\r\n    <Compile Include=\"Gumps\\GumpCollection.cs\" />\r\n    <Compile Include=\"Gumps\\GumpElement.cs\" />\r\n    <Compile Include=\"Gumps\\GumpPage.cs\" />\r\n    <Compile Include=\"Gumps\\GumpType.cs\" />\r\n    <Compile Include=\"Core\\OverheadManager.cs\" />\r\n    <Compile Include=\"Core\\WaypointManager.cs\" />\r\n    <Compile Include=\"Filters\\SoundMusicManager.cs\" />\r\n    <Compile Include=\"Filters\\TargetFilterManager.cs\" />\r\n    <Compile Include=\"Core\\FriendsManager.cs\" />\r\n    <Compile Include=\"Core\\MessageInBottleCapture.cs\" />\r\n    <Compile Include=\"Core\\ContainerLabels.cs\" />\r\n    <Compile Include=\"Core\\GoldPerHourTimer.cs\" />\r\n    <Compile Include=\"Core\\GateTimer.cs\" />\r\n    <Compile Include=\"Core\\SkillTimer.cs\" />\r\n    <Compile Include=\"Core\\BandageTimer.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Commands.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Counters.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\DressList.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\TargetingClosest.cs\" />\r\n    <Compile Include=\"Core\\TargetingNextPrevious.cs\" />\r\n    <Compile Include=\"Filters\\Death.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Filters\\Filter.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Filters\\Light.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Filters\\MessageFilter.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Filters\\MobileFilter.cs\" />\r\n    <Compile Include=\"Filters\\SoundFilters.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Filters\\StaffItems.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Filters\\VetRewardGump.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Filters\\WallStaticFilter.cs\" />\r\n    <Compile Include=\"Filters\\Weather.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Geometry.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Gumps\\Internal\\BuffGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\CooldownGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\DamageTrackerListGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\InputDialogGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\MobileInfoGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\ItemInfoGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\DamageTrackerGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\HotKeyGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\BoatControlGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\SystemMessagesGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\AgentsGump.cs\" />\r\n    <Compile Include=\"Gumps\\Internal\\TestMessageGump.cs\" />\r\n    <Compile Include=\"HotKeys\\Counters.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"HotKeys\\HotKeys.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"HotKeys\\Misc.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"HotKeys\\SkillHotKeys.cs\" />\r\n    <Compile Include=\"HotKeys\\SpecialMoves.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"HotKeys\\Undress.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Item.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\ItemID.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Agents\\ScavengerAgent.cs\" />\r\n    <Compile Include=\"Network\\PacketWriter.cs\" />\r\n    <Compile Include=\"Scripts\\AgentCommands.cs\" />\r\n    <Compile Include=\"Scripts\\Engine\\Interpreter.cs\" />\r\n    <Compile Include=\"Scripts\\Engine\\Lexer.cs\" />\r\n    <Compile Include=\"Macros\\MacroVariables.cs\" />\r\n    <Compile Include=\"Macros\\Actions.cs\">\r\n      <SubType>Component</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Macros\\Macro.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Macros\\MacroManager.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Main.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Map.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Scripts\\Aliases.cs\" />\r\n    <Compile Include=\"Scripts\\Commands.cs\" />\r\n    <Compile Include=\"Scripts\\Engine\\TextParser.cs\" />\r\n    <Compile Include=\"Scripts\\Expressions.cs\" />\r\n    <Compile Include=\"Scripts\\Helpers\\CommandHelper.cs\" />\r\n    <Compile Include=\"Scripts\\RazorScript.cs\" />\r\n    <Compile Include=\"Scripts\\ScriptVariables.cs\" />\r\n    <Compile Include=\"Scripts\\ScriptManager.cs\" />\r\n    <Compile Include=\"Map\\MapWindow.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Map\\Region.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Map\\UOMapControl.cs\">\r\n      <SubType>Component</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Map\\UOMapRuneButton.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\MemHelper.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Mobile.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\MsgQueue.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Platform.cs\" />\r\n    <Compile Include=\"Client\\Client.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Network\\Handlers.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Network\\Packet.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Network\\PacketHandler.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Network\\Packets.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\ObjectPropertyList.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\PasswordMemory.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Ping.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Player.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Network\\PacketTable.cs\" />\r\n    <Compile Include=\"Client\\UOAssist.cs\" />\r\n    <Compile Include=\"Properties\\Resources.Designer.cs\">\r\n      <AutoGen>True</AutoGen>\r\n      <DesignTime>True</DesignTime>\r\n      <DependentUpon>Resources.resx</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"Core\\ScreenCapture.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Serial.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Spells.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\StealthSteps.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Targeting.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Timer.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\TargetingRandom.cs\" />\r\n    <Compile Include=\"Scripts\\TargetCommands.cs\" />\r\n    <Compile Include=\"Scripts\\SpeechCommands.cs\" />\r\n    <Compile Include=\"UI\\AddCounter.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\ArtViewer.cs\">\r\n      <SubType>UserControl</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\ArtViewer.Designer.cs\">\r\n      <DependentUpon>ArtViewer.cs</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"UI\\BuffDebuffOptions.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\BuffDebuffOptions.Designer.cs\">\r\n      <DependentUpon>BuffDebuffOptions.cs</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"UI\\Config.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\Ext.cs\" />\r\n    <Compile Include=\"UI\\SoundEntry.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\HueEntry.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\InputDropdown.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\InputBox.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\Languages.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\MacroInsertDoWhile.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\MacroInsertWhile.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\MacroInsertIf.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\MacroInsertWait.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\MessageDialog.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\ContainerLabels.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\ContainerLabels.Designer.cs\">\r\n      <DependentUpon>ContainerLabels.cs</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"UI\\Razor.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\Razor.Designer.cs\">\r\n      <DependentUpon>Razor.cs</DependentUpon>\r\n    </Compile>\r\n    <Compile Include=\"UI\\SplashScreen.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UI\\WelcomeForm.cs\">\r\n      <SubType>Form</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\UOEntity.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\Utility.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\World.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"Core\\ZLib.cs\">\r\n      <SubType>Code</SubType>\r\n    </Compile>\r\n    <Compile Include=\"UltimaSDK\\AnimationEdit.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Animations.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Animdata.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Art.cs\" />\r\n    <Compile Include=\"UltimaSDK\\ASCIIFont.cs\" />\r\n    <Compile Include=\"UltimaSDK\\BwtDecompress.cs\" />\r\n    <Compile Include=\"UltimaSDK\\CalibrationInfo.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Client.cs\" />\r\n    <Compile Include=\"UltimaSDK\\ClientHandles.cs\" />\r\n    <Compile Include=\"UltimaSDK\\FileIndex.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Files.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Gumps.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Hues.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Light.cs\" />\r\n    <Compile Include=\"UltimaSDK\\LocationPointer.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Map.cs\" />\r\n    <Compile Include=\"UltimaSDK\\MultiMap.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Multis.cs\" />\r\n    <Compile Include=\"UltimaSDK\\NativeMethods.cs\" />\r\n    <Compile Include=\"UltimaSDK\\ProcessStream.cs\" />\r\n    <Compile Include=\"UltimaSDK\\RadarCol.cs\" />\r\n    <Compile Include=\"UltimaSDK\\SkillGroups.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Skills.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Sound.cs\" />\r\n    <Compile Include=\"UltimaSDK\\SpeechList.cs\" />\r\n    <Compile Include=\"UltimaSDK\\StackDataReader.cs\" />\r\n    <Compile Include=\"UltimaSDK\\StringEntry.cs\" />\r\n    <Compile Include=\"UltimaSDK\\StringHelper.cs\" />\r\n    <Compile Include=\"UltimaSDK\\StringList.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Textures.cs\" />\r\n    <Compile Include=\"UltimaSDK\\TileData.cs\" />\r\n    <Compile Include=\"UltimaSDK\\TileList.cs\" />\r\n    <Compile Include=\"UltimaSDK\\TileMatrix.cs\" />\r\n    <Compile Include=\"UltimaSDK\\TileMatrixPatch.cs\" />\r\n    <Compile Include=\"UltimaSDK\\UnicodeFont.cs\" />\r\n    <Compile Include=\"UltimaSDK\\ValueStringBuilder.cs\" />\r\n    <Compile Include=\"UltimaSDK\\Verdata.cs\" />\r\n    <Compile Include=\"UltimaSDK\\WindowProcessStream.cs\" />\r\n    <EmbeddedResource Include=\"Boat\\BoatWindow.resx\">\r\n      <DependentUpon>BoatWindow.cs</DependentUpon>\r\n      <SubType>Designer</SubType>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"Macros\\Actions.resx\">\r\n      <DependentUpon>Actions.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"Map\\MapWindow.resx\">\r\n      <DependentUpon>MapWindow.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"Map\\UOMapControl.resx\">\r\n      <DependentUpon>UOMapControl.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"Properties\\Resources.resx\">\r\n      <Generator>ResXFileCodeGenerator</Generator>\r\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\AddCounter.resx\">\r\n      <DependentUpon>AddCounter.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\App.ico\" />\r\n    <EmbeddedResource Include=\"UI\\BuffDebuffOptions.resx\">\r\n      <DependentUpon>BuffDebuffOptions.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\SoundEntry.resx\">\r\n      <DependentUpon>SoundEntry.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\HueEntry.resx\">\r\n      <DependentUpon>HueEntry.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\InputDropdown.resx\">\r\n      <DependentUpon>InputDropdown.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\InputBox.resx\">\r\n      <DependentUpon>InputBox.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\MacroInsertDoWhile.resx\">\r\n      <DependentUpon>MacroInsertDoWhile.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\MacroInsertWhile.resx\">\r\n      <DependentUpon>MacroInsertWhile.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\MacroInsertIf.resx\">\r\n      <DependentUpon>MacroInsertIf.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\MacroInsertWait.resx\">\r\n      <DependentUpon>MacroInsertWait.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\MessageDialog.resx\">\r\n      <DependentUpon>MessageDialog.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\ContainerLabels.resx\">\r\n      <DependentUpon>ContainerLabels.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\Razor.resx\">\r\n      <DependentUpon>Razor.cs</DependentUpon>\r\n      <SubType>Designer</SubType>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\SplashScreen.resx\">\r\n      <DependentUpon>SplashScreen.cs</DependentUpon>\r\n      <SubType>Designer</SubType>\r\n    </EmbeddedResource>\r\n    <EmbeddedResource Include=\"UI\\WelcomeForm.resx\">\r\n      <DependentUpon>WelcomeForm.cs</DependentUpon>\r\n    </EmbeddedResource>\r\n    <Content Include=\"Boat\\Images\\anchor-left.png\" />\r\n    <Content Include=\"Boat\\Images\\anchor-right.png\" />\r\n    <Content Include=\"Boat\\Images\\boateast.png\" />\r\n    <Content Include=\"Boat\\Images\\boatnorth.png\" />\r\n    <Content Include=\"Boat\\Images\\boatsouth.png\" />\r\n    <Content Include=\"Boat\\Images\\boatwest.png\" />\r\n    <Content Include=\"Boat\\Images\\east.png\" />\r\n    <Content Include=\"Boat\\Images\\north.png\" />\r\n    <Content Include=\"Boat\\Images\\northeast.png\" />\r\n    <Content Include=\"Boat\\Images\\northwest.png\" />\r\n    <Content Include=\"Boat\\Images\\serpentspillar.png\" />\r\n    <Content Include=\"Boat\\Images\\south.png\" />\r\n    <Content Include=\"Boat\\Images\\southeast.png\" />\r\n    <Content Include=\"Boat\\Images\\southwest.png\" />\r\n    <Content Include=\"Boat\\Images\\west.png\" />\r\n    <Content Include=\"cuoapi.dll\">\r\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\r\n    </Content>\r\n    <Content Include=\"UI\\Lock.ico\" />\r\n    <Content Include=\"UI\\UOPS.ico\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <BootstrapperPackage Include=\"Microsoft.Net.Client.3.5\">\r\n      <Visible>False</Visible>\r\n      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>\r\n      <Install>false</Install>\r\n    </BootstrapperPackage>\r\n    <BootstrapperPackage Include=\"Microsoft.Net.Framework.3.5.SP1\">\r\n      <Visible>False</Visible>\r\n      <ProductName>.NET Framework 3.5 SP1</ProductName>\r\n      <Install>true</Install>\r\n    </BootstrapperPackage>\r\n    <BootstrapperPackage Include=\"Microsoft.Windows.Installer.3.1\">\r\n      <Visible>False</Visible>\r\n      <ProductName>Windows Installer 3.1</ProductName>\r\n      <Install>true</Install>\r\n    </BootstrapperPackage>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"app.config\" />\r\n    <None Include=\"packages.config\" />\r\n    <None Include=\"Razor.manifest\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\FastColoredTextBox\\FastColoredTextBox.csproj\">\r\n      <Project>{6DD14A85-CCFC-4774-BD26-0F5772512319}</Project>\r\n      <Name>FastColoredTextBox</Name>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <ItemGroup />\r\n  <Import Project=\"$(MSBuildBinPath)\\Microsoft.CSharp.targets\" />\r\n  <PropertyGroup>\r\n    <PreBuildEvent>\r\n    </PreBuildEvent>\r\n    <PostBuildEvent>xcopy /S /Q /Y \"$(SolutionDir)etc\\*\" \"$(SolutionDir)bin\\Win32\\$(Configuration)\\\"\r\nxcopy /S /Q /Y \"$(SolutionDir)etc\\*\" \"$(SolutionDir)bin\\x64\\$(Configuration)\\\"</PostBuildEvent>\r\n  </PropertyGroup>\r\n</Project>"
  },
  {
    "path": "Razor/Razor.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<asmv1:assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\" xmlns:asmv1=\"urn:schemas-microsoft-com:asm.v1\" xmlns:asmv2=\"urn:schemas-microsoft-com:asm.v2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <assemblyIdentity version=\"1.0.0.0\" name=\"Razor\" />\n  <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">\n    <security>\n      <requestedPrivileges xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n        <requestedExecutionLevel level=\"requireAdministrator\" uiAccess=\"false\" />\n      </requestedPrivileges>\n      <applicationRequestMinimum>\n        <PermissionSet Unrestricted=\"true\" ID=\"Custom\" SameSite=\"site\" />\n        <defaultAssemblyRequest permissionSetReference=\"Custom\" />\n      </applicationRequestMinimum>\n    </security>\n  </trustInfo>\n</asmv1:assembly>"
  },
  {
    "path": "Razor/Scripts/AgentCommands.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing Assistant.Agents;\nusing Assistant.Scripts.Engine;\n\nnamespace Assistant.Scripts\n{\n    public static class AgentCommands\n    {\n        public static void Register()\n        {\n            // \"useonce\", \"organizer\", \"org\", \"restock\", \"scav\", \"scavenger\"\n            Interpreter.RegisterCommandHandler(\"useonce\", UseOnceCommand);\n            Interpreter.RegisterCommandHandler(\"organizer\", OrganizerAgentCommand);\n            Interpreter.RegisterCommandHandler(\"organize\", OrganizerAgentCommand);\n            Interpreter.RegisterCommandHandler(\"org\", OrganizerAgentCommand);\n            Interpreter.RegisterCommandHandler(\"restock\", RestockAgentCommand);\n            Interpreter.RegisterCommandHandler(\"scav\", ScavAgentCommand);\n            Interpreter.RegisterCommandHandler(\"scavenger\", ScavAgentCommand);\n            Interpreter.RegisterCommandHandler(\"sell\", SellAgentCommand);\n        }\n\n        private static bool RestockAgentCommand(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError( \"Usage: restock (number) ['set']\");\n            }\n            \n            bool setBag = false;\n\n            if (vars.Length == 2)\n            {\n                if (vars[1].AsString().IndexOf(\"set\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    setBag = true;\n                }\n            }\n\n            if (!int.TryParse(vars[0].AsString(), out var agentNum))\n            {\n                string alias = vars[0].AsString();\n\n                foreach (RestockAgent agent in RestockAgent.Agents)\n                {\n                    if (agent.Alias.IndexOf(alias, StringComparison.OrdinalIgnoreCase) != -1)\n                    {\n                        agentNum = agent.Number;\n                        break;\n                    }\n                }\n            }\n\n            if (setBag)\n            {\n                RestockAgent.Agents[agentNum - 1].SetHB();\n            }\n            else\n            {\n                RestockAgent.Agents[agentNum - 1].OnHotKey();\n            }\n\n            return true;\n        }\n\n        private static bool UseOnceCommand(string command, Variable[] vars, bool quiet, bool force)\n        {\n            bool add = false;\n            bool container = false;\n\n            if (vars.Length == 1)\n            {\n                if (vars[0].AsString().IndexOf(\"add\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    add = true;\n                }\n                else if (vars[0].AsString().IndexOf(\"addcontainer\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    container = true;\n                }\n            }\n\n            if (add)\n            {\n                UseOnceAgent.Instance.OnAdd();\n            }\n            else if (container)\n            {\n                UseOnceAgent.Instance.OnAddContainer();\n            }\n            else\n            {\n                UseOnceAgent.Instance.OnHotKey();\n            }\n\n            return true;\n        }\n\n        private static bool OrganizerAgentCommand(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: organizer (number) ['set']\");\n            }\n\n            bool setBag = false;\n\n            if (vars.Length == 2)\n            {\n                if (vars[1].AsString().IndexOf(\"set\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    setBag = true;\n                }\n            }\n\n            if (!int.TryParse(vars[0].AsString(), out var agentNum))\n            {\n                string alias = vars[0].AsString();\n\n                foreach (OrganizerAgent agent in OrganizerAgent.Agents)\n                {\n                    if (agent.Alias.IndexOf(alias, StringComparison.OrdinalIgnoreCase) != -1)\n                    {\n                        agentNum = agent.Number;\n                        break;\n                    }\n                }\n            }\n\n            if (setBag)\n            {\n                OrganizerAgent.Agents[agentNum - 1].SetHotBag();\n            }\n            else\n            {\n                OrganizerAgent.Agents[agentNum - 1].Organize();\n            }\n\n            return true;\n        }\n\n        private static bool ScavAgentCommand(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: scavenger ['clear'/'add'/'on'/'off'/'set']\");\n            }\n\n            bool clear = false;\n            bool add = false;\n            bool set = false;\n\n            bool status = false;\n            bool enabled = true;\n\n            if (vars.Length == 1)\n            {\n                if (vars[0].AsString().IndexOf(\"clear\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    clear = true;\n                }\n                else if (vars[0].AsString().IndexOf(\"add\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    add = true;\n                }\n                else if (vars[0].AsString().IndexOf(\"on\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    status = true;\n                }\n                else if (vars[0].AsString().IndexOf(\"off\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    status = true;\n                    enabled = false;\n                }\n                else if (vars[0].AsString().IndexOf(\"set\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    set = true;\n                }\n            }\n\n            if (clear)\n            {\n                ScavengerAgent.Instance.ClearCache();\n            }\n            else if (add)\n            {\n                ScavengerAgent.Instance.OnAddToHotBag();\n            }\n            else if (status)\n            {\n                if (enabled)\n                {\n                    ScavengerAgent.Instance.Enable();\n                }\n                else\n                {\n                    ScavengerAgent.Instance.Disable();\n                }\n            }\n            else if (set)\n            {\n                ScavengerAgent.Instance.OnSetHotBag();\n            }\n\n            return true;\n        }\n\n        private static bool SellAgentCommand(string command, Variable[] vars, bool quiet, bool force)\n        {\n            SellAgent.Instance.SetHotBag();\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Scripts/Aliases.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing Assistant.Scripts.Engine;\n\nnamespace Assistant.Scripts\n{\n    public static class Aliases\n    {\n        public static void Register()\n        {\n            Interpreter.RegisterAliasHandler(\"backpack\", Backpack);\n            Interpreter.RegisterAliasHandler(\"last\", Last);\n            Interpreter.RegisterAliasHandler(\"lasttarget\", Last);\n            Interpreter.RegisterAliasHandler(\"lastobject\", LastObject);\n            Interpreter.RegisterAliasHandler(\"self\", Self);\n            Interpreter.RegisterAliasHandler(\"righthand\", RightHand);\n            Interpreter.RegisterAliasHandler(\"lefthand\", LeftHand);\n            Interpreter.RegisterAliasHandler(\"hand\", Hand);\n        }\n\n        private static uint RightHand(string alias)\n        {\n            Item item = World.Player.GetItemOnLayer(Layer.RightHand);\n\n            return World.Player != null && item != null\n                ? (uint) item.Serial\n                : 0;\n        }\n\n        private static uint LeftHand(string alias)\n        {\n            Item item = World.Player.GetItemOnLayer(Layer.LeftHand);\n\n            return World.Player != null && item != null\n                ? (uint)item.Serial\n                : 0;\n        }\n\n        private static uint Hand(string alias)\n        {\n            Item item = World.Player.GetItemOnLayer(Layer.RightHand) ?? World.Player.GetItemOnLayer(Layer.LeftHand);\n\n            return World.Player != null && item != null\n                ? (uint)item.Serial\n                : 0;\n        }\n\n        private static uint Backpack(string alias)\n        {\n            if (World.Player == null || World.Player.Backpack == null)\n                return 0;\n\n            return World.Player.Backpack.Serial;\n        }\n\n        private static uint Last(string alias)\n        {\n            if (Targeting.LastTargetInfo != null)\n                return Targeting.LastTargetInfo.Serial;\n\n            return 0;\n        }\n\n        private static uint LastObject(string alias)\n        {\n            if (World.Player.LastObject != null)\n                return World.Player.LastObject;\n\n            return 0;\n        }\n\n        private static uint Self(string alias)\n        {\n            if (World.Player == null)\n                return 0;\n\n            return World.Player.Serial;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Scripts/Commands.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Text;\nusing Assistant.Core;\nusing Assistant.HotKeys;\nusing Assistant.Scripts.Engine;\nusing Assistant.Scripts.Helpers;\nusing Ultima;\n\nnamespace Assistant.Scripts\n{\n    public static class Commands\n    {\n        public static void Register()\n        {\n            // Commands based on Actions.cs\n            Interpreter.RegisterCommandHandler(\"attack\", Attack); //Attack by serial\n            Interpreter.RegisterCommandHandler(\"cast\", Cast); //BookcastAction, etc\n\n            // Dress\n            Interpreter.RegisterCommandHandler(\"dress\", DressCommand); //DressAction\n            Interpreter.RegisterCommandHandler(\"undress\", UnDressCommand); //UndressAction\n\n            // Using stuff\n            Interpreter.RegisterCommandHandler(\"dclicktype\", DClickType); // DoubleClickTypeAction\n            Interpreter.RegisterCommandHandler(\"dclick\", DClick); //DoubleClickAction\n\n            Interpreter.RegisterCommandHandler(\"usetype\", DClickType); // DoubleClickTypeAction\n            Interpreter.RegisterCommandHandler(\"useobject\", DClick); //DoubleClickAction\n\n            // Moving stuff\n            Interpreter.RegisterCommandHandler(\"drop\", DropItem); //DropAction\n            Interpreter.RegisterCommandHandler(\"droprelloc\", DropRelLoc); //DropAction\n            Interpreter.RegisterCommandHandler(\"lift\", LiftItem); //LiftAction\n            Interpreter.RegisterCommandHandler(\"lifttype\", LiftType); //LiftTypeAction\n\n            // Gump\n            Interpreter.RegisterCommandHandler(\"waitforgump\", WaitForGump); // WaitForGumpAction\n            Interpreter.RegisterCommandHandler(\"gumpresponse\", GumpResponse); // GumpResponseAction\n            Interpreter.RegisterCommandHandler(\"gumpclose\", GumpClose); // GumpResponseAction\n\n            // Menu\n            Interpreter.RegisterCommandHandler(\"menu\", ContextMenu); //ContextMenuAction\n            Interpreter.RegisterCommandHandler(\"menuresponse\", MenuResponse); //MenuResponseAction\n            Interpreter.RegisterCommandHandler(\"waitformenu\", WaitForMenu); //WaitForMenuAction\n\n            // Prompt\n            Interpreter.RegisterCommandHandler(\"promptresponse\", PromptResponse); //PromptAction\n            Interpreter.RegisterCommandHandler(\"waitforprompt\", WaitForPrompt); //WaitForPromptAction\n\n            // Hotkey execution\n            Interpreter.RegisterCommandHandler(\"hotkey\", Hotkey); //HotKeyAction\n\n            \n\n            Interpreter.RegisterCommandHandler(\"overhead\", OverheadMessage); //OverheadMessageAction\n            Interpreter.RegisterCommandHandler(\"headmsg\", OverheadMessage); //OverheadMessageAction\n            Interpreter.RegisterCommandHandler(\"sysmsg\", SystemMessage); //SystemMessageAction\n            Interpreter.RegisterCommandHandler(\"clearsysmsg\", ClearSysMsg); //SystemMessageAction\n            Interpreter.RegisterCommandHandler(\"clearjournal\", ClearSysMsg); //SystemMessageAction\n\n            // General Waits/Pauses\n            Interpreter.RegisterCommandHandler(\"wait\", Pause); //PauseAction\n            Interpreter.RegisterCommandHandler(\"pause\", Pause); //PauseAction\n            Interpreter.RegisterCommandHandler(\"waitforsysmsg\", WaitForSysMsg);\n            Interpreter.RegisterCommandHandler(\"wfsysmsg\", WaitForSysMsg);\n\n            // Misc\n            Interpreter.RegisterCommandHandler(\"setability\", SetAbility); //SetAbilityAction\n            Interpreter.RegisterCommandHandler(\"setlasttarget\", SetLastTarget); //SetLastTargetAction\n            Interpreter.RegisterCommandHandler(\"lasttarget\", LastTarget); //LastTargetAction\n            Interpreter.RegisterCommandHandler(\"skill\", UseSkill); //SkillAction\n            Interpreter.RegisterCommandHandler(\"useskill\", UseSkill); //SkillAction\n            Interpreter.RegisterCommandHandler(\"walk\", Walk); //Move/WalkAction\n            Interpreter.RegisterCommandHandler(\"potion\", Potion);\n\n            // Script related\n            Interpreter.RegisterCommandHandler(\"script\", PlayScript);\n            Interpreter.RegisterCommandHandler(\"setvar\", SetVar);\n            Interpreter.RegisterCommandHandler(\"setvariable\", SetVar);\n            Interpreter.RegisterCommandHandler(\"unsetvar\", UnsetVar);\n            Interpreter.RegisterCommandHandler(\"unsetvariable\", UnsetVar);\n\n            Interpreter.RegisterCommandHandler(\"stop\", Stop);\n\n            Interpreter.RegisterCommandHandler(\"clearall\", ClearAll);\n\n            Interpreter.RegisterCommandHandler(\"clearhands\", ClearHands);\n\n            Interpreter.RegisterCommandHandler(\"virtue\", Virtue);\n\n            Interpreter.RegisterCommandHandler(\"random\", Random);\n\n            Interpreter.RegisterCommandHandler(\"cleardragdrop\", ClearDragDrop);\n            Interpreter.RegisterCommandHandler(\"interrupt\", Interrupt);\n\n            Interpreter.RegisterCommandHandler(\"sound\", Sound);\n            Interpreter.RegisterCommandHandler(\"music\", Music);\n\n            Interpreter.RegisterCommandHandler(\"classicuo\", ClassicUOProfile);\n            Interpreter.RegisterCommandHandler(\"cuo\", ClassicUOProfile);\n            \n            Interpreter.RegisterCommandHandler(\"rename\", Rename);\n            \n            Interpreter.RegisterCommandHandler(\"getlabel\", GetLabel);\n            \n            Interpreter.RegisterCommandHandler(\"ignore\", AddIgnore);\n            Interpreter.RegisterCommandHandler(\"unignore\", RemoveIgnore);\n            Interpreter.RegisterCommandHandler(\"clearignore\", ClearIgnore);\n            \n            Interpreter.RegisterCommandHandler(\"cooldown\", Cooldown);\n            \n            Interpreter.RegisterCommandHandler(\"poplist\", PopList);\n            Interpreter.RegisterCommandHandler(\"pushlist\", PushList);\n            Interpreter.RegisterCommandHandler(\"removelist\", RemoveList);\n            Interpreter.RegisterCommandHandler(\"createlist\", CreateList);\n            Interpreter.RegisterCommandHandler(\"clearlist\", ClearList);\n            \n            Interpreter.RegisterCommandHandler(\"settimer\", SetTimer);\n            Interpreter.RegisterCommandHandler(\"removetimer\", RemoveTimer);\n            Interpreter.RegisterCommandHandler(\"createtimer\", CreateTimer);\n        }\n        \n        private static bool PopList(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 2)\n                throw new RunTimeError(\"Usage: poplist ('list name') ('element value'/'front'/'back')\");\n\n            if (args[1].AsString() == \"front\")\n            {\n                if (force)\n                    while (Interpreter.PopList(args[0].AsString(), true, out _)) { }\n                else\n                    Interpreter.PopList(args[0].AsString(), true, out _);\n            }\n            else if (args[1].AsString() == \"back\")\n            {\n                if (force)\n                    while (Interpreter.PopList(args[0].AsString(), false, out _)) { }\n                else\n                    Interpreter.PopList(args[0].AsString(), false, out _);\n            }\n            else\n            {\n                var evaluatedVar = new Variable(args[1].AsString());\n                if (force)\n                {\n                    while (Interpreter.PopList(args[0].AsString(), evaluatedVar)) { }\n                }\n                else\n                    Interpreter.PopList(args[0].AsString(), evaluatedVar);\n            }\n\n            return true;\n        }\n\n        private static bool PushList(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length < 2 || args.Length > 3)\n                throw new RunTimeError(\"Usage: pushlist ('list name') ('element value') ['front'/'back']\");\n\n            bool front = false;\n            if (args.Length == 3)\n            {\n                if (args[2].AsString() == \"front\")\n                    front = true;\n            }\n\n            Interpreter.PushList(args[0].AsString(), new Variable(args[1].AsString()), front, force);\n\n            return true;\n        }\n\n        private static bool RemoveList(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 1)\n                throw new RunTimeError(\"Usage: removelist ('list name')\");\n\n            Interpreter.DestroyList(args[0].AsString());\n\n            return true;\n        }\n\n        private static bool CreateList(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 1)\n                throw new RunTimeError(\"Usage: createlist ('list name')\");\n\n            Interpreter.CreateList(args[0].AsString());\n\n            return true;\n        }\n\n        private static bool ClearList(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 1)\n                throw new RunTimeError(\"Usage: clearlist ('list name')\");\n\n            Interpreter.ClearList(args[0].AsString());\n\n            return true;\n        }\n\n        private static bool SetTimer(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 2)\n                throw new RunTimeError(\"Usage: settimer (timer name) (value)\");\n\n\n            Interpreter.SetTimer(args[0].AsString(), args[1].AsInt());\n            return true;\n        }\n\n        private static bool RemoveTimer(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 1)\n                throw new RunTimeError(\"Usage: removetimer (timer name)\");\n\n            Interpreter.RemoveTimer(args[0].AsString());\n            return true;\n        }\n\n        private static bool CreateTimer(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 1)\n                throw new RunTimeError(\"Usage: createtimer (timer name)\");\n\n            Interpreter.CreateTimer(args[0].AsString());\n            return true;\n        }\n\n        private static bool Cooldown(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 2)\n            {\n                throw new RunTimeError(\"Usage: cooldown ('name') ('seconds') ['hue'] ['icon'] ['sound'] ['stay visible'] ['foreground color'] ['background color']\");\n            }\n\n            string name = vars[0].AsString();\n            int seconds = vars[1].AsInt();\n            \n            int hue = 0, sound = 0;\n            string icon = \"none\";\n            bool stay = false;\n            \n            Color foreColor = Color.Empty;\n            Color backColor = Color.Empty;\n            \n            switch (vars.Length)\n            {\n                case 3:\n                    hue = vars[2].AsInt();\n\n                    break;\n                case 4:\n                    hue = vars[2].AsInt();\n                    icon = vars[3].AsString();\n\n                    break;\n                case 5:\n                    hue = vars[2].AsInt();\n                    icon = vars[3].AsString();\n                    sound = vars[4].AsInt();\n\n                    break;\n                case 6:\n                    hue = vars[2].AsInt();\n                    icon = vars[3].AsString();\n                    sound = vars[4].AsInt();\n                    stay = vars[5].AsBool();\n\n                    break;\n                case 7:\n                    hue = vars[2].AsInt();\n                    icon = vars[3].AsString();\n                    sound = vars[4].AsInt();\n                    stay = vars[5].AsBool();\n\n                    foreColor = Color.FromName(vars[6].AsString());\n\n                    break;\n                case 8:\n                    hue = vars[2].AsInt();\n                    icon = vars[3].AsString();\n                    sound = vars[4].AsInt();\n                    stay = vars[5].AsBool();\n\n                    foreColor = Color.FromName(vars[6].AsString());\n                    backColor = Color.FromName(vars[7].AsString());\n\n                    break;\n            }\n            \n            CooldownManager.AddCooldown(new Cooldown\n            {\n                Name = name,\n                EndTime = DateTime.UtcNow.AddSeconds(seconds),\n                Hue = hue,\n                Icon = icon.Equals(\"0\") ? 0 : BuffDebuffManager.GetGraphicId(icon),\n                Seconds = seconds,\n                SoundId = sound,\n                StayVisible = stay,\n                ForegroundColor = foreColor,\n                BackgroundColor = backColor\n            });\n\n            return true;\n        }\n        \n        private enum GetLabelState\n        {\n            None,\n            WaitingForFirstLabel,\n            WaitingForRemainingLabels\n        };\n        \n        private static GetLabelState _getLabelState = GetLabelState.None;\n        private static Action<Packet, PacketHandlerEventArgs, Serial, ushort, MessageType, ushort, ushort, string, string, string> _onLabelMessage;\n        private static Action _onStop;\n        \n        private static bool GetLabel(string command, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 2)\n                throw new RunTimeError(\"Usage: getlabel (serial) (name)\");\n\n            var serial = args[0].AsSerial();\n            var name = args[1].AsString(false);\n\n            var mobile = World.FindMobile(serial);\n            if (mobile != null)\n            {\n                if (mobile.IsHuman)\n                {\n                    return false;\n                }\n            }\n\n            switch (_getLabelState)\n            {\n                case GetLabelState.None:\n                    _getLabelState = GetLabelState.WaitingForFirstLabel;\n                    Interpreter.Timeout(2000, () =>\n                    {\n                        MessageManager.OnLabelMessage -= _onLabelMessage;\n                        _onLabelMessage = null;\n                        Interpreter.OnStop -= _onStop;\n                        _getLabelState = GetLabelState.None;\n                        MessageManager.GetLabelCommand = false;\n                        return true;\n                    });\n\n                    // Single click the object\n                    Client.Instance.SendToServer(new SingleClick((Serial)args[0].AsSerial()));\n\n                    // Capture all message responses\n                    StringBuilder label = new StringBuilder();\n                    \n                    // Some messages from Outlands server are send in sequence of LabelType and RegularType\n                    // so we want to invoke that _onLabelMessage in both cases with delays\n                    MessageManager.GetLabelCommand = true;\n\n                    // Reset the state when script is stopped\n                    _onStop = () =>\n                    {\n                        if (_onLabelMessage != null)\n                        {\n                            MessageManager.OnLabelMessage -= _onLabelMessage;\n                            _onLabelMessage = null;\n                        }\n                        _getLabelState = GetLabelState.None;\n                        \n                        Interpreter.OnStop -= _onStop;\n                        MessageManager.GetLabelCommand = false;\n                    };\n\n                    _onLabelMessage = (p, a, source, graphic, type, hue, font, lang, sourceName, text) =>\n                    {\n                        if (source != serial)\n                            return;\n\n                        a.Block = true;\n\n                        if (_getLabelState == GetLabelState.WaitingForFirstLabel)\n                        {\n                            // After the first message, switch to a pause instead of a timeout.\n                            _getLabelState = GetLabelState.WaitingForRemainingLabels;\n                            Interpreter.Pause(500);\n                        }\n\n                        label.Append(\" \" + text);\n\n                        Interpreter.SetVariable(name, label.ToString().Trim());\n                    };\n\n                    Interpreter.OnStop += _onStop;\n                    MessageManager.OnLabelMessage += _onLabelMessage;\n                    \n                    break;\n                case GetLabelState.WaitingForFirstLabel:\n                    break;\n                case GetLabelState.WaitingForRemainingLabels:\n                    // We get here after the pause has expired.\n                    Interpreter.OnStop -= _onStop;\n                    MessageManager.OnLabelMessage -= _onLabelMessage;\n                    \n                    _onLabelMessage = null;\n                    _getLabelState = GetLabelState.None;\n                    \n                    MessageManager.GetLabelCommand = false;\n                    \n                    return true;\n            }\n\n            return false;\n        }\n\n        private static bool Rename(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 2)\n            {\n                throw new RunTimeError(\"Usage: rename (serial) (new_name)\");\n            }\n\n            string newName = vars[1].AsString();\n            \n            if (newName.Length < 1)\n            {\n                throw new RunTimeError(\"Mobile name must be longer than one character\");\n            }\n\n            if (World.Mobiles.TryGetValue(vars[0].AsSerial(), out var follower))\n            {\n                if (follower.CanRename)\n                {\n                    PlayerData.RenameMobile(follower.Serial, newName);\n                }\n                else\n                {\n                    CommandHelper.SendMessage(\"Unable to rename mobile\", quiet);\n                }\n            }\n            \n            return true;\n        }\n\n        private static bool ClassicUOProfile(string commands, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length != 2)\n            {\n                throw new RunTimeError(\"Usage: cuo (setting) (value)\");\n            }\n\n            string property = ClassicUOManager.IsValidProperty(vars[0].AsString());\n\n            if (string.IsNullOrEmpty(property))\n            {\n                throw new RunTimeError(\"Unknown ClassicUO setting/property. Type `>cuo list` for a list of valid settings.\");\n            }\n\n            bool isNumeric = int.TryParse(vars[0].AsString(), out var value);\n\n            if (isNumeric)\n            {\n                ClassicUOManager.ProfilePropertySet(property, value);\n            }\n            else\n            {\n                switch (vars[1].AsString())\n                {\n                    case \"true\":\n                        ClassicUOManager.ProfilePropertySet(property, true);\n                        break;\n                    case \"false\":\n                        ClassicUOManager.ProfilePropertySet(property, false);\n                        break;\n                    default:\n                        ClassicUOManager.ProfilePropertySet(property, vars[1].AsString());\n                        break;\n                }\n            }\n\n            CommandHelper.SendMessage($\"ClassicUO Setting: '{property}' set to '{vars[1].AsString()}'\", quiet);\n\n            return true;\n        }\n\n        private static bool Sound(string commands, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length != 1)\n            {\n                throw new RunTimeError(\"Usage: sound (serial)\");\n            }\n\n            Client.Instance.SendToClient(new PlaySound(vars[0].AsInt()));\n\n            return true;\n        }\n\n        private static bool Music(string commands, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length != 1)\n            {\n                throw new RunTimeError(\"Usage: music (id)\");\n            }\n\n            Client.Instance.SendToClient(new PlayMusic(vars[0].AsUShort()));\n\n            return true;\n        }\n\n        private static bool AddIgnore(string commands, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length != 1)\n                throw new RunTimeError(\"Usage: ignore (serial)\");\n\n            Variable toIgnore = vars[0];\n            string ignoreListName = vars[0].AsString();\n            \n            if (Interpreter.ListExists(ignoreListName))\n            {\n                List<Serial> list = Interpreter.GetList(ignoreListName).Select(v => (Serial)v.AsSerial()).ToList();\n                Interpreter.AddIgnoreRange(list);\n                CommandHelper.SendMessage($\"Added {list.Count} entries to ignore list\", quiet);\n            }\n            else\n            {\n                uint serial = toIgnore.AsSerial();\n                Interpreter.AddIgnore(serial);\n                CommandHelper.SendMessage($\"Added {serial} to ignore list\", quiet);\n            }\n            \n            return true;\n        }\n        \n        private static bool RemoveIgnore(string commands, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length != 1)\n                throw new RunTimeError(\"Usage: unignore (serial or list)\");\n            \n            Variable toIgnore = vars[0];\n            string ignoreListName = toIgnore.AsString();\n            \n            if (Interpreter.ListExists(ignoreListName))\n            {\n                List<Serial> list = Interpreter.GetList(ignoreListName).Select(v => (Serial)v.AsSerial()).ToList();\n                Interpreter.RemoveIgnoreRange(list);\n                CommandHelper.SendMessage($\"Removed {list.Count} entries from ignore list\", quiet);\n            }\n            else\n            {\n                uint serial = toIgnore.AsSerial();\n                Interpreter.RemoveIgnore(serial);\n                CommandHelper.SendMessage($\"Removed {serial} from ignore list\", quiet);\n            }\n            \n            return true;\n        }\n\n        private static bool ClearIgnore(string commands, Variable[] vars, bool quiet, bool force)\n        {\n            Interpreter.ClearIgnore();\n\n            CommandHelper.SendMessage(\"Ignore List cleared\", quiet);\n\n            return true;\n        }\n\n        private static readonly string[] Virtues = { \"honor\", \"sacrifice\", \"valor\" };\n\n        private static bool Virtue(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0 || !Virtues.Contains(vars[0].AsString()))\n            {\n                throw new RunTimeError(\"Usage: virtue ('honor'/'sacrifice'/'valor')\");\n            }\n\n            switch (vars[0].AsString())\n            {\n                case \"honor\":\n                    PlayerData.InvokeVirtue(PlayerData.InvokeVirtues.Honor);\n                    break;\n                case \"sacrifice\":\n                    PlayerData.InvokeVirtue(PlayerData.InvokeVirtues.Sacrifice);\n                    break;\n                case \"valor\":\n                    PlayerData.InvokeVirtue(PlayerData.InvokeVirtues.Valor);\n                    break;\n            }\n\n            return true;\n        }\n\n        private static bool ClearAll(string command, Variable[] vars, bool quiet, bool force)\n        {\n\n            DragDropManager.GracefulStop(); // clear drag/drop queue\n            Targeting.CancelTarget(); // clear target queue & cancel current target\n            DragDropManager.DropCurrent(); // drop what you are currently holding\n\n            return true;\n        }\n\n        private static bool SetLastTarget(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: setlasttarget ('serial')\");\n            }\n            \n            Serial serial = vars[0].AsSerial();\n\n            if (serial != Serial.Zero)\n            {\n                Mobile mobile = World.FindMobile(serial);\n\n                if (mobile != null)\n                {\n                    Targeting.SetLastTarget(mobile);\n                    return true;\n                }\n                    \n                Item item = World.FindItem(serial);\n\n                if (item != null)\n                {\n                    Targeting.SetLastTarget(item);\n                    return true;\n                }\n\n                Targeting.SetLastTarget(serial);\n            }\n\n            return true;\n        }\n        \n        private enum SetVarState\n        {\n            INITIAL_PROMPT,\n            WAIT_FOR_TARGET,\n            COMPLETE,\n        };\n\n        private static SetVarState _setVarState = SetVarState.INITIAL_PROMPT;\n\n        private static bool SetVar(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1 || vars.Length > 2)\n            {\n                throw new RunTimeError(\"Usage: setvar ('variable') [serial] [timeout]\");\n            }\n\n            string name = vars[0].AsString(false);\n\n            if (vars.Length == 2)\n            {\n                // No need to target anything. We have the serial.\n                var serial = vars[1].AsSerial();\n\n                if (force)\n                {\n                    Interpreter.SetVariable(name, serial.ToString(), true);\n                    return true;\n                }\n\n                if (ScriptVariables.GetVariable(name) == Serial.MinusOne && !quiet)\n                {\n                    CommandHelper.SendMessage($\"'{name}' not found, creating new variable\", quiet);\n                }\n\n                ScriptVariables.RegisterVariable(name, serial);\n                CommandHelper.SendMessage($\"'{name}' script variable updated to '{serial}'\", quiet);\n\n                Assistant.Engine.MainWindow.SaveScriptVariables();\n\n                return true;\n            }\n\n            Interpreter.Timeout(vars.Length == 2 ? vars[1].AsUInt() : 30000, () => { _setVarState = SetVarState.INITIAL_PROMPT; return true; } );\n\n            switch (_setVarState)\n            {\n                case SetVarState.INITIAL_PROMPT:\n                    if (ScriptVariables.GetVariable(name) == Serial.MinusOne)\n                    {\n                        CommandHelper.SendMessage($\"'{name}' not found, creating new variable\", quiet);\n                    }\n                    World.Player.SendMessage(MsgLevel.Force, $\"Select target for variable '{name}'\");\n\n                    _setVarState = SetVarState.WAIT_FOR_TARGET;\n\n                    Targeting.OneTimeTarget((ground, serial, pt, gfx) =>\n                    {\n                        ScriptVariables.RegisterVariable(name, serial);\n                        CommandHelper.SendMessage($\"'{name}' script variable updated to '{serial}'\", quiet);\n\n                        Assistant.Engine.MainWindow.SaveScriptVariables();\n                        _setVarState = SetVarState.COMPLETE;\n                    },\n                    () =>\n                    {\n                        _setVarState = SetVarState.COMPLETE;\n                    });\n                    break;\n                case SetVarState.WAIT_FOR_TARGET:\n                    break;\n                case SetVarState.COMPLETE:\n                    _setVarState = SetVarState.INITIAL_PROMPT;\n                    return true;\n            }\n\n            return false;\n        }\n        \n        private static bool UnsetVar(string expression, Variable[] args, bool quiet, bool force)\n        {\n            if (args.Length != 1)\n                throw new RunTimeError(\"Usage: unsetvar ('name')\");\n\n            var name = args[0].AsString(false);\n\n            if (force)\n            {\n                if (quiet)\n                {\n                    Interpreter.ClearVariable(name);\n                }\n                else\n                {\n                    Interpreter.ClearAlias(name);\n                }\n            }\n            else\n            {\n                ScriptVariables.UnregisterVariable(name);\n                ScriptManager.RedrawScripts();\n            }\n\n            return true;\n        }\n\n\n        private static bool Stop(string command, Variable[] vars, bool quiet, bool force)\n        {\n            ScriptManager.StopScript();\n\n            return true;\n        }\n\n        private static bool Hotkey(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: hotkey ('name of hotkey') OR (hotkeyId)\");\n            }\n\n            string query = vars[0].AsString();\n\n            KeyData hk = HotKey.GetByNameOrId(query);\n\n            if (hk == null)\n            {\n                throw new RunTimeError($\"{command} - Hotkey '{query}' not found\");\n            }\n\n            hk.Callback();\n\n            return true;\n        }\n\n        private static bool WaitForGump(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: waitforgump (gumpId/'any') [timeout]\");\n            }\n\n            uint gumpId = 0;\n            bool strict = false;\n\n            if (vars[0].AsString().IndexOf(\"any\", StringComparison.OrdinalIgnoreCase) != -1)\n            {\n                strict = false;\n            }\n            else\n            {\n                gumpId = Utility.ToUInt32(vars[0].AsString(), 0);\n\n                if (gumpId > 0)\n                {\n                    strict = true;\n                }\n            }\n\n            Interpreter.Timeout(vars.Length == 2 ? vars[1].AsUInt() : 30000, () => { return true; });\n\n            if ((World.Player.HasGump || World.Player.HasCompressedGump) &&\n                (World.Player.CurrentGumpI == gumpId || !strict || gumpId == 0))\n            {\n                Interpreter.ClearTimeout();\n                return true;\n            }\n\n            return false;\n        }\n\n        private static bool WaitForMenu(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: waitformenu (menuId/'any') [timeout]\");\n            }\n\n            uint menuId = 0;\n\n            // Look for a specific menu\n            menuId = vars[0].AsString().IndexOf(\"any\", StringComparison.OrdinalIgnoreCase) != -1\n                ? 0\n                : Utility.ToUInt32(vars[0].AsString(), 0);\n\n            Interpreter.Timeout(vars.Length == 2 ? vars[1].AsUInt() : 30000, () => { return true; });\n\n            if (World.Player.HasMenu && (World.Player.CurrentGumpI == menuId || menuId == 0))\n            {\n                Interpreter.ClearTimeout();\n                return true;\n            }\n\n            return false;\n        }\n\n        private static bool WaitForPrompt(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: waitforprompt (promptId/'any') [timeout]\");\n            }\n\n            uint promptId = 0;\n            bool strict = false;\n\n            // Look for a specific prompt\n            if (vars[0].AsString().IndexOf(\"any\", StringComparison.OrdinalIgnoreCase) != -1)\n            {\n                strict = false;\n            }\n            else\n            {\n                promptId = Utility.ToUInt32(vars[0].AsString(), 0);\n\n                if (promptId > 0)\n                {\n                    strict = true;\n                }\n            }\n\n            Interpreter.Timeout(vars.Length == 2 ? vars[1].AsUInt() : 30000, () => { return true; });\n\n            if (World.Player.HasPrompt && (World.Player.PromptID == promptId || !strict || promptId == 0))\n            {\n                Interpreter.ClearTimeout();\n                return true;\n            }\n\n            return false;\n        }\n\n        private static readonly string[] Abilities = {\"primary\", \"secondary\", \"stun\", \"disarm\"};\n\n        private static bool SetAbility(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1 || !Abilities.Contains(vars[0].AsString()))\n            {\n                throw new RunTimeError(\"Usage: setability ('primary'/'secondary'/'stun'/'disarm') ['on'/'off']\");\n            }\n\n            if (vars.Length == 2 && vars[1].AsString() == \"on\" || vars.Length == 1)\n            {\n                switch (vars[0].AsString())\n                {\n                    case \"primary\":\n                        SpecialMoves.SetPrimaryAbility();\n                        break;\n                    case \"secondary\":\n                        SpecialMoves.SetSecondaryAbility();\n                        break;\n                    case \"stun\":\n                        Client.Instance.SendToServer(new StunRequest());\n                        break;\n                    case \"disarm\":\n                        Client.Instance.SendToServer(new DisarmRequest());\n                        break;\n                }\n            }\n            else if (vars.Length == 2 && vars[1].AsString() == \"off\")\n            {\n                Client.Instance.SendToServer(new UseAbility(AOSAbility.Clear));\n                Client.Instance.SendToClient(ClearAbility.Instance);\n            }\n\n            return true;\n        }\n\n        private static readonly string[] Hands = {\"left\", \"right\", \"both\", \"hands\"};\n\n        private static bool ClearHands(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0 || !Hands.Contains(vars[0].AsString()))\n            {\n                throw new RunTimeError(\"Usage: clearhands ('left'/'right'/'both')\");\n            }\n\n            switch (vars[0].AsString())\n            {\n                case \"left\":\n                    Dress.Unequip(Layer.LeftHand);\n                    break;\n                case \"right\":\n                    Dress.Unequip(Layer.RightHand);\n                    break;\n                default:\n                    Dress.Unequip(Layer.LeftHand);\n                    Dress.Unequip(Layer.RightHand);\n                    break;\n            }\n\n            return true;\n        }\n\n        private static bool DClickType(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: dclicktype ('name of item'/'graphicID') [inrangecheck (true/false)/backpack] [hue]\");\n            }\n\n            string gfxStr = vars[0].AsString();\n            Serial gfx = Utility.ToUInt16(gfxStr, 0);\n            List<Item> items;\n            List<Mobile> mobiles = new List<Mobile>();\n\n            bool inRangeCheck = false;\n            bool backpack = false;\n            int hue = -1;\n\n            if (vars.Length > 1)\n            {\n                if (vars.Length == 3)\n                {\n                    hue = vars[2].AsInt();\n                }\n\n                if (vars[1].AsString().IndexOf(\"pack\", StringComparison.OrdinalIgnoreCase) > 0)\n                {\n                    backpack = true;\n                }\n                else\n                {\n                    inRangeCheck = vars[1].AsBool();\n                }\n            }\n\n            // No graphic id, maybe searching by name?\n            if (gfx == 0)\n            {\n                items = CommandHelper.GetItemsByName(gfxStr, backpack, inRangeCheck, hue);\n\n                if (items.Count == 0) // no item found, search mobile by name\n                {\n                    mobiles = CommandHelper.GetMobilesByName(gfxStr, inRangeCheck);\n                }\n            }\n            else // Provided graphic id for type, check backpack first (same behavior as DoubleClickAction in macros\n            {\n                ushort id = Utility.ToUInt16(gfxStr, 0);\n\n                items = CommandHelper.GetItemsById(id, backpack, inRangeCheck, hue);\n                \n                // Still no item? Mobile check!\n                if (items.Count == 0)\n                {\n                    mobiles = CommandHelper.GetMobilesById(id, inRangeCheck);\n                }\n            }\n\n            if (items.Count > 0)\n            {\n                PlayerData.DoubleClick(items[Utility.Random(items.Count)].Serial);\n            }\n            else if (mobiles.Count > 0)\n            {\n                PlayerData.DoubleClick(mobiles[Utility.Random(mobiles.Count)].Serial);\n            }\n            else\n            {\n                CommandHelper.SendWarning(command, $\"Item or mobile type '{gfxStr}' not found\", quiet);\n            }\n\n            return true;\n        }\n\n        private static bool DClick(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: dclick (serial) or dclick ('left'/'right'/'hands')\");\n            }\n\n            if (Hands.Contains(vars[0].AsString()))\n            {\n                Item item;\n\n                switch (vars[0].AsString())\n                {\n                    case \"left\":\n                        item = World.Player.GetItemOnLayer(Layer.LeftHand);\n                        break;\n                    case \"right\":\n                        item = World.Player.GetItemOnLayer(Layer.RightHand);\n                        break;\n                    default:\n                        item = World.Player.GetItemOnLayer(Layer.RightHand) ?? World.Player.GetItemOnLayer(Layer.LeftHand);\n                        break;\n                }\n\n                if (item != null)\n                {\n                    PlayerData.DoubleClick(item);\n                }\n                else\n                {\n                    CommandHelper.SendWarning(command, $\"Item not found in '{vars[0].AsString()}'\", quiet);\n                }\n            }\n            else\n            {\n                Serial serial = vars[0].AsSerial();\n\n                if (!serial.IsValid)\n                {\n                    throw new RunTimeError(\"dclick - invalid serial\");\n                }\n\n                PlayerData.DoubleClick(serial);\n            }\n\n            return true;\n        }\n\n        private static bool DropItem(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: drop (serial) (x y z/layername)\");\n            }\n\n            Serial serial = vars[0].AsString().IndexOf(\"ground\", StringComparison.OrdinalIgnoreCase) > 0\n                ? uint.MaxValue\n                : vars[0].AsSerial();\n\n            Point3D to = new Point3D(0, 0, 0);\n            Layer layer = Layer.Invalid;\n\n            switch (vars.Length)\n            {\n                case 1: // drop at feet if only serial is provided\n                    to = new Point3D(World.Player.Position.X, World.Player.Position.Y, World.Player.Position.Z);\n                    break;\n                case 2: // dropping on a layer\n                    layer = (Layer) Enum.Parse(typeof(Layer), vars[1].AsString(), true);\n                    break;\n                case 3: // x y\n                    to = new Point3D(Utility.ToInt32(vars[1].AsString(), 0), Utility.ToInt32(vars[2].AsString(), 0), 0);\n                    break;\n                case 4: // x y z\n                    to = new Point3D(Utility.ToInt32(vars[1].AsString(), 0), Utility.ToInt32(vars[2].AsString(), 0),\n                        Utility.ToInt32(vars[3].AsString(), 0));\n                    break;\n            }\n\n            if (DragDropManager.Holding != null)\n            {\n                if (layer > Layer.Invalid && layer <= Layer.LastUserValid)\n                {\n                    Mobile m = World.FindMobile(serial);\n                    if (m != null)\n                        DragDropManager.Drop(DragDropManager.Holding, m, layer);\n                }\n                else\n                {\n                    DragDropManager.Drop(DragDropManager.Holding, serial, to);\n                }\n            }\n            else\n            {\n                CommandHelper.SendWarning(command, \"Not holding anything\", quiet);\n            }\n\n            return true;\n        }\n\n        private static bool DropRelLoc(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 2)\n            {\n                throw new RunTimeError(\"Usage: droprelloc (x) (y)\");\n            }\n\n            int x = vars[0].AsInt();\n            int y = vars[1].AsInt();\n\n            if (DragDropManager.Holding != null)\n            {\n                DragDropManager.Drop(DragDropManager.Holding, null,\n                    new Point3D((ushort) (World.Player.Position.X + x),\n                        (ushort) (World.Player.Position.Y + y), World.Player.Position.Z));\n            }\n            else\n            {\n                CommandHelper.SendWarning(command, \"Not holding anything\", quiet);\n            }\n\n            return true;\n        }\n\n        private static int _lastLiftId;\n\n        private static bool LiftItem(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: lift (serial) [amount] [timeout]\");\n            }\n\n            Serial serial = vars[0].AsSerial();\n\n            if (!serial.IsValid)\n            {\n                throw new RunTimeError($\"{command} - Invalid serial\");\n            }\n\n            ushort amount = 1;\n\n            if (vars.Length == 2)\n            {\n                amount = Utility.ToUInt16(vars[1].AsString(), 1);\n            }\n\n            long timeout = 30000;\n            \n            if (vars.Length == 3)\n            {\n                timeout = Utility.ToLong(vars[2].AsString(), 30000);\n            }\n\n            if (_lastLiftId > 0)\n            {\n                if (DragDropManager.LastIDLifted == _lastLiftId)\n                {\n                    _lastLiftId = 0;\n                    Interpreter.ClearTimeout();\n                    return true;\n                }\n\n                Interpreter.Timeout(timeout, () =>\n                {\n                    _lastLiftId = 0;\n                    return true;\n                });\n            }\n            else\n            {\n                Item item = World.FindItem(serial);\n\n                if (item != null)\n                {\n                    _lastLiftId = DragDropManager.Drag(item, amount <= item.Amount ? amount : item.Amount);\n                }\n                else\n                {\n                    CommandHelper.SendWarning(command, \"Item not found or out of range\", quiet);\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private static int _lastLiftTypeId;\n\n        private static bool LiftType(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: lifttype (gfx/'name of item') [amount] [hue]\");\n            }\n\n            string gfxStr = vars[0].AsString();\n            ushort gfx = Utility.ToUInt16(gfxStr, 0);\n            ushort amount = 1;\n            int hue = -1;\n\n            if (vars.Length > 1)\n            {\n                if (vars.Length >= 2)\n                {\n                    amount = Utility.ToUInt16(vars[1].AsString(), 1);\n                }\n\n                if (vars.Length == 3)\n                {\n                    hue = Utility.ToUInt16(vars[2].AsString(), 0);\n                }\n            }\n\n            if (_lastLiftTypeId > 0)\n            {\n                if (DragDropManager.LastIDLifted == _lastLiftTypeId)\n                {\n                    _lastLiftTypeId = 0;\n                    Interpreter.ClearTimeout();\n                    return true;\n                }\n\n                Interpreter.Timeout(30000, () =>\n                {\n                    _lastLiftTypeId = 0;\n                    return true;\n                });\n            }\n            else\n            {\n                List<Item> items = new List<Item>();\n\n                // No graphic id, maybe searching by name?\n                if (gfx == 0)\n                {\n                    items = World.Player.Backpack.FindItemsByName(gfxStr, true);\n\n                    if (items.Count == 0)\n                    {\n                        CommandHelper.SendWarning(command, $\"Item '{gfxStr}' not found\", quiet);\n                        return true;\n                    }\n                }\n                else\n                {\n                    items = World.Player.Backpack.FindItemsById(gfx);\n                }\n\n                if (hue > -1)\n                {\n                    items.RemoveAll(item => item.Hue != hue);\n                }\n\n                if (items.Count > 0)\n                {\n                    Item item = items[Utility.Random(items.Count)];\n\n                    if (item.Amount < amount)\n                        amount = item.Amount;\n\n                    _lastLiftTypeId = DragDropManager.Drag(item, amount);\n                }\n                else\n                {\n                    CommandHelper.SendWarning(command, Language.Format(LocString.NoItemOfType, (ItemID)gfx), quiet);\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private static bool Walk(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: walk ('direction')\");\n            }\n\n            if (ScriptManager.LastWalk + TimeSpan.FromSeconds(0.4) >= DateTime.UtcNow)\n            {\n                return false;\n            }\n\n            ScriptManager.LastWalk = DateTime.UtcNow;\n\n            Direction dir = (Direction) Enum.Parse(typeof(Direction), vars[0].AsString(), true);\n            Client.Instance.RequestMove(dir);\n\n            return true;\n        }\n\n        private static bool UseSkill(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: skill ('skill name'/'last')\");\n            }\n\n            int skillId = 0;\n\n            if (World.Player.LastSkill != -1)\n            {\n                skillId = World.Player.LastSkill;\n            }\n\n            if (vars[0].AsString() == \"last\")\n            {\n                Client.Instance.SendToServer(new UseSkill(World.Player.LastSkill));\n            }\n            else if (Skills.SkillsByName.TryGetValue(vars[0].AsString(), out SkillInfo skill))\n            {\n                if (skill.IsAction)\n                {\n                    Client.Instance.SendToServer(new UseSkill(skill.Index));\n\n                    World.Player.LastSkill = skill.Index;\n                }\n                else\n                {\n                    CommandHelper.SendWarning(command, $\"Skill '{vars[0].AsString()}' is not usable. Available usable skills: {string.Join(\", \", Skills.GetUsableSkillNames())}\", quiet);\n                }\n            }\n            else\n            {\n                CommandHelper.SendWarning(command, $\"Skill '{vars[0].AsString()}' not found. Available usable skills: {string.Join(\", \", Skills.GetUsableSkillNames())}\", quiet);\n            }\n\n            if (skillId == Skills.StealthIndex && !World.Player.Visible)\n            {\n                StealthSteps.Hide();\n            }\n\n            return true;\n        }\n        \n        private static bool Pause(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n                throw new RunTimeError(\"Usage: wait (timeout) [shorthand]\");\n\n            uint timeout = vars[0].AsUInt();\n\n            if (vars.Length == 2)\n            {\n                switch (vars[1].AsString())\n                {\n                    case \"s\":\n                    case \"sec\":\n                    case \"secs\":\n                    case \"second\":\n                    case \"seconds\":\n                        timeout *= 1000;\n                        break;\n                    case \"m\":\n                    case \"min\":\n                    case \"mins\":\n                    case \"minute\":\n                    case \"minutes\":\n                        timeout *= 60000;\n                        break;\n                }\n            }\n\n            Interpreter.Pause(timeout);\n\n            return true;\n        }\n\n        private static bool Attack(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: attack (serial)\");\n            }\n\n            Serial serial = vars[0].AsSerial();\n\n            if (!serial.IsValid)\n            {\n                throw new RunTimeError($\"{command} - Invalid serial\");\n            }\n\n            if (serial == Targeting.LastTargetInfo.Serial)\n            {\n                Targeting.AttackLastTarg();\n            }\n            else\n            {\n                if (serial.IsMobile)\n                    Client.Instance.SendToServer(new AttackReq(serial));\n            }\n\n            return true;\n        }\n\n        private static bool Cast(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: cast 'name of spell'\");\n            }\n\n            Spell spell = int.TryParse(vars[0].AsString(), out int spellnum)\n                ? Spell.Get(spellnum)\n                : Spell.GetByName(vars[0].AsString());\n\n            if (spell != null)\n            {\n                spell.OnCast(new CastSpellFromMacro((ushort) spell.GetID()));\n            }\n            else\n            {\n                throw new RunTimeError($\"{command} - Spell name or number not valid\");\n            }\n\n            return true;\n        }\n\n        private static bool OverheadMessage(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: overhead ('text') [color] [serial]\");\n            }\n            \n            string overheadMessage = vars[0].AsString();\n            overheadMessage = CommandHelper.ReplaceStringInterpolations(overheadMessage);\n\n            if (vars.Length == 1)\n            {\n                World.Player.OverheadMessage(Config.GetInt(\"SysColor\"), overheadMessage);\n            }\n            else if (vars.Length == 2)\n            {\n                int hue = Utility.ToInt32(vars[1].AsString(), 0);\n\n                if (vars.Length == 3)\n                {\n                    uint serial = vars[2].AsSerial();\n\n                    Mobile m = World.FindMobile(serial);\n                    m?.OverheadMessage(hue, overheadMessage);\n                }\n                else\n                {\n                    World.Player.OverheadMessage(hue, overheadMessage);\n                }\n            }\n\n            return true;\n        }\n\n        private static bool SystemMessage(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: sysmsg ('text') [color]\");\n            }\n            \n            var sysMessage = vars[0].AsString();\n            sysMessage = CommandHelper.ReplaceStringInterpolations(sysMessage);\n\n            if (vars.Length == 1)\n            {\n                World.Player.SendMessage(Config.GetInt(\"SysColor\"), sysMessage);\n            }\n            else if (vars.Length == 2)\n            {\n                World.Player.SendMessage(Utility.ToInt32(vars[1].AsString(), 0), sysMessage);\n            }\n\n            return true;\n        }\n\n        private static bool ClearSysMsg(string command, Variable[] vars, bool quiet, bool force)\n        {\n            SystemMessages.Messages.Clear();\n\n            return true;\n        }\n\n        private static DressList _lastDressList;\n\n        private static bool DressCommand(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: dress ('name of dress list')\");\n            }\n\n            if (_lastDressList == null)\n            {\n                _lastDressList = DressList.Find(vars[0].AsString());\n                \n                if (_lastDressList != null)\n                {\n                    _lastDressList.Dress();\n                }\n                else\n                {\n                    Serial serial = vars[0].AsSerial();\n                    Item item = World.FindItem(serial);\n\n                    if (item != null)\n                    {\n                        DressList dressList = new DressList(\"temp\");\n                        dressList.Items.Add(serial);\n                        dressList.Dress();\n\n                        _lastDressList = dressList;\n                    }\n                    else\n                    {\n                        CommandHelper.SendWarning(command, $\"'{vars[0].AsString()}' not found\", quiet);\n                        return true;\n                    }\n                }\n            }\n            else if (ActionQueue.Empty)\n            {\n                _lastDressList = null;\n                return true;\n            }\n\n            return false;\n        }\n\n        private static DressList _lastUndressList;\n        private static bool _undressAll;\n        private static bool _undressLayer;\n\n        private static bool UnDressCommand(string command, Variable[] vars, bool quiet, bool force)\n        {\n\n            if (vars.Length == 0 && !_undressAll) // full naked!\n            {\n                _undressAll = true;\n                UndressHotKeys.OnUndressAll();\n            }\n            else if (vars.Length == 1 && _lastUndressList == null && !_undressLayer) // either a dress list item or a layer\n            {\n                _lastUndressList = DressList.Find(vars[0].AsString());\n\n                if (_lastUndressList != null)\n                {\n                    _lastUndressList.Undress();\n                }\n                else // lets find the layer\n                {\n                    if (Enum.TryParse(vars[0].AsString(), true, out Layer layer))\n                    {\n                        Dress.Unequip(layer);\n                        _undressLayer = true;\n                    }\n                    else\n                    {\n                        Serial serial = vars[0].AsSerial();\n                        Item item = World.FindItem(serial);\n\n                        if (item != null)\n                        {\n                            DressList undressList = new DressList(\"temp\");\n                            undressList.Items.Add(serial);\n                            undressList.Undress();\n\n                            _lastUndressList = undressList;\n                        }\n                        else\n                        {\n                            CommandHelper.SendWarning(command, $\"'{vars[0].AsString()}' not found\", quiet);\n                            return true;\n                        }\n                    }\n                }\n            }\n            else if (ActionQueue.Empty)\n            {\n                _undressAll = false;\n                _undressLayer = false;\n                _lastUndressList = null;\n                return true;\n            }\n\n            return false;\n        }\n\n        private static bool GumpResponse(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: gumpresponse (buttondId)\");\n                //throw new RunTimeError(\"Usage: gumpresponse (buttondId) [option] ['text1'|fieldId] ['text2'|fieldId]\");\n            }\n\n            int buttonId = vars[0].AsInt();\n\n            /*private int m_ButtonID;\n                    private int[] m_Switches;\n                    private GumpTextEntry[] m_TextEntries;*/\n\n            //Assistant.Macros.GumpResponseAction|9|0|0\n            //Assistant.Macros.GumpResponseAction|1|0|1|0&Hello How are you?\n            //Assistant.Macros.GumpResponseAction|501|0|2|1&box2|0&box1\n\n            Client.Instance.SendToClient(new CloseGump(World.Player.CurrentGumpI));\n            Client.Instance.SendToServer(new GumpResponse(World.Player.CurrentGumpS, World.Player.CurrentGumpI,\n                buttonId, new int[] { }, new GumpTextEntry[] { }));\n\n            World.Player.HasGump = false;\n            World.Player.HasCompressedGump = false;\n\n            return true;\n        }\n\n        private static bool GumpClose(string command, Variable[] vars, bool quiet, bool force)\n        {\n            uint gumpI = World.Player.CurrentGumpI;\n\n            if (vars.Length > 0)\n            {\n                gumpI = vars[0].AsUInt();\n            }\n\n            if (!World.Player.GumpList.ContainsKey(gumpI))\n            {\n                CommandHelper.SendWarning(command, $\"'{gumpI}' unknown gump id\", quiet);\n                return true;\n            }\n\n            uint gumpS = World.Player.GumpList[gumpI].GumpSerial;\n\n            Client.Instance.SendToClient(new CloseGump(gumpI));\n            Client.Instance.SendToServer(new GumpResponse(gumpS, gumpI, 0, new int[] { }, new GumpTextEntry[] { }));\n\n            World.Player.HasGump = false;\n            World.Player.HasCompressedGump = false;\n\n            return true;\n        }\n\n        private static bool ContextMenu(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 2)\n            {\n                throw new RunTimeError(\"Usage: menu (serial) (index)\");\n            }\n\n            Serial s = vars[0].AsSerial();\n            ushort index = vars[1].AsUShort();\n            bool blockPopup = true;\n\n            if (vars.Length > 2)\n            {\n                blockPopup = vars[2].AsBool();\n            }\n\n            if (s == Serial.Zero && World.Player != null)\n                s = World.Player.Serial;\n            \n            ScriptManager.BlockPopupMenu = blockPopup;\n\n            Client.Instance.SendToServer(new ContextMenuRequest(s));\n            Client.Instance.SendToServer(new ContextMenuResponse(s, index));\n            return true;\n        }\n\n        private static bool MenuResponse(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 2)\n            {\n                throw new RunTimeError(\"Usage: menuresponse (index) (menuId) [hue]\");\n            }\n\n            ushort index = vars[0].AsUShort();\n            ushort menuId = vars[1].AsUShort();\n            ushort hue = 0;\n\n            if (vars.Length == 3)\n                hue = vars[2].AsUShort();\n\n            Client.Instance.SendToServer(new MenuResponse(World.Player.CurrentMenuS, World.Player.CurrentMenuI, index,\n                menuId, hue));\n            World.Player.HasMenu = false;\n            return true;\n        }\n\n        private static bool PromptResponse(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: promptresponse ('response to the prompt')\");\n            }\n\n            World.Player.ResponsePrompt(vars[0].AsString());\n            return true;\n        }\n\n        private static bool LastTarget(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (!Targeting.DoLastTarget())\n                Targeting.ResendTarget();\n\n            return true;\n        }\n\n        private static bool PlayScript(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: script 'name of script'\");\n            }\n\n            ScriptManager.PlayScript(vars[0].AsString());\n\n            return true;\n        }\n\n        private static readonly Dictionary<string, ushort> PotionList = new Dictionary<string, ushort>()\n        {\n            {\"heal\", 3852},\n            {\"cure\", 3847},\n            {\"refresh\", 3851},\n            {\"nightsight\", 3846},\n            {\"ns\", 3846},\n            {\"explosion\", 3853},\n            {\"strength\", 3849},\n            {\"str\", 3849},\n            {\"agility\", 3848}\n        };\n\n        private static bool Potion(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: potion ('type')\");\n            }\n\n            Item pack = World.Player.Backpack;\n            if (pack == null)\n                return true;\n\n            if (PotionList.TryGetValue(vars[0].AsString().ToLower(), out ushort potionId))\n            {\n                if (potionId == 3852 && World.Player.Poisoned && Config.GetBool(\"BlockHealPoison\") &&\n                    Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\n                {\n                    World.Player.SendMessage(MsgLevel.Force, LocString.HealPoisonBlocked);\n                    return true;\n                }\n\n                if (!World.Player.UseItem(pack, potionId))\n                {\n                    CommandHelper.SendWarning(command, Language.Format(LocString.NoItemOfType, (ItemID)potionId), quiet);\n                }\n            }\n            else\n            {\n                throw new RunTimeError($\"{command} - Unknown potion type\");\n            }\n\n            return true;\n        }\n\n        private static bool WaitForSysMsg(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: waitforsysmsg 'message to wait for' [timeout]\");\n            }\n            \n            if (SystemMessages.Exists(vars[0].AsString()))\n            {\n                Interpreter.ClearTimeout();\n                return true;\n            }\n\n            Interpreter.Timeout(vars.Length > 1 ? vars[1].AsUInt() : 30000, () => { return true; });\n\n            return false;\n        }\n\n        private static bool Random(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: random 'max value'\");\n            }\n\n            int max = vars[0].AsInt();\n\n            World.Player.SendMessage(MsgLevel.Info, $\"Random: {Utility.Random(1, max)}\");\n\n            return true;\n        }\n\n        private static bool ClearDragDrop(string command, Variable[] vars, bool quiet, bool force)\n        {\n            DragDropManager.GracefulStop();\n\n            return true;\n        }\n        \n        private static bool Interrupt(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 1)\n            {\n                Layer layer = (Layer) Enum.Parse(typeof(Layer), vars[0].AsString(), true);\n\n                if (layer > Layer.Invalid && layer <= Layer.LastUserValid)\n                {\n                    Spell.Interrupt(layer);\n                }\n                else\n                {\n                    throw new RunTimeError($\"{command} - Invalid layer\");\n                }\n            }\n            else\n            {\n                Spell.Interrupt();    \n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Scripts/Engine/Interpreter.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Globalization;\n\nnamespace Assistant.Scripts.Engine\n{\n    public class RunTimeError : Exception\n    {\n        public RunTimeError(string error) : base(error)\n        {\n        }\n    }\n\n    internal static class TypeConverter\n    {\n        public static int ToInt(string token)\n        {\n            int val;\n\n            if (token.StartsWith(\"0x\"))\n            {\n                if (int.TryParse(token.Substring(2), NumberStyles.HexNumber, Interpreter.Culture, out val))\n                    return val;\n            }\n            else if (int.TryParse(token, out val))\n                return val;\n\n            throw new RunTimeError(\"Cannot convert argument to int\");\n        }\n\n        public static uint ToUInt(string token)\n        {\n            uint val;\n\n            if (token.StartsWith(\"0x\"))\n            {\n                if (uint.TryParse(token.Substring(2), NumberStyles.HexNumber, Interpreter.Culture, out val))\n                    return val;\n            }\n            else if (uint.TryParse(token, out val))\n                return val;\n\n            throw new RunTimeError(\"Cannot convert argument to uint\");\n        }\n\n        public static ushort ToUShort(string token)\n        {\n            ushort val;\n\n            if (token.StartsWith(\"0x\"))\n            {\n                if (ushort.TryParse(token.Substring(2), NumberStyles.HexNumber, Interpreter.Culture, out val))\n                    return val;\n            }\n            else if (ushort.TryParse(token, out val))\n                return val;\n\n            throw new RunTimeError(\"Cannot convert argument to ushort\");\n        }\n\n        public static double ToDouble(string token)\n        {\n            double val;\n\n            if (double.TryParse(token, out val))\n                return val;\n\n            throw new RunTimeError(\"Cannot convert argument to double\");\n        }\n\n        public static bool ToBool(string token)\n        {\n            bool val;\n\n            if (bool.TryParse(token, out val))\n                return val;\n\n            throw new RunTimeError(\"Cannot convert argument to bool\");\n        }\n    }\n\n    internal class Scope\n    {\n        private Dictionary<string, Variable> _namespace = new Dictionary<string, Variable>();\n        private readonly HashSet<Serial> _ignoreList = new HashSet<Serial>();\n\n        public readonly ASTNode StartNode;\n        public readonly Scope Parent;\n\n        public Scope(Scope parent, ASTNode start)\n        {\n            Parent = parent;\n            StartNode = start;\n        }\n\n        public Variable GetVariable(string name)\n        {\n            Variable arg;\n\n            if (_namespace.TryGetValue(name, out arg))\n                return arg;\n\n            return null;\n        }\n\n        public void SetVariable(string name, Variable val)\n        {\n            _namespace[name] = val;\n        }\n\n        public void ClearVariable(string name)\n        {\n            _namespace.Remove(name);\n        }\n\n        public bool ExistVariable(string name)\n        {\n            return _namespace.ContainsKey(name);\n        }\n\n        public void AddIgnore(Serial serial)\n        {\n            _ignoreList.Add(serial);\n        }\n\n        public void AddIgnoreRange(List<Serial> serials)\n        {\n            serials.ForEach(AddIgnore);\n        }\n        public void RemoveIgnore(Serial serial)\n        {\n            if (_ignoreList.Contains(serial))\n                _ignoreList.Remove(serial);\n        }\n\n        public void RemoveIgnoreRange(List<Serial> serials)\n        {\n            _ignoreList.RemoveWhere(serials.Contains);\n        }\n\n        public void ClearIgnore()\n        {\n            _ignoreList.Clear();\n        }\n\n        public bool CheckIgnored(Serial serial)\n        {\n            return _ignoreList.Contains(serial);\n        }\n\n    }\n\n    public class Variable\n    {\n        private string _value;\n\n        public Variable(string value)\n        {\n            _value = value;\n        }\n\n        // Treat the argument as an integer\n        public int AsInt()\n        {\n            if (_value == null)\n                throw new RunTimeError(\"Cannot convert argument to int\");\n\n            // Try to resolve it as a scoped variable first\n            var arg = Interpreter.GetVariable(_value);\n            if (arg != null)\n                return arg.AsInt();\n\n            return TypeConverter.ToInt(_value);\n        }\n\n        // Treat the argument as an unsigned integer\n        public uint AsUInt()\n        {\n            if (_value == null)\n                throw new RunTimeError(\"Cannot convert argument to uint\");\n\n            // Try to resolve it as a scoped variable first\n            var arg = Interpreter.GetVariable(_value);\n            if (arg != null)\n                return arg.AsUInt();\n\n            return TypeConverter.ToUInt(_value);\n        }\n\n        public ushort AsUShort()\n        {\n            if (_value == null)\n                throw new RunTimeError(\"Cannot convert argument to ushort\");\n\n            // Try to resolve it as a scoped variable first\n            var arg = Interpreter.GetVariable(_value);\n            if (arg != null)\n                return arg.AsUShort();\n\n            return TypeConverter.ToUShort(_value);\n        }\n\n        // Treat the argument as a serial or an alias. Aliases will\n        // be automatically resolved to serial numbers.\n        public uint AsSerial()\n        {\n            if (_value == null)\n                throw new RunTimeError(\"Cannot convert argument to serial\");\n\n            // Try to resolve it as a scoped variable first\n            var arg = Interpreter.GetVariable(_value);\n            if (arg != null)\n                return arg.AsSerial();\n\n            // Resolve it as a global alias next\n            uint serial = Interpreter.GetAlias(_value);\n            if (serial != uint.MaxValue)\n                return serial;\n\n            try\n            {\n                return AsUInt();\n            }\n            catch (RunTimeError)\n            { }\n\n            return Serial.MinusOne;\n        }\n\n        // Treat the argument as a string\n        public string AsString(bool resolve = true)\n        {\n            if (_value == null)\n                throw new RunTimeError(\"Cannot convert argument to string\");\n\n            if (resolve)\n            {\n                // Try to resolve it as a scoped variable first\n                var arg = Interpreter.GetVariable(_value);\n                if (arg != null)\n                    return arg.AsString();\n            }\n\n            return _value;\n        }\n\n        public bool AsBool()\n        {\n            if (_value == null)\n                throw new RunTimeError(\"Cannot convert argument to bool\");\n\n            return TypeConverter.ToBool(_value);\n        }\n\n        public override bool Equals(object obj)\n        {\n            if (obj == null)\n                return false;\n\n            Variable arg = obj as Variable;\n\n            if (arg == null)\n                return false;\n\n            return Equals(arg);\n        }\n\n        public bool Equals(Variable other)\n        {\n            if (other == null)\n                return false;\n\n            return (other._value == _value);\n        }\n    }\n\n    public class Script\n    {\n        private ASTNode _statement;\n\n        public int CurrentLine\n        {\n            get\n            {\n                return _statement == null ? 0 : _statement.LineNumber;\n            }\n        }\n\n        private Variable[] ConstructArguments(ref ASTNode node)\n        {\n            List<Variable> args = new List<Variable>();\n\n            node = node.Next();\n\n            while (node != null)\n            {\n                switch (node.Type)\n                {\n                    case ASTNodeType.AND:\n                    case ASTNodeType.OR:\n                    case ASTNodeType.EQUAL:\n                    case ASTNodeType.NOT_EQUAL:\n                    case ASTNodeType.LESS_THAN:\n                    case ASTNodeType.LESS_THAN_OR_EQUAL:\n                    case ASTNodeType.GREATER_THAN:\n                    case ASTNodeType.GREATER_THAN_OR_EQUAL:\n                    case ASTNodeType.IN:\n                    case ASTNodeType.AS:\n                        return args.ToArray();\n                }\n\n                args.Add(new Variable(node.Lexeme));\n\n                node = node.Next();\n            }\n\n            return args.ToArray();\n        }\n\n        // For now, the scripts execute directly from the\n        // abstract syntax tree. This is relatively simple.\n        // A more robust approach would be to \"compile\" the\n        // scripts to a bytecode. That would allow more errors\n        // to be caught with better error messages, as well as\n        // make the scripts execute more quickly.\n        public Script(ASTNode root)\n        {\n            // Set current to the first statement\n            _statement = root.FirstChild();\n        }\n\n        public void Initialize()\n        {\n            Interpreter.PushScope(_statement);\n        }\n\n        public bool ExecuteNext()\n        {\n            if (_statement == null)\n                return false;\n\n            if (_statement.Type != ASTNodeType.STATEMENT)\n                throw new RunTimeError(\"Invalid script\");\n\n            var node = _statement.FirstChild();\n\n            if (node == null)\n                throw new RunTimeError(\"Invalid statement\");\n\n            int depth = 0;\n\n            switch (node.Type)\n            {\n                case ASTNodeType.IF:\n                    {\n                        Interpreter.PushScope(node);\n\n                        var expr = node.FirstChild();\n                        var result = EvaluateExpression(ref expr);\n\n                        // Advance to next statement\n                        Advance();\n\n                        // Evaluated true. Jump right into execution.\n                        if (result)\n                            break;\n\n                        // The expression evaluated false, so keep advancing until\n                        // we hit an elseif, else, or endif statement that matches\n                        // and try again.\n                        depth = 0;\n\n                        while (_statement != null)\n                        {\n                            node = _statement.FirstChild();\n\n                            if (node.Type == ASTNodeType.IF)\n                            {\n                                depth++;\n                            }\n                            else if (node.Type == ASTNodeType.ELSEIF)\n                            {\n                                if (depth == 0)\n                                {\n                                    expr = node.FirstChild();\n                                    result = EvaluateExpression(ref expr);\n\n                                    // Evaluated true. Jump right into execution\n                                    if (result)\n                                    {\n                                        Advance();\n                                        break;\n                                    }\n                                }\n                            }\n                            else if (node.Type == ASTNodeType.ELSE)\n                            {\n                                if (depth == 0)\n                                {\n                                    // Jump into the else clause\n                                    Advance();\n                                    break;\n                                }\n                            }\n                            else if (node.Type == ASTNodeType.ENDIF)\n                            {\n                                if (depth == 0)\n                                    break;\n\n                                depth--;\n                            }\n\n                            Advance();\n                        }\n\n                        if (_statement == null)\n                            throw new RunTimeError(\"If with no matching endif\");\n\n                        break;\n                    }\n                case ASTNodeType.ELSEIF:\n                    // If we hit the elseif statement during normal advancing, skip over it. The only way\n                    // to execute an elseif clause is to jump directly in from an if statement.\n                    depth = 0;\n\n                    while (_statement != null)\n                    {\n                        node = _statement.FirstChild();\n\n                        if (node.Type == ASTNodeType.IF)\n                        {\n                            depth++;\n                        }\n                        else if (node.Type == ASTNodeType.ENDIF)\n                        {\n                            if (depth == 0)\n                                break;\n\n                            depth--;\n                        }\n\n                        Advance();\n                    }\n\n                    if (_statement == null)\n                        throw new RunTimeError(\"If with no matching endif\");\n\n                    break;\n                case ASTNodeType.ENDIF:\n                    Interpreter.PopScope();\n                    Advance();\n                    break;\n                case ASTNodeType.ELSE:\n                    // If we hit the else statement during normal advancing, skip over it. The only way\n                    // to execute an else clause is to jump directly in from an if statement.\n                    depth = 0;\n\n                    while (_statement != null)\n                    {\n                        node = _statement.FirstChild();\n\n                        if (node.Type == ASTNodeType.IF)\n                        {\n                            depth++;\n                        }\n                        else if (node.Type == ASTNodeType.ENDIF)\n                        {\n                            if (depth == 0)\n                                break;\n\n                            depth--;\n                        }\n\n                        Advance();\n                    }\n\n                    if (_statement == null)\n                        throw new RunTimeError(\"If with no matching endif\");\n\n                    break;\n                case ASTNodeType.WHILE:\n                    {\n                        // The iterator variable's name is the hash code of the for loop's ASTNode.\n                        var iterName = node.GetHashCode().ToString();\n\n                        // When we first enter the loop, push a new scope\n                        if (Interpreter.CurrentScope.StartNode != node)\n                        {\n                            Interpreter.PushScope(node);\n                            Interpreter.SetVariable(iterName, \"0\");\n                            Interpreter.SetVariable(\"index\", \"0\");\n                        }\n                        else\n                        {\n                            // Increment the iterator argument\n                            var arg = Interpreter.GetVariable(iterName);\n                            var index = arg.AsUInt() + 1;\n                            Interpreter.SetVariable(iterName, index.ToString());\n                            Interpreter.SetVariable(\"index\", index.ToString());\n                        }\n\n                        var expr = node.FirstChild();\n                        var result = EvaluateExpression(ref expr);\n\n                        // Advance to next statement\n                        Advance();\n\n                        // The expression evaluated false, so keep advancing until\n                        // we hit an endwhile statement.\n                        if (!result)\n                        {\n                            depth = 0;\n\n                            while (_statement != null)\n                            {\n                                node = _statement.FirstChild();\n\n                                if (node.Type == ASTNodeType.WHILE)\n                                {\n                                    depth++;\n                                }\n                                else if (node.Type == ASTNodeType.ENDWHILE)\n                                {\n                                    if (depth == 0)\n                                    {\n                                        Interpreter.PopScope();\n                                        // Go one past the endwhile so the loop doesn't repeat\n                                        Advance();\n                                        break;\n                                    }\n\n                                    depth--;\n                                }\n\n                                Advance();\n                            }\n                        }\n                        break;\n                    }\n                case ASTNodeType.ENDWHILE:\n                    // Walk backward to the while statement\n                    _statement = _statement.Prev();\n\n                    depth = 0;\n\n                    while (_statement != null)\n                    {\n                        node = _statement.FirstChild();\n\n                        if (node.Type == ASTNodeType.ENDWHILE)\n                        {\n                            depth++;\n                        }\n                        else if (node.Type == ASTNodeType.WHILE)\n                        {\n                            if (depth == 0)\n                                break;\n\n                            depth--;\n                        }\n\n                        _statement = _statement.Prev();\n                    }\n\n                    if (_statement == null)\n                        throw new RunTimeError(\"Unexpected endwhile\");\n\n                    break;\n                case ASTNodeType.FOR:\n                    {\n                        // The iterator variable's name is the hash code of the for loop's ASTNode.\n                        var iterName = node.GetHashCode().ToString();\n\n                        // When we first enter the loop, push a new scope\n                        if (Interpreter.CurrentScope.StartNode != node)\n                        {\n                            Interpreter.PushScope(node);\n\n                            // Grab the arguments\n                            var max = node.FirstChild();\n\n                            if (max.Type != ASTNodeType.INTEGER)\n                                throw new RunTimeError(\"Invalid for loop syntax\");\n\n                            // Create a dummy argument that acts as our loop variable\n                            Interpreter.SetVariable(iterName, \"0\");\n                            Interpreter.SetVariable(\"index\", \"0\");\n                        }\n                        else\n                        {\n                            // Increment the iterator argument\n                            var arg = Interpreter.GetVariable(iterName);\n                            var index = arg.AsUInt() + 1;\n                            Interpreter.SetVariable(iterName, index.ToString());\n                            Interpreter.SetVariable(\"index\", index.ToString());\n                        }\n\n                        // Check loop condition\n                        var i = Interpreter.GetVariable(iterName);\n\n                        // Grab the max value to iterate to\n                        node = node.FirstChild();\n                        var end = new Variable(node.Lexeme);\n\n                        if (i.AsUInt() < end.AsUInt())\n                        {\n                            // enter the loop\n                            Advance();\n                        }\n                        else\n                        {\n                            // Walk until the end of the loop\n                            Advance();\n\n                            depth = 0;\n\n                            while (_statement != null)\n                            {\n                                node = _statement.FirstChild();\n\n                                if (node.Type == ASTNodeType.FOR || node.Type == ASTNodeType.FOREACH)\n                                {\n                                    depth++;\n                                }\n                                else if (node.Type == ASTNodeType.ENDFOR)\n                                {\n                                    if (depth == 0)\n                                    {\n                                        Interpreter.PopScope();\n                                        // Go one past the end so the loop doesn't repeat\n                                        Advance();\n                                        break;\n                                    }\n\n                                    depth--;\n                                }\n\n                                Advance();\n                            }\n                        }\n                    }\n                    break;\n                case ASTNodeType.FOREACH:\n                    {\n                        // foreach VAR in LIST\n                        // The iterator's name is the hash code of the for loop's ASTNode.\n                        var varName = node.FirstChild().Lexeme;\n                        var listName = node.FirstChild().Next().Lexeme;\n                        var iterName = node.GetHashCode().ToString();\n\n                        // When we first enter the loop, push a new scope\n                        if (Interpreter.CurrentScope.StartNode != node)\n                        {\n                            Interpreter.PushScope(node);\n\n                            // Create a dummy argument that acts as our iterator object\n                            Interpreter.SetVariable(iterName, \"0\");\n                            Interpreter.SetVariable(\"index\", \"0\");\n\n                            // Make the user-chosen variable have the value for the front of the list\n                            var arg = Interpreter.GetListValue(listName, 0);\n\n                            if (arg != null)\n                                Interpreter.SetVariable(varName, arg.AsString());\n                            else\n                                Interpreter.ClearVariable(varName);\n                        }\n                        else\n                        {\n                            // Increment the iterator argument\n                            var idx = Interpreter.GetVariable(iterName).AsInt() + 1;\n                            Interpreter.SetVariable(iterName, idx.ToString()); ;\n                            Interpreter.SetVariable(\"index\", idx.ToString());\n\n                            // Update the user-chosen variable\n                            var arg = Interpreter.GetListValue(listName, idx);\n\n                            if (arg != null)\n                                Interpreter.SetVariable(varName, arg.AsString());\n                            else\n                                Interpreter.ClearVariable(varName);\n                        }\n\n                        // Check loop condition\n                        var i = Interpreter.GetVariable(varName);\n\n                        if (i != null)\n                        {\n                            // enter the loop\n                            Advance();\n                        }\n                        else\n                        {\n                            // Walk until the end of the loop\n                            Advance();\n\n                            depth = 0;\n\n                            while (_statement != null)\n                            {\n                                node = _statement.FirstChild();\n\n                                if (node.Type == ASTNodeType.FOR ||\n                                    node.Type == ASTNodeType.FOREACH)\n                                {\n                                    depth++;\n                                }\n                                else if (node.Type == ASTNodeType.ENDFOR)\n                                {\n                                    if (depth == 0)\n                                    {\n                                        Interpreter.PopScope();\n                                        // Go one past the end so the loop doesn't repeat\n                                        Advance();\n                                        break;\n                                    }\n\n                                    depth--;\n                                }\n\n                                Advance();\n                            }\n                        }\n                        break;\n                    }\n                case ASTNodeType.ENDFOR:\n                    // Walk backward to the for statement\n                    _statement = _statement.Prev();\n\n                    // track depth in case there is a nested for\n                    depth = 0;\n\n                    while (_statement != null)\n                    {\n                        node = _statement.FirstChild();\n\n                        if (node.Type == ASTNodeType.ENDFOR)\n                        {\n                            depth++;\n                        }\n                        else if (node.Type == ASTNodeType.FOR ||\n                                 node.Type == ASTNodeType.FOREACH)\n                        {\n                            if (depth == 0)\n                            {\n                                break;\n                            }\n                            depth--;\n                        }\n\n                        _statement = _statement.Prev();\n                    }\n\n                    if (_statement == null)\n                        throw new RunTimeError(\"Unexpected endfor\");\n\n                    break;\n                case ASTNodeType.BREAK:\n                    // Walk until the end of the loop\n                    Advance();\n\n                    depth = 0;\n\n                    while (_statement != null)\n                    {\n                        node = _statement.FirstChild();\n\n                        if (node.Type == ASTNodeType.WHILE ||\n                            node.Type == ASTNodeType.FOR ||\n                            node.Type == ASTNodeType.FOREACH)\n                        {\n                            depth++;\n                        }\n                        else if (node.Type == ASTNodeType.ENDWHILE ||\n                            node.Type == ASTNodeType.ENDFOR)\n                        {\n                            if (depth == 0)\n                            {\n                                // Go one past the end so the loop doesn't repeat\n                                Advance();\n                                break;\n                            }\n\n                            depth--;\n                        }\n\n                        Advance();\n                    }\n\n                    Interpreter.PopScope();\n                    break;\n                case ASTNodeType.CONTINUE:\n                    // Walk backward to the loop statement\n                    _statement = _statement.Prev();\n\n                    depth = 0;\n\n                    while (_statement != null)\n                    {\n                        node = _statement.FirstChild();\n\n                        if (node.Type == ASTNodeType.ENDWHILE ||\n                            node.Type == ASTNodeType.ENDFOR)\n                        {\n                            depth++;\n                        }\n                        else if (node.Type == ASTNodeType.WHILE ||\n                                 node.Type == ASTNodeType.FOR ||\n                                 node.Type == ASTNodeType.FOREACH)\n                        {\n                            if (depth == 0)\n                                break;\n\n                            depth--;\n                        }\n\n                        _statement = _statement.Prev();\n                    }\n\n                    if (_statement == null)\n                        throw new RunTimeError(\"Unexpected continue\");\n                    break;\n                case ASTNodeType.STOP:\n                    _statement = null;\n                    break;\n                case ASTNodeType.REPLAY:\n                    _statement = _statement.Parent.FirstChild();\n                    break;\n                case ASTNodeType.QUIET:\n                case ASTNodeType.FORCE:\n                case ASTNodeType.COMMAND:\n                    if (ExecuteCommand(node))\n                        Advance();\n\n                    break;\n            }\n\n            return (_statement != null) ? true : false;\n        }\n\n        public void Advance()\n        {\n            Interpreter.ClearTimeout();\n            _statement = _statement.Next();\n        }\n\n        private ASTNode EvaluateModifiers(ASTNode node, out bool quiet, out bool force, out bool not)\n        {\n            quiet = false;\n            force = false;\n            not = false;\n\n            while (true)\n            {\n                switch (node.Type)\n                {\n                    case ASTNodeType.QUIET:\n                        quiet = true;\n                        break;\n                    case ASTNodeType.FORCE:\n                        force = true;\n                        break;\n                    case ASTNodeType.NOT:\n                        not = true;\n                        break;\n                    default:\n                        return node;\n                }\n\n                node = node.Next();\n            }\n        }\n\n        private bool ExecuteCommand(ASTNode node)\n        {\n            node = EvaluateModifiers(node, out bool quiet, out bool force, out _);\n\n            var handler = Interpreter.GetCommandHandler(node.Lexeme);\n\n            if (handler == null)\n                throw new RunTimeError(\"Unknown command\");\n\n            var cont = handler(node.Lexeme, ConstructArguments(ref node), quiet, force);\n\n            if (node != null)\n                throw new RunTimeError(\"Command did not consume all available arguments\");\n\n            return cont;\n        }\n\n        private bool EvaluateExpression(ref ASTNode expr)\n        {\n            if (expr == null || (expr.Type != ASTNodeType.UNARY_EXPRESSION && expr.Type != ASTNodeType.BINARY_EXPRESSION && expr.Type != ASTNodeType.LOGICAL_EXPRESSION))\n                throw new RunTimeError(\"No expression following control statement\");\n\n            var node = expr.FirstChild();\n\n            if (node == null)\n                throw new RunTimeError(\"Empty expression following control statement\");\n\n            switch (expr.Type)\n            {\n                case ASTNodeType.UNARY_EXPRESSION:\n                    return EvaluateUnaryExpression(ref node);\n                case ASTNodeType.BINARY_EXPRESSION:\n                    return EvaluateBinaryExpression(ref node);\n            }\n\n            bool lhs = EvaluateExpression(ref node);\n\n            node = node.Next();\n\n            while (node != null)\n            {\n                // Capture the operator\n                var op = node.Type;\n                node = node.Next();\n\n                if (node == null)\n                    throw new RunTimeError(\"Invalid logical expression\");\n\n                bool rhs;\n\n                var e = node.FirstChild();\n\n                switch (node.Type)\n                {\n                    case ASTNodeType.UNARY_EXPRESSION:\n                        rhs = EvaluateUnaryExpression(ref e);\n                        break;\n                    case ASTNodeType.BINARY_EXPRESSION:\n                        rhs = EvaluateBinaryExpression(ref e);\n                        break;\n                    default:\n                        throw new RunTimeError(\"Nested logical expressions are not possible\");\n                }\n\n                switch (op)\n                {\n                    case ASTNodeType.AND:\n                        lhs = lhs && rhs;\n                        break;\n                    case ASTNodeType.OR:\n                        lhs = lhs || rhs;\n                        break;\n                    default:\n                        throw new RunTimeError(\"Invalid logical operator\");\n                }\n\n                node = node.Next();\n            }\n\n            return lhs;\n        }\n\n        private bool CompareOperands(ASTNodeType op, IComparable lhs, IComparable rhs)\n        {\n            if (op == ASTNodeType.IN)\n            {\n                if (lhs.GetType() != typeof(string) || rhs.GetType() != typeof(string))\n                {\n                    throw new RunTimeError(\"The 'in' operator only works on string operands.\");\n                }\n            }\n            else if (op == ASTNodeType.AS)\n            {\n                if (lhs.GetType() != typeof(uint))\n                {\n                    throw new RunTimeError(\"The left hand side of an 'as' expression must evaluate to a serial\");\n                }\n\n                if (rhs.GetType() != typeof(string))\n                {\n                    throw new RunTimeError(\"The right hand side of an 'as' expression must evaluate to a string\");\n                }\n            }\n            else if (lhs.GetType() != rhs.GetType())\n            {\n                // Different types. Try to convert one to match the other.\n\n                if (rhs is double)\n                {\n                    // Special case for rhs doubles because we don't want to lose precision.\n                    lhs = (double)lhs;\n                }\n                else if (rhs is bool)\n                {\n                    // Special case for rhs bools because we want to down-convert the lhs.\n                    var tmp = Convert.ChangeType(lhs, typeof(bool));\n                    lhs = (IComparable)tmp;\n                }\n                else\n                {\n                    var tmp = Convert.ChangeType(rhs, lhs.GetType());\n                    rhs = (IComparable)tmp;\n                }\n            }\n\n            try\n            {\n                // Evaluate the whole expression\n                switch (op)\n                {\n                    case ASTNodeType.EQUAL:\n                        return lhs.CompareTo(rhs) == 0;\n                    case ASTNodeType.NOT_EQUAL:\n                        return lhs.CompareTo(rhs) != 0;\n                    case ASTNodeType.LESS_THAN:\n                        return lhs.CompareTo(rhs) < 0;\n                    case ASTNodeType.LESS_THAN_OR_EQUAL:\n                        return lhs.CompareTo(rhs) <= 0;\n                    case ASTNodeType.GREATER_THAN:\n                        return lhs.CompareTo(rhs) > 0;\n                    case ASTNodeType.GREATER_THAN_OR_EQUAL:\n                        return lhs.CompareTo(rhs) >= 0;\n                    case ASTNodeType.IN:\n                        return ((string)rhs).Contains((string)lhs);\n                    case ASTNodeType.AS:\n\n                        if ((uint) lhs > 0)\n                        {\n                            Interpreter.SetVariable(rhs.ToString(), lhs.ToString());\n                        }\n\n                        return CompareOperands(ASTNodeType.EQUAL, lhs, true);\n                }\n            }\n            catch (ArgumentException e)\n            {\n                throw new RunTimeError(e.Message);\n            }\n\n            throw new RunTimeError(\"Unknown operator in expression\");\n\n        }\n\n        private bool EvaluateUnaryExpression(ref ASTNode node)\n        {\n            node = EvaluateModifiers(node, out bool quiet, out bool force, out bool not);\n\n            var handler = Interpreter.GetExpressionHandler(node.Lexeme);\n\n            if (handler == null)\n                throw new RunTimeError(\"Unknown expression\");\n\n            var result = handler(node.Lexeme, ConstructArguments(ref node), quiet, force);\n\n            if (not)\n                return CompareOperands(ASTNodeType.EQUAL, result, false);\n            else\n                return CompareOperands(ASTNodeType.EQUAL, result, true);\n        }\n\n        private bool EvaluateBinaryExpression(ref ASTNode node)\n        {\n            // Evaluate the left hand side\n            var lhs = EvaluateBinaryOperand(ref node);\n\n            // Capture the operator\n            var op = node.Type;\n            node = node.Next();\n\n            // Evaluate the right hand side\n            var rhs = EvaluateBinaryOperand(ref node);\n\n            return CompareOperands(op, lhs, rhs);\n        }\n\n        private IComparable EvaluateBinaryOperand(ref ASTNode node)\n        {\n            IComparable val;\n\n            node = EvaluateModifiers(node, out bool quiet, out bool force, out _);\n            switch (node.Type)\n            {\n                case ASTNodeType.INTEGER:\n                    val = TypeConverter.ToInt(node.Lexeme);\n                    node = node.Next();\n                    break;\n                case ASTNodeType.SERIAL:\n                    val = TypeConverter.ToUInt(node.Lexeme);\n                    node = node.Next();\n                    break;\n                case ASTNodeType.STRING:\n                    val = node.Lexeme;\n                    node = node.Next();\n                    break;\n                case ASTNodeType.DOUBLE:\n                    val = TypeConverter.ToDouble(node.Lexeme);\n                    node = node.Next();\n                    break;\n                case ASTNodeType.OPERAND:\n                    {\n                        // This might be a registered keyword, so do a lookup\n                        var handler = Interpreter.GetExpressionHandler(node.Lexeme);\n\n                        if (handler != null)\n                        {\n                            val = handler(node.Lexeme, ConstructArguments(ref node), quiet, force);\n                            break;\n                        }\n\n                        // It could be a variable\n                        var arg = Interpreter.GetVariable(node.Lexeme);\n                        if (arg != null)\n                        {\n                            // TODO: Should really look at the type of arg here\n                            val = arg.AsString();\n                            node = node.Next();\n                            break;\n                        }\n\n                        // It's just a string\n                        val = node.Lexeme;\n                        node = node.Next();\n                        break;\n                    }\n                default:\n                    throw new RunTimeError(\"Invalid type found in expression\");\n            }\n\n            return val;\n        }\n    }\n\n    public static class Interpreter\n    {\n        public static Action OnStop;\n\n        // The \"global\" scope\n        private readonly static Scope _scope = new Scope(null, null);\n\n        // The current scope\n        private static Scope _currentScope = _scope;\n        \n        // Lists\n        private static Dictionary<string, List<Variable>> _lists = new Dictionary<string, List<Variable>>();\n\n        // Timers\n        private static Dictionary<string, DateTime> _timers = new Dictionary<string, DateTime>();\n\n        // Expressions\n        public delegate IComparable ExpressionHandler(string expression, Variable[] args, bool quiet, bool force);\n        public delegate T ExpressionHandler<T>(string expression, Variable[] args, bool quiet, bool force) where T : IComparable;\n\n        private static Dictionary<string, ExpressionHandler> _exprHandlers = new Dictionary<string, ExpressionHandler>();\n\n        public delegate bool CommandHandler(string command, Variable[] args, bool quiet, bool force);\n\n        private static Dictionary<string, CommandHandler> _commandHandlers = new Dictionary<string, CommandHandler>();\n\n        public delegate uint AliasHandler(string alias);\n\n        private static Dictionary<string, AliasHandler> _aliasHandlers = new Dictionary<string, AliasHandler>();\n\n        private static Script _activeScript = null;\n\n        public static int CurrentLine\n        {\n            get\n            {\n                return _activeScript == null ? 0 : _activeScript.CurrentLine;\n            }\n        }\n\n        private enum ExecutionState\n        {\n            RUNNING,\n            PAUSED,\n            TIMING_OUT\n        };\n\n        public delegate bool TimeoutCallback();\n\n        private static ExecutionState _executionState = ExecutionState.RUNNING;\n        private static long _pauseTimeout = long.MaxValue;\n        private static TimeoutCallback _timeoutCallback = null;\n\n        internal static CultureInfo Culture;\n\n        static Interpreter()\n        {\n            Culture = new CultureInfo(CultureInfo.CurrentCulture.LCID, false);\n            Culture.NumberFormat.NumberDecimalSeparator = \".\";\n            Culture.NumberFormat.NumberGroupSeparator = \",\";\n        }\n\n        public static void RegisterExpressionHandler<T>(string keyword, ExpressionHandler<T> handler) where T : IComparable\n        {\n            _exprHandlers[keyword] = (expression, args, quiet, force) => handler(expression, args, quiet, force);\n        }\n\n        public static ExpressionHandler GetExpressionHandler(string keyword)\n        {\n            _exprHandlers.TryGetValue(keyword, out var expression);\n\n            return expression;\n        }\n\n        public static void RegisterCommandHandler(string keyword, CommandHandler handler)\n        {\n            _commandHandlers[keyword] = handler;\n        }\n\n        public static CommandHandler GetCommandHandler(string keyword)\n        {\n            _commandHandlers.TryGetValue(keyword, out CommandHandler handler);\n\n            return handler;\n        }\n\n        public static void RegisterAliasHandler(string keyword, AliasHandler handler)\n        {\n            _aliasHandlers[keyword] = handler;\n        }\n\n        public static void UnregisterAliasHandler(string keyword)\n        {\n            _aliasHandlers.Remove(keyword);\n        }\n        \n        public static bool AliasHandlerExist(string alias)\n        {\n            return _aliasHandlers.TryGetValue(alias, out _);\n        }\n\n        public static void PushScope(ASTNode node)\n        {\n            _currentScope = new Scope(_currentScope, node);\n        }\n\n        public static void PopScope()\n        {\n            if (_currentScope == _scope)\n                throw new RunTimeError(\"Attempted to remove global scope\");\n\n            _currentScope = _currentScope.Parent;\n        }\n\n        internal static Scope CurrentScope => _currentScope;\n\n        public static void SetVariable(string name, string value, bool global = false)\n        {\n            Scope scope = global ? _scope : _currentScope;\n\n            scope.SetVariable(name, new Variable(value));\n        }\n\n        public static void AddIgnore(Serial serial, bool global = true)\n        {\n            Scope scope = global ? _scope : _currentScope;\n            scope.AddIgnore(serial);\n        }\n\n        public static void ClearIgnore(bool global = true)\n        {\n            Scope scope = global ? _scope : _currentScope;\n            scope.ClearIgnore();\n        }\n        \n        public static void AddIgnoreRange(List<Serial> serials, bool global = true)\n        {\n            Scope scope = global ? _scope : _currentScope;\n            scope.AddIgnoreRange(serials);\n        }\n\n        public static void RemoveIgnore(Serial serial, bool global = true)\n        {\n            Scope scope = global ? _scope : _currentScope;\n            scope.RemoveIgnore(serial);\n        }\n\n        public static void RemoveIgnoreRange(List<Serial> serials, bool global = true)\n        {\n            Scope scope = global ? _scope : _currentScope;\n            scope.RemoveIgnoreRange(serials);\n        }\n        \n        public static bool CheckIgnored(Serial serial, bool global = true)\n        {\n            Scope scope = global ? _scope : _currentScope;\n            return scope.CheckIgnored(serial);\n        }\n\n        public static Variable GetVariable(string name)\n        {\n            var scope = _currentScope;\n            Variable result = null;\n\n            while (scope != null)\n            {\n                result = scope.GetVariable(name);\n                if (result != null)\n                    return result;\n\n                scope = scope.Parent;\n            }\n\n            return result;\n        }\n\n        public static void ClearVariable(string name)\n        {\n            _currentScope.ClearVariable(name);\n        }\n\n        public static bool ExistVariable(string name)\n        {\n            return _currentScope.ExistVariable(name);\n        }\n\n        public static uint GetAlias(string alias)\n        {\n            // If a handler is explicitly registered, call that.\n            if (_aliasHandlers.TryGetValue(alias, out AliasHandler handler))\n                return handler(alias);\n\n            var arg = GetVariable(alias);\n\n            return arg?.AsUInt() ?? uint.MaxValue;\n        }\n\n        public static void SetAlias(string alias, uint serial)\n        {\n            SetVariable(alias, serial.ToString(), true);\n        }\n\n        public static void ClearAlias(string alias)\n        {\n            _scope.ClearVariable(alias);\n        }\n\n        public static bool ExistAlias(string alias)\n        {\n            return _scope.ExistVariable(alias);\n        }\n        \n        public static void CreateList(string name)\n        {\n            if (_lists.ContainsKey(name))\n                return;\n\n            _lists[name] = new List<Variable>();\n        }\n\n        public static void DestroyList(string name)\n        {\n            _lists.Remove(name);\n        }\n\n        public static void ClearList(string name)\n        {\n            if (!_lists.ContainsKey(name))\n                return;\n\n            _lists[name].Clear();\n        }\n\n        public static bool ListExists(string name)\n        {\n            return _lists.ContainsKey(name);\n        }\n\n        public static List<Variable> GetList(string name)\n        {\n            return _lists.ContainsKey(name) ? _lists[name] : null;\n        }\n        public static bool ListContains(string name, Variable arg)\n        {\n            if (!_lists.ContainsKey(name))\n                throw new RunTimeError(\"List does not exist\");\n\n            var list = _lists[name];\n            var a = arg.AsString();\n\n            foreach (var v in list)\n            {\n                if (v.AsString().Equals(a, StringComparison.OrdinalIgnoreCase))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public static int ListLength(string name)\n        {\n            if (!_lists.ContainsKey(name))\n                throw new RunTimeError(\"List does not exist\");\n\n            return _lists[name].Count;\n        }\n\n        public static void PushList(string name, Variable arg, bool front, bool unique)\n        {\n            if (!_lists.ContainsKey(name))\n                throw new RunTimeError(\"List does not exist\");\n\n            if (unique && _lists[name].Contains(arg))\n                return;\n\n            if (front)\n                _lists[name].Insert(0, arg);\n            else\n                _lists[name].Add(arg);\n        }\n\n        public static bool PopList(string name, Variable arg)\n        {\n            if (!_lists.ContainsKey(name))\n                throw new RunTimeError(\"List does not exist\");\n\n            return _lists[name].Remove(arg);\n        }\n\n        public static bool PopList(string name, bool front, out Variable removedVar)\n        {\n            if (!_lists.ContainsKey(name))\n                throw new RunTimeError(\"List does not exist\");\n\n            var list = _lists[name];\n            var idx = front ? 0 : _lists[name].Count - 1;\n\n            removedVar = list[idx];\n            list.RemoveAt(idx);\n\n            return list.Count > 0;\n        }\n\n        public static Variable GetListValue(string name, int idx)\n        {\n            if (!_lists.ContainsKey(name))\n                throw new RunTimeError(\"List does not exist\");\n\n            var list = _lists[name];\n\n            if (idx < list.Count)\n                return list[idx];\n\n            return null;\n        }\n\n        public static void CreateTimer(string name)\n        {\n            _timers[name] = DateTime.UtcNow;\n        }\n\n        public static TimeSpan GetTimer(string name)\n        {\n            if (!_timers.TryGetValue(name, out DateTime timestamp))\n                throw new RunTimeError(\"Timer does not exist\");\n\n            TimeSpan elapsed = DateTime.UtcNow - timestamp;\n\n            return elapsed;\n        }\n\n        public static void SetTimer(string name, int elapsed)\n        {\n            // Setting a timer to start at a given value is equivalent to\n            // starting the timer that number of milliseconds in the past.\n            _timers[name] = DateTime.UtcNow.AddMilliseconds(-elapsed);\n        }\n\n        public static void RemoveTimer(string name)\n        {\n            _timers.Remove(name);\n        }\n\n        public static bool TimerExists(string name)\n        {\n            return _timers.ContainsKey(name);\n        }\n\n        public static bool StartScript(Script script)\n        {\n            if (_activeScript != null)\n                return false;\n\n            _currentScope = _scope;\n            _activeScript = script;\n            _activeScript.Initialize();\n            _executionState = ExecutionState.RUNNING;\n\n            ExecuteScript();\n\n            return true;\n        }\n\n        public static void StopScript()\n        {\n            _activeScript = null;\n            _currentScope = _scope;\n            _executionState = ExecutionState.RUNNING;\n            \n            if (_timeoutCallback != null)\n            {\n                if (_timeoutCallback())\n                {\n                    ClearTimeout();\n                }\n\n                _timeoutCallback = null;\n            }\n            \n            OnStop?.Invoke();\n        }\n        \n        public static void PauseScript()\n        {\n            _pauseTimeout = DateTime.MaxValue.Ticks;\n            _executionState = ExecutionState.PAUSED;\n        }\n        public static void ResumeScript()\n        {\n            _executionState = ExecutionState.RUNNING;\n        }\n\n        public static bool ExecuteScript()\n        {\n            if (_activeScript == null)\n                return false;\n\n            if (_executionState == ExecutionState.PAUSED)\n            {\n                if (_pauseTimeout < DateTime.UtcNow.Ticks)\n                    _executionState = ExecutionState.RUNNING;\n                else\n                    return true;\n            }\n            else if (_executionState == ExecutionState.TIMING_OUT)\n            {\n                if (_pauseTimeout < DateTime.UtcNow.Ticks)\n                {\n                    if (_timeoutCallback != null)\n                    {\n                        if (_timeoutCallback())\n                        {\n                            _activeScript.Advance();\n                            ClearTimeout();\n                        }\n\n                        _timeoutCallback = null;\n                    }\n\n                    /* If the callback changed the state to running, continue\n                     * on. Otherwise, exit.\n                     */\n                    if (_executionState != ExecutionState.RUNNING)\n                    {\n                        _activeScript = null;\n                        return false;\n                    }\n                }\n            }\n\n            if (!_activeScript.ExecuteNext())\n            {\n                _activeScript = null;\n                return false;\n            }\n\n            return true;\n        }\n\n        // Pause execution for the given number of milliseconds\n        public static void Pause(long duration)\n        {\n            // Already paused or timing out\n            if (_executionState != ExecutionState.RUNNING)\n                return;\n\n            _pauseTimeout = DateTime.UtcNow.Ticks + (duration * 10000);\n            _executionState = ExecutionState.PAUSED;\n        }\n\n        // Unpause execution\n        public static void Unpause()\n        {\n            if (_executionState != ExecutionState.PAUSED)\n                return;\n\n            _pauseTimeout = 0;\n            _executionState = ExecutionState.RUNNING;\n        }\n\n        // If forward progress on the script isn't made within this\n        // amount of time (milliseconds), bail\n        public static void Timeout(long duration, TimeoutCallback callback)\n        {\n            // Don't change an existing timeout\n            if (_executionState != ExecutionState.RUNNING)\n                return;\n\n            _pauseTimeout = DateTime.UtcNow.Ticks + (duration * 10000);\n            _executionState = ExecutionState.TIMING_OUT;\n            _timeoutCallback = callback;\n        }\n\n        // Clears any previously set timeout. Automatically\n        // called any time the script advances a statement.\n        public static void ClearTimeout()\n        {\n            if (_executionState != ExecutionState.TIMING_OUT)\n                return;\n\n            _pauseTimeout = 0;\n            _executionState = ExecutionState.RUNNING;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Scripts/Engine/Lexer.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\n\nnamespace Assistant.Scripts.Engine\n{\n    public class SyntaxError : Exception\n    {\n        public ASTNode Node;\n        public string Line;\n        public int LineNumber;\n\n        public SyntaxError(ASTNode node, string error) : base(error)\n        {\n            Node = node;\n            Line = null;\n            LineNumber = 0;\n        }\n\n        public SyntaxError(string line, int lineNumber, ASTNode node, string error) : base(error)\n        {\n            Line = line;\n            LineNumber = lineNumber;\n            Node = node;\n        }\n    }\n\n    public enum ASTNodeType\n    {\n        // Keywords\n        IF,\n        ELSEIF,\n        ELSE,\n        ENDIF,\n        WHILE,\n        ENDWHILE,\n        FOR,\n        FOREACH,\n        ENDFOR,\n        BREAK,\n        CONTINUE,\n        STOP,\n        REPLAY,\n\n        // Operators\n        EQUAL,\n        NOT_EQUAL,\n        LESS_THAN,\n        LESS_THAN_OR_EQUAL,\n        GREATER_THAN,\n        GREATER_THAN_OR_EQUAL,\n        IN,\n        AS,\n\n        // Logical Operators\n        NOT,\n        AND,\n        OR,\n\n        // Value types\n        STRING,\n        SERIAL,\n        INTEGER,\n        DOUBLE,\n        LIST,\n\n        // Modifiers\n        QUIET, // @ symbol\n        FORCE, // ! symbol\n\n        // Everything else\n        SCRIPT,\n        STATEMENT,\n        COMMAND,\n        OPERAND,\n        LOGICAL_EXPRESSION,\n        UNARY_EXPRESSION,\n        BINARY_EXPRESSION,\n    }\n\n    // Abstract Syntax Tree Node\n    public class ASTNode\n    {\n        public readonly ASTNodeType Type;\n        public readonly string Lexeme;\n        public readonly ASTNode Parent;\n        public readonly int LineNumber;\n\n        internal LinkedListNode<ASTNode> _node;\n        private LinkedList<ASTNode> _children;\n\n        public ASTNode(ASTNodeType type, string lexeme, ASTNode parent, int lineNumber)\n        {\n            Type = type;\n            if (lexeme != null)\n                Lexeme = lexeme;\n            else\n                Lexeme = \"\";\n            Parent = parent;\n            LineNumber = lineNumber;\n        }\n\n        public ASTNode Push(ASTNodeType type, string lexeme, int lineNumber)\n        {\n            var node = new ASTNode(type, lexeme, this, lineNumber);\n\n            if (_children == null)\n                _children = new LinkedList<ASTNode>();\n\n            node._node = _children.AddLast(node);\n\n            return node;\n        }\n\n        public ASTNode FirstChild()\n        {\n            if (_children == null || _children.First == null)\n                return null;\n\n            return _children.First.Value;\n        }\n\n        public ASTNode Next()\n        {\n            if (_node == null || _node.Next == null)\n                return null;\n\n            return _node.Next.Value;\n        }\n\n        public ASTNode Prev()\n        {\n            if (_node == null || _node.Previous == null)\n                return null;\n\n            return _node.Previous.Value;\n        }\n    }\n\n    public static class Lexer\n    {\n        private static int _curLine = 0;\n        \n        public static bool AllowLoop { get; set; } = true;\n\n        public static T[] Slice<T>(this T[] src, int start, int end)\n        {\n            if (end < start)\n                return new T[0];\n\n            int len = end - start + 1;\n\n            T[] slice = new T[len];\n            for (int i = 0; i < len; i++)\n            {\n                slice[i] = src[i + start];\n            }\n\n            return slice;\n        }\n\n        public static ASTNode Lex(string[] lines)\n        {\n            ASTNode node = new ASTNode(ASTNodeType.SCRIPT, null, null, 0);\n\n            try\n            {\n                for (_curLine = 0; _curLine < lines.Length; _curLine++)\n                {\n                    foreach (var l in lines[_curLine].Split(';'))\n                    {\n                        ParseLine(node, l);\n                    }\n                }\n            }\n            catch (SyntaxError e)\n            {\n                throw new SyntaxError(lines[_curLine], _curLine, e.Node, e.Message);\n            }\n            catch (Exception e)\n            {\n                throw new SyntaxError(lines[_curLine], _curLine, null, e.Message);\n            }\n\n            return node;\n        }\n\n        public static ASTNode Lex(string fname)\n        {\n            ASTNode node = new ASTNode(ASTNodeType.SCRIPT, null, null, 0);\n\n            using (var file = new StreamReader(fname))\n            {\n                _curLine = 0;\n                string line = null;\n\n                try\n                {\n                    while (true)\n                    {\n                        // Each line in the file is a statement. Statements starting\n                        // with a control flow keyword contain an expression.\n\n                        line = file.ReadLine();\n\n                        // End of file\n                        if (line == null)\n                            break;\n\n                        foreach (var l in line.Split(';'))\n                            ParseLine(node, line);\n\n                        _curLine++;\n                    }\n                }\n                catch (SyntaxError e)\n                {\n                    throw new SyntaxError(line, _curLine, e.Node, e.Message);\n                }\n                catch (Exception e)\n                {\n                    throw new SyntaxError(line, _curLine, null, e.Message);\n                }\n            }\n\n            return node;\n        }\n\n        private static TextParser _tfp = new TextParser(\"\", new char[] { ' ' }, new char[] { }, new char[] { '\\'', '\\'', '\"', '\"' });\n        private static void ParseLine(ASTNode node, string line)\n        {\n            line = line.Trim();\n\n            if (line.StartsWith(\"//\") || line.StartsWith(\"#\"))\n                return;\n\n            // Split the line by spaces (unless the space is in quotes)\n            var lexemes = _tfp.GetTokens(line, false);\n\n            if (lexemes.Length == 0)\n                return;\n\n            ParseStatement(node, lexemes);\n        }\n\n        private static void ParseValue(ASTNode node, string lexeme, ASTNodeType typeDefault)\n        {\n            if (lexeme.StartsWith(\"0x\"))\n                node.Push(ASTNodeType.SERIAL, lexeme, _curLine);\n            else if (int.TryParse(lexeme, out _))\n                node.Push(ASTNodeType.INTEGER, lexeme, _curLine);\n            else if (double.TryParse(lexeme, out _))\n                node.Push(ASTNodeType.DOUBLE, lexeme, _curLine);\n            else\n                node.Push(typeDefault, lexeme, _curLine);\n        }\n\n        private static void ParseCommand(ASTNode node, string lexeme)\n        {\n            // A command may start with an '@' symbol. Pick that\n            // off.\n            if (lexeme[0] == '@')\n            {\n                node.Push(ASTNodeType.QUIET, null, _curLine);\n                lexeme = lexeme.Substring(1, lexeme.Length - 1);\n            }\n\n            // A command may end with a '!' symbol. Pick that\n            // off.\n            if (lexeme.EndsWith(\"!\"))\n            {\n                node.Push(ASTNodeType.FORCE, null, _curLine);\n                lexeme = lexeme.Substring(0, lexeme.Length - 1);\n            }\n\n            node.Push(ASTNodeType.COMMAND, lexeme, _curLine);\n        }\n\n        private static void ParseOperand(ASTNode node, string lexeme)\n        {\n            bool modifier = false;\n\n            // An operand may start with an '@' symbol. Pick that\n            // off.\n            if (lexeme[0] == '@')\n            {\n                node.Push(ASTNodeType.QUIET, null, _curLine);\n                lexeme = lexeme.Substring(1, lexeme.Length - 1);\n                modifier = true;\n            }\n\n            // An operand may end with a '!' symbol. Pick that\n            // off.\n            if (lexeme.EndsWith(\"!\"))\n            {\n                node.Push(ASTNodeType.FORCE, null, _curLine);\n                lexeme = lexeme.Substring(0, lexeme.Length - 1);\n                modifier = true;\n            }\n\n            if (!modifier)\n                ParseValue(node, lexeme, ASTNodeType.OPERAND);\n            else\n                node.Push(ASTNodeType.OPERAND, lexeme, _curLine);\n        }\n\n        private static ASTNodeType ParseOperator(ASTNode node, string lexeme)\n        {\n            ASTNodeType type;\n\n            switch (lexeme)\n            {\n                case \"==\":\n                case \"=\":\n                    type = ASTNodeType.EQUAL;\n                    break;\n                case \"!=\":\n                    type = ASTNodeType.NOT_EQUAL;\n                    break;\n                case \"<\":\n                    type = ASTNodeType.LESS_THAN;\n                    break;\n                case \"<=\":\n                    type = ASTNodeType.LESS_THAN_OR_EQUAL;\n                    break;\n                case \">\":\n                    type = ASTNodeType.GREATER_THAN;\n                    break;\n                case \">=\":\n                    type = ASTNodeType.GREATER_THAN_OR_EQUAL;\n                    break;\n                case \"in\":\n                    type = ASTNodeType.IN;\n                    break;\n                case \"as\":\n                    type = ASTNodeType.AS;\n                    break;\n                default:\n                    throw new SyntaxError(node, \"Invalid operator in binary expression\");\n            }\n\n            node.Push(type, null, _curLine);\n\n            return type;\n        }\n\n        private static void ParseStatement(ASTNode node, string[] lexemes)\n        {\n            var statement = node.Push(ASTNodeType.STATEMENT, null, _curLine);\n\n            // Examine the first word on the line\n            switch (lexemes[0])\n            {\n                // Ignore comments\n                case \"#\":\n                case \"//\":\n                    return;\n\n                // Control flow statements are special\n                case \"if\":\n                    {\n                        if (lexemes.Length <= 1)\n                            throw new SyntaxError(node, \"Script compilation error\");\n\n                        var t = statement.Push(ASTNodeType.IF, null, _curLine);\n                        ParseLogicalExpression(t, lexemes.Slice(1, lexemes.Length - 1));\n                        break;\n                    }\n                case \"elseif\":\n                    {\n                        if (lexemes.Length <= 1)\n                            throw new SyntaxError(node, \"Script compilation error\");\n\n                        var t = statement.Push(ASTNodeType.ELSEIF, null, _curLine);\n                        ParseLogicalExpression(t, lexemes.Slice(1, lexemes.Length - 1));\n                        break;\n                    }\n                case \"else\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(ASTNodeType.ELSE, null, _curLine);\n                    break;\n                case \"endif\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(ASTNodeType.ENDIF, null, _curLine);\n                    break;\n                case \"while\":\n                    {\n                        if (lexemes.Length <= 1)\n                            throw new SyntaxError(node, \"Script compilation error\");\n\n                        var t = statement.Push(ASTNodeType.WHILE, null, _curLine);\n                        ParseLogicalExpression(t, lexemes.Slice(1, lexemes.Length - 1));\n                        break;\n                    }\n                case \"endwhile\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(ASTNodeType.ENDWHILE, null, _curLine);\n                    break;\n                case \"for\":\n                    {\n                        if (lexemes.Length <= 1)\n                            throw new SyntaxError(node, \"Script compilation error\");\n\n                        ParseForLoop(statement, lexemes.Slice(1, lexemes.Length - 1));\n                        break;\n                    }\n                case \"endfor\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(ASTNodeType.ENDFOR, null, _curLine);\n                    break;\n                case \"foreach\":\n                {\n                    if (lexemes.Length != 4)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    ParseForEachLoop(statement, lexemes.Slice(1, lexemes.Length - 1));\n                    break;\n                }\n                case \"break\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(ASTNodeType.BREAK, null, _curLine);\n                    break;\n                case \"continue\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(ASTNodeType.CONTINUE, null, _curLine);\n                    break;\n                case \"stop\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(ASTNodeType.STOP, null, _curLine);\n                    break;\n                case \"replay\":\n                case \"loop\":\n                    if (lexemes.Length > 1)\n                        throw new SyntaxError(node, \"Script compilation error\");\n\n                    statement.Push(AllowLoop ? ASTNodeType.REPLAY : ASTNodeType.STOP, null, _curLine);\n                    break;\n                default:\n                    // It's a regular statement.\n                    ParseCommand(statement, lexemes[0]);\n\n                    foreach (var lexeme in lexemes.Slice(1, lexemes.Length - 1))\n                    {\n                        ParseValue(statement, lexeme, ASTNodeType.STRING);\n                    }\n                    break;\n            }\n\n        }\n\n        private static bool IsOperator(string lexeme)\n        {\n            switch (lexeme)\n            {\n                case \"==\":\n                case \"=\":\n                case \"!=\":\n                case \"<\":\n                case \"<=\":\n                case \">\":\n                case \">=\":\n                case \"in\":\n                case \"as\":\n                    return true;\n            }\n\n            return false;\n        }\n\n        private static void ParseLogicalExpression(ASTNode node, string[] lexemes)\n        {\n            // The steam language supports logical operators 'and' and 'or'.\n            // Catch those and split the expression into pieces first.\n            // Fortunately, it does not support parenthesis.\n            var expr = node;\n            bool logical = false;\n            int start = 0;\n\n            for (int i = start; i < lexemes.Length; i++)\n            {\n                if (lexemes[i] == \"and\" || lexemes[i] == \"or\")\n                {\n                    if (!logical)\n                    {\n                        expr = node.Push(ASTNodeType.LOGICAL_EXPRESSION, null, _curLine);\n                        logical = true;\n                    }\n\n                    ParseExpression(expr, lexemes.Slice(start, i - 1));\n                    start = i + 1;\n                    expr.Push(lexemes[i] == \"and\" ? ASTNodeType.AND : ASTNodeType.OR, null, _curLine);\n\n                }\n            }\n\n            ParseExpression(expr, lexemes.Slice(start, lexemes.Length - 1));\n        }\n\n        private static void ParseExpression(ASTNode node, string[] lexemes)\n        {\n\n            // The steam language supports both unary and\n            // binary expressions. First determine what type\n            // we have here.\n\n            bool unary = false;\n            bool binary = false;\n\n            foreach (var lexeme in lexemes)\n            {\n                if (lexeme == \"not\")\n                {\n                    // The not lexeme only appears in unary expressions.\n                    // Binary expressions would use \"!=\".\n                    unary = true;\n                }\n                else if (IsOperator(lexeme))\n                {\n                    // Operators mean it is a binary expression.\n                    binary = true;\n                }\n            }\n\n            // If no operators appeared, it's a unary expression\n            if (!unary && !binary)\n                unary = true;\n\n            if (unary && binary)\n                throw new SyntaxError(node, \"Invalid expression\");\n\n            if (unary)\n                ParseUnaryExpression(node, lexemes);\n            else\n                ParseBinaryExpression(node, lexemes);\n        }\n\n        private static void ParseUnaryExpression(ASTNode node, string[] lexemes)\n        {\n            var expr = node.Push(ASTNodeType.UNARY_EXPRESSION, null, _curLine);\n\n            int i = 0;\n\n            if (lexemes[i] == \"not\")\n            {\n                expr.Push(ASTNodeType.NOT, null, _curLine);\n                i++;\n            }\n\n            ParseOperand(expr, lexemes[i++]);\n\n            for (; i < lexemes.Length; i++)\n            {\n                ParseValue(expr, lexemes[i], ASTNodeType.STRING);\n            }\n        }\n\n        private static void ParseBinaryExpression(ASTNode node, string[] lexemes)\n        {\n            var expr = node.Push(ASTNodeType.BINARY_EXPRESSION, null, _curLine);\n\n            int i = 0;\n\n            // The expressions on either side of the operator can be values\n            // or operands that need to be evaluated.\n            ParseOperand(expr, lexemes[i++]);\n\n            for (; i < lexemes.Length; i++)\n            {\n                if (IsOperator(lexemes[i]))\n                    break;\n\n                ParseValue(expr, lexemes[i], ASTNodeType.STRING);\n            }\n\n            var op = ParseOperator(expr, lexemes[i++]);\n\n            if (op == ASTNodeType.AS)\n            {\n                expr.Push(ASTNodeType.STRING, lexemes[i++], _curLine);\n            }\n            else\n            {\n                ParseOperand(expr, lexemes[i++]);\n            }\n\n            for (; i < lexemes.Length; i++)\n            {\n                if (IsOperator(lexemes[i]))\n                    break;\n\n                ParseValue(expr, lexemes[i], ASTNodeType.STRING);\n            }\n        }\n\n        private static void ParseForLoop(ASTNode statement, string[] lexemes)\n        {\n            // There are 4 variants of for loops in steam. The simplest two just\n            // iterate a fixed number of times. The other two iterate\n            // parts of lists. We call those second two FOREACH.\n\n            // We're intentionally deprecating two of the variants here.\n            // The for X to Y variant, where both X and Y are integers,\n            // is useless. It can be just written as for X.\n            // The for X to Y in LIST variant may have some niche uses, but\n            // is annoying to implement.\n\n            // The for X loop remains supported as is, while the\n            // for X in LIST form is actually transformed into a foreach\n            // statement.\n\n            if (lexemes.Length == 1)\n            {\n                // for X\n                var loop = statement.Push(ASTNodeType.FOR, null, _curLine);\n\n                ParseValue(loop, lexemes[0], ASTNodeType.STRING);\n\n            }\n            else if (lexemes.Length == 3 && lexemes[1] == \"to\")\n            {\n                // for X to LIST\n                var loop = statement.Push(ASTNodeType.FOREACH, null, _curLine);\n\n                loop.Push(ASTNodeType.STRING, lexemes[2], _curLine);\n                loop.Push(ASTNodeType.LIST, lexemes[2].Substring(0, lexemes[2].Length - 2), _curLine);\n            }\n            else\n            {\n                throw new SyntaxError(statement, \"Invalid for loop\");\n            }\n        }\n        \n        private static void ParseForEachLoop(ASTNode statement, string[] lexemes)\n        {\n            // foreach X in LIST\n            var loop = statement.Push(ASTNodeType.FOREACH, null, _curLine);\n\n            if (lexemes[1] != \"in\")\n                throw new SyntaxError(statement, \"Invalid foreach loop\");\n\n            // This is the iterator name\n            ParseValue(loop, lexemes[0], ASTNodeType.STRING);\n            loop.Push(ASTNodeType.LIST, lexemes[2], _curLine);\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Scripts/Engine/TextParser.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\nusing System.Text;\n\nnamespace Assistant.Scripts.Engine\n{\n    internal class TextParser\n    {\n        private readonly char[] _delimiters, _comments, _quotes;\n        private int _eol;\n        private int _pos;\n        private int _Size;\n        private string _string;\n        private bool _trim;\n\n        public TextParser(string str, char[] delimiters, char[] comments, char[] quotes)\n        {\n            _delimiters = delimiters;\n            _comments = comments;\n            _quotes = quotes;\n            _Size = str.Length;\n            _string = str;\n        }\n\n        internal bool IsDelimiter()\n        {\n            bool result = false;\n\n            for (int i = 0; i < _delimiters.Length && !result; i++)\n                result = _string[_pos] == _delimiters[i];\n\n            return result;\n        }\n\n        private void SkipToData()\n        {\n            while (_pos < _eol && IsDelimiter())\n                _pos++;\n        }\n\n        private bool IsComment()\n        {\n            bool result = _string[_pos] == '\\n';\n\n            for (int i = 0; i < _comments.Length && !result; i++)\n            {\n                result = _string[_pos] == _comments[i];\n\n                if (result && i + 1 < _comments.Length && _comments[i] == _comments[i + 1] && _pos + 1 < _eol)\n                {\n                    result = _string[_pos] == _string[_pos + 1];\n                    i++;\n                }\n            }\n\n            return result;\n        }\n\n        private string ObtainData()\n        {\n            StringBuilder result = new StringBuilder();\n\n            while (_pos < _Size && _string[_pos] != '\\n')\n            {\n                if (IsDelimiter())\n                    break;\n\n                if (IsComment())\n                {\n                    _pos = _eol;\n\n                    break;\n                }\n\n                if (_string[_pos] != '\\r' && (!_trim || _string[_pos] != ' ' && _string[_pos] != '\\t'))\n                    result.Append(_string[_pos]);\n\n                _pos++;\n            }\n\n            return result.ToString();\n        }\n\n        private string ObtainQuotedData()\n        {\n            bool exit = false;\n            string result = \"\";\n\n            for (int i = 0; i < _quotes.Length; i += 2)\n            {\n                if (_string[_pos] == _quotes[i])\n                {\n                    char endQuote = _quotes[i + 1];\n                    exit = true;\n\n                    int pos = _pos + 1;\n                    int start = pos;\n\n                    while (pos < _eol && _string[pos] != '\\n' && _string[pos] != endQuote)\n                    {\n                        if (_string[pos] == _quotes[i]) // another {\n                        {\n                            _pos = pos;\n                            ObtainQuotedData(); // skip\n                            pos = _pos;\n                        }\n\n                        pos++;\n                    }\n\n                    _pos++;\n                    int size = pos - start;\n\n                    if (size > 0)\n                    {\n                        result = _string.Substring(start, size).TrimEnd('\\r', '\\n');\n                        _pos = pos;\n\n                        if (_pos < _eol && _string[_pos] == endQuote)\n                            _pos++;\n                    }\n\n                    break;\n                }\n            }\n\n            if (!exit)\n                result = ObtainData();\n\n            return result;\n        }\n\n        internal string[] GetTokens(string str, bool trim = true)\n        {\n            _trim = trim;\n            List<string> result = new List<string>();\n\n            _pos = 0;\n            _string = str;\n            _Size = str.Length;\n            _eol = _Size - 1;\n\n            while (_pos < _eol)\n            {\n                SkipToData();\n\n                if (IsComment())\n                    break;\n\n                string buf = ObtainQuotedData();\n\n                if (buf.Length > 0)\n                    result.Add(buf);\n            }\n\n            return result.ToArray();\n        }\n    }\n}"
  },
  {
    "path": "Razor/Scripts/Expressions.cs",
    "content": "﻿#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing Assistant.Core;\r\nusing Assistant.Scripts.Engine;\r\nusing Assistant.Scripts.Helpers;\r\nusing Ultima;\r\n\r\nnamespace Assistant.Scripts\r\n{\r\n    public static class Expressions\r\n    {\r\n        public static void Register()\r\n        {\r\n            Interpreter.RegisterExpressionHandler(\"stam\", Stam);\r\n            Interpreter.RegisterExpressionHandler(\"maxstam\", MaxStam);\r\n            Interpreter.RegisterExpressionHandler(\"hp\", Hp);\r\n            Interpreter.RegisterExpressionHandler(\"hits\", Hp);\r\n            Interpreter.RegisterExpressionHandler(\"maxhp\", MaxHp);\r\n            Interpreter.RegisterExpressionHandler(\"maxhits\", MaxHp);\r\n            Interpreter.RegisterExpressionHandler(\"mana\", Mana);\r\n            Interpreter.RegisterExpressionHandler(\"maxmana\", MaxMana);\r\n            Interpreter.RegisterExpressionHandler(\"poisoned\", Poisoned);\r\n            Interpreter.RegisterExpressionHandler(\"hidden\", Hidden);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"mounted\", Mounted);\r\n            Interpreter.RegisterExpressionHandler(\"rhandempty\", RHandEmpty);\r\n            Interpreter.RegisterExpressionHandler(\"lhandempty\", LHandEmpty);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"dead\", Dead);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"str\", Str);\r\n            Interpreter.RegisterExpressionHandler(\"int\", Int);\r\n            Interpreter.RegisterExpressionHandler(\"dex\", Dex);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"weight\", Weight);\r\n            Interpreter.RegisterExpressionHandler(\"maxweight\", MaxWeight);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"skill\", SkillExpression);\r\n            Interpreter.RegisterExpressionHandler(\"count\", CountExpression);\r\n            Interpreter.RegisterExpressionHandler(\"counter\", CountExpression);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"insysmsg\", InSysMessage);\r\n            Interpreter.RegisterExpressionHandler(\"insysmessage\", InSysMessage);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"findtype\", FindType);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"findbuff\", FindBuffDebuff);\r\n            Interpreter.RegisterExpressionHandler(\"finddebuff\", FindBuffDebuff);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"position\", Position);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"queued\", Queued);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"varexist\", VarExist);\r\n            Interpreter.RegisterExpressionHandler(\"varexists\", VarExist);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"followers\", Followers);\r\n            Interpreter.RegisterExpressionHandler(\"maxfollowers\", MaxFollowers);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"targetexists\", TargetExists);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"diffweight\", DiffWeight);\r\n            Interpreter.RegisterExpressionHandler(\"diffhits\", DiffHits);\r\n            Interpreter.RegisterExpressionHandler(\"diffhp\", DiffHits);\r\n            Interpreter.RegisterExpressionHandler(\"diffstam\", DiffStam);\r\n            Interpreter.RegisterExpressionHandler(\"diffmana\", DiffMana);\r\n\r\n            Interpreter.RegisterExpressionHandler(\"name\", Name);\r\n            Interpreter.RegisterExpressionHandler(\"paralyzed\", Paralyzed);\r\n            Interpreter.RegisterExpressionHandler(\"invuln\", Invulnerable);\r\n            Interpreter.RegisterExpressionHandler(\"invul\", Invulnerable);\r\n            Interpreter.RegisterExpressionHandler(\"blessed\", Invulnerable);\r\n            Interpreter.RegisterExpressionHandler(\"warmode\", Warmode);\r\n            \r\n            Interpreter.RegisterExpressionHandler(\"itemcount\", ItemCount);\r\n            \r\n            Interpreter.RegisterExpressionHandler(\"poplist\", PopListExp);\r\n            Interpreter.RegisterExpressionHandler(\"listexists\", ListExists);\r\n            Interpreter.RegisterExpressionHandler(\"list\", ListLength);\r\n            Interpreter.RegisterExpressionHandler(\"inlist\", InList);\r\n            \r\n            Interpreter.RegisterExpressionHandler(\"timer\", TimerValue);\r\n            Interpreter.RegisterExpressionHandler(\"timerexists\", TimerExists);\r\n        }\r\n        \r\n        private static int TimerValue(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (args.Length != 1)\r\n                throw new RunTimeError(\"Usage: timer ('timer name')\");\r\n\r\n            var ts = Interpreter.GetTimer(args[0].AsString());\r\n\r\n            return (int)ts.TotalMilliseconds;\r\n        }\r\n\r\n        private static bool TimerExists(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (args.Length != 1)\r\n                throw new RunTimeError(\"Usage: timerexists ('timer name')\");\r\n\r\n            return Interpreter.TimerExists(args[0].AsString());\r\n        }\r\n        \r\n        private static bool ListExists(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (args.Length != 1)\r\n                throw new RunTimeError(\"Usage: listexists ('list name')\");\r\n\r\n            if (Interpreter.ListExists(args[0].AsString()))\r\n                return true;\r\n\r\n            return false;\r\n        }\r\n\r\n        private static int ListLength(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (args.Length != 1)\r\n                throw new RunTimeError(\"Usage: list (list name) (operator) (value)\");\r\n\r\n            return Interpreter.ListLength(args[0].AsString());\r\n        }\r\n\r\n        private static bool InList(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (args.Length != 2)\r\n                throw new RunTimeError(\"Usage: inlist (list name) (element)\");\r\n\r\n            if (Interpreter.ListContains(args[0].AsString(), args[1]))\r\n                return true;\r\n\r\n            return false;\r\n        }\r\n        \r\n        private static uint PopListExp(string command, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (args.Length != 2)\r\n                throw new RunTimeError(\"Usage: poplist ('list name') ('element value'/'front'/'back')\");\r\n\r\n            var listName = args[0].AsString();\r\n            var frontBackOrElementVar = args[1];\r\n            var isFrontOrBack = frontBackOrElementVar.AsString() == \"front\" || frontBackOrElementVar.AsString() == \"back\";\r\n\r\n            if (isFrontOrBack)\r\n            {\r\n                var isFront = frontBackOrElementVar.AsString() == \"front\";\r\n                if (force)\r\n                {\r\n                    while (Interpreter.PopList(listName, isFront, out _)) { }\r\n                    return Serial.Zero;\r\n                }\r\n\r\n                Interpreter.PopList(listName, isFront, out var popped);\r\n                return popped.AsSerial();\r\n            }\r\n\r\n            var evaluatedVar = new Variable(frontBackOrElementVar.AsString());\r\n\r\n            if (force)\r\n            {\r\n                while (Interpreter.PopList(listName, evaluatedVar)) { }\r\n                return Serial.Zero;\r\n            }\r\n\r\n            Interpreter.PopList(listName, evaluatedVar);\r\n            return evaluatedVar.AsSerial();\r\n        }\r\n        \r\n        private static int ItemCount(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            return World.Player == null ? 0 : World.Player.Backpack.GetTotalCount();\r\n        }\r\n        \r\n        private static string Name(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            return World.Player == null ? string.Empty : World.Player.Name;\r\n        }\r\n\r\n        private static bool Paralyzed(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && World.Player.Paralyzed;\r\n        }\r\n\r\n        private static bool Invulnerable(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && World.Player.Blessed;\r\n        }\r\n\r\n        private static bool Warmode(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && World.Player.Warmode;\r\n        }\r\n\r\n        private static int MaxFollowers(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            return World.Player == null ? 0 : World.Player.FollowersMax;\r\n        }\r\n\r\n        private static int Followers(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            return World.Player == null ? 0 : World.Player.Followers;\r\n        }\r\n\r\n        private static bool VarExist(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (vars.Length != 1)\r\n            {\r\n                throw new RunTimeError(\"Usage: varexist ('name')\");\r\n            }\r\n\r\n            string varName = vars[0].AsString(false);\r\n\r\n            return quiet ? Interpreter.ExistVariable(varName) : Interpreter.ExistAlias(varName);\r\n        }\r\n\r\n        private static bool Queued(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            return !ActionQueue.Empty;\r\n        }\r\n\r\n        private static bool FindBuffDebuff(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (vars.Length == 0)\r\n            {\r\n                throw new RunTimeError(\"Usage: findbuff/finddebuff ('name of buff')\");\r\n            }\r\n\r\n            string name = vars[0].AsString();\r\n\r\n            foreach (BuffDebuff buff in World.Player.BuffsDebuffs)\r\n            {\r\n                if (buff.ClilocMessage1.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1)\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        private static uint FindType(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (vars.Length == 0)\r\n            {\r\n                throw new RunTimeError(\"Usage: findtype ('name of item'/'graphicID) [inrangecheck (true/false)/backpack] [hue]\");\r\n            }\r\n\r\n            string gfxStr = vars[0].AsString();\r\n            Serial gfx = Utility.ToUInt16(gfxStr, 0);\r\n            List<Item> items;\r\n            List<Mobile> mobiles;\r\n\r\n            bool inRangeCheck = false;\r\n            bool backpack = false;\r\n            int hue = -1;\r\n\r\n            if (vars.Length > 1)\r\n            {\r\n                if (vars.Length == 3)\r\n                {\r\n                    hue = vars[2].AsInt();\r\n                }\r\n\r\n                if (vars[1].AsString().IndexOf(\"pack\", StringComparison.OrdinalIgnoreCase) > 0)\r\n                {\r\n                    backpack = true;\r\n                }\r\n                else\r\n                {\r\n                    inRangeCheck = vars[1].AsBool();\r\n                }\r\n            }\r\n\r\n            // No graphic id, maybe searching by name?\r\n            if (gfx == 0)\r\n            {\r\n                items = CommandHelper.GetItemsByName(gfxStr, backpack, inRangeCheck, hue);\r\n\r\n                if (items.Count == 0) // no item found, search mobile by name\r\n                {\r\n                    mobiles = CommandHelper.GetMobilesByName(gfxStr, inRangeCheck);\r\n\r\n                    if (mobiles.Count > 0)\r\n                    {\r\n                        return mobiles[Utility.Random(mobiles.Count)].Serial;\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    return items[Utility.Random(items.Count)].Serial;\r\n                }\r\n            }\r\n            else // Provided graphic id for type, check backpack first (same behavior as DoubleClickAction in macros\r\n            {\r\n                ushort id = Utility.ToUInt16(gfxStr, 0);\r\n\r\n                items = CommandHelper.GetItemsById(id, backpack, inRangeCheck, hue);\r\n\r\n                // Still no item? Mobile check!\r\n                if (items.Count == 0)\r\n                {\r\n                    mobiles = CommandHelper.GetMobilesById(id, inRangeCheck);\r\n\r\n                    if (mobiles.Count > 0)\r\n                    {\r\n                        return mobiles[Utility.Random(mobiles.Count)].Serial;\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    return items[Utility.Random(items.Count)].Serial;\r\n                }\r\n            }\r\n\r\n            return Serial.Zero;\r\n        }\r\n\r\n        private static bool Mounted(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && World.Player.GetItemOnLayer(Layer.Mount) != null;\r\n        }\r\n\r\n        private static bool RHandEmpty(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && World.Player.GetItemOnLayer(Layer.RightHand) == null;\r\n        }\r\n\r\n        private static bool LHandEmpty(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && World.Player.GetItemOnLayer(Layer.LeftHand) == null;\r\n        }\r\n\r\n        private static bool Dead(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && World.Player.IsGhost;\r\n        }\r\n\r\n        private static bool InSysMessage(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (vars.Length == 0)\r\n            {\r\n                throw new RunTimeError(\"Usage: insysmsg ('text')\");\r\n            }\r\n\r\n            string text = vars[0].AsString();\r\n\r\n            return SystemMessages.Exists(text);\r\n        }\r\n\r\n        private static int Mana(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.Mana;\r\n        }\r\n\r\n        private static int MaxMana(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.ManaMax;\r\n        }\r\n\r\n        private static bool Poisoned(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned) &&\r\n                   World.Player.Poisoned;\r\n        }\r\n\r\n        private static bool Hidden(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            return World.Player != null && !World.Player.Visible;\r\n        }\r\n\r\n        private static int Hp(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.Hits;\r\n        }\r\n\r\n        private static int MaxHp(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.HitsMax;\r\n        }\r\n\r\n        private static int Stam(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.Stam;\r\n        }\r\n\r\n        private static int MaxStam(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.StamMax;\r\n        }\r\n\r\n        private static int Str(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.Str;\r\n        }\r\n\r\n        private static int Dex(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.Dex;\r\n        }\r\n\r\n        private static int Int(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.Int;\r\n        }\r\n\r\n        private static int Weight(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.Weight;\r\n        }\r\n\r\n        private static int MaxWeight(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.MaxWeight;\r\n        }\r\n\r\n        private static double SkillExpression(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (vars.Length < 1)\r\n                throw new RunTimeError(\"Usage: skill ('name of skill')\");\r\n\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            if (Skills.SkillsByName.TryGetValue(vars[0].AsString(), out var skill))\r\n            {\r\n                return force ? World.Player.Skills[skill.Index].Base : World.Player.Skills[skill.Index].Value;\r\n            }\r\n\r\n            CommandHelper.SendWarning(expression, $\"Skill '{vars[0].AsString()}' not found\", quiet);\r\n\r\n            return 0;\r\n        }\r\n\r\n        private static int CountExpression(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (vars.Length < 1)\r\n                throw new RunTimeError(\"Usage: count ('name of counter') OR count ('name of item' OR graphicID) [hue]\");\r\n\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            var counter = Counter.FindCounter(vars[0].AsString());\r\n            if (counter != null)\r\n            {\r\n                return counter.Amount;\r\n            }\r\n\r\n            string gfxStr = vars[0].AsString();\r\n            Serial gfx = Utility.ToUInt16(gfxStr, 0);\r\n            ushort hue = 0xFFFF;\r\n\r\n            if (vars.Length == 2)\r\n            {\r\n                hue = Utility.ToUInt16(vars[1].AsString(), 0xFFFF);\r\n            }\r\n\r\n            // No graphic id, maybe searching by name?\r\n            if (gfx == 0)\r\n            {\r\n                var items = CommandHelper.GetItemsByName(gfxStr, true, false, -1);\r\n                \r\n                return items.Count == 0 ? 0 : Counter.GetCount(items[0].ItemID, hue);\r\n            }\r\n\r\n            return Counter.GetCount(new ItemID((ushort)gfx.Value), hue);\r\n        }\r\n\r\n        private static bool Position(string expression, Variable[] vars, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return false;\r\n\r\n            if (vars.Length < 2)\r\n            {\r\n                throw new RunTimeError(\"Usage: position (x, y) or position (x, y, z)\");\r\n            } \r\n\r\n            int x = vars[0].AsInt();\r\n            int y = vars[1].AsInt();\r\n            int z = (vars.Length > 2) \r\n                ? vars[2].AsInt() \r\n                : World.Player.Position.Z;\r\n\r\n            return World.Player.Position.X == x\r\n                && World.Player.Position.Y == y\r\n                && World.Player.Position.Z == z;\r\n        }\r\n\r\n        private static readonly Dictionary<string, byte> TargetMap = new Dictionary<string, byte>\r\n        {\r\n            {\"neutral\", 0},\r\n            {\"harmful\", 1},\r\n            {\"beneficial\", 2},\r\n            {\"any\", 3}\r\n        };\r\n\r\n        private static bool TargetExists(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            byte type = 3;\r\n\r\n            if (args.Length > 0)\r\n            {\r\n                if (!TargetMap.TryGetValue(args[0].AsString().ToLower(), out type))\r\n                {\r\n                    throw new RunTimeError(\"Invalid target type: 0 = neutral, 1 = harmful, 2 = beneficial, any = 3\");\r\n                }\r\n            }\r\n\r\n            if (!Targeting.HasTarget)\r\n                return false;\r\n\r\n            if (type == 3)\r\n                return true;\r\n\r\n            return Targeting.CursorType == type;\r\n        }\r\n\r\n        private static int DiffWeight(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.MaxWeight - World.Player.Weight;\r\n        }\r\n\r\n        private static int DiffHits(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.HitsMax - World.Player.Hits;\r\n        }\r\n\r\n        private static int DiffStam(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.StamMax - World.Player.Stam;\r\n        }\r\n\r\n        private static int DiffMana(string expression, Variable[] args, bool quiet, bool force)\r\n        {\r\n            if (World.Player == null)\r\n                return 0;\r\n\r\n            return World.Player.ManaMax - World.Player.Mana;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/Scripts/Helpers/CommandHelper.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing Assistant.Filters;\nusing Assistant.Scripts.Engine;\n\nnamespace Assistant.Scripts.Helpers\n{\n    public static class CommandHelper\n    {\n        /// <summary>\n        /// Common logic for dclicktype and targettype to find items by name\n        /// </summary>\n        /// <param name=\"name\"></param>\n        /// <param name=\"backpack\"></param>\n        /// <param name=\"inRange\"></param>\n        /// <param name=\"hue\"></param>\n        /// <returns></returns>\n        public static List<Item> GetItemsByName(string name, bool backpack, bool inRange, int hue)\n        {\n            List<Item> items = new List<Item>();\n\n            if (backpack && World.Player.Backpack != null) // search backpack only\n            {\n                items.AddRange(World.Player.Backpack.FindItemsByName(name, true).Where(item => !Interpreter.CheckIgnored(item.Serial)));\n            }\n            else if (inRange) // inrange includes both backpack and within 2 tiles\n            {\n                items.AddRange(World.FindItemsByName(name).Where(item =>\n                    !item.IsInBank && !Interpreter.CheckIgnored(item.Serial) && (Utility.InRange(World.Player.Position, item.Position, 2) ||\n                                       item.RootContainer == World.Player)));\n            }\n            else\n            {\n                items.AddRange(World.FindItemsByName(name).Where(item => !item.IsInBank && !Interpreter.CheckIgnored(item.Serial)));\n            }\n\n            if (hue > -1)\n            {\n                items.RemoveAll(item => item.Hue != hue);\n            }\n\n            return items;\n        }\n\n        /// <summary>\n        /// Common logic for dclicktype and targettype to find items by id\n        /// </summary>\n        /// <param name=\"id\"></param>\n        /// <param name=\"backpack\"></param>\n        /// <param name=\"inRange\"></param>\n        /// <param name=\"hue\"></param>\n        /// <returns></returns>\n        public static List<Item> GetItemsById(ushort id, bool backpack, bool inRange, int hue)\n        {\n            List<Item> items = new List<Item>();\n\n            if (backpack && World.Player.Backpack != null)\n            {\n                items.AddRange(World.Player.Backpack.FindItemsById(id, true).Where(item => !Interpreter.CheckIgnored(item.Serial)));\n            } \n            else if (inRange)\n            {\n                items.AddRange(World.FindItemsById(id).Where(item =>\n                    !item.IsInBank && !Interpreter.CheckIgnored(item.Serial) && (Utility.InRange(World.Player.Position, item.Position, 2) ||\n                                                                              item.RootContainer == World.Player)));\n            }\n            else\n            {\n                items.AddRange(World.FindItemsById(id).Where(item => !item.IsInBank && !Interpreter.CheckIgnored(item.Serial)));\n            }\n\n            if (hue > -1)\n            {\n                items.RemoveAll(item => item.Hue != hue);\n            }\n\n            return items;\n        }\n\n        /// <summary>\n        /// Common logic for dclicktype and targettype to find mobiles by name\n        /// </summary>\n        /// <param name=\"name\"></param>\n        /// <param name=\"inRange\"></param>\n        /// <returns></returns>\n        public static List<Mobile> GetMobilesByName(string name, bool inRange)\n        {\n            List<Mobile> mobiles = new List<Mobile>();\n\n            mobiles.AddRange(inRange\n                ? World.FindMobilesByName(name).Where(m => !Interpreter.CheckIgnored(m.Serial) && Utility.InRange(World.Player.Position, m.Position, 2))\n                : World.FindMobilesByName(name).Where(m => !Interpreter.CheckIgnored(m.Serial)));\n\n            return mobiles;\n        }\n\n        /// <summary>\n        /// Common logic for dclicktype and targettype to find mobiles by id\n        /// </summary>\n        /// <param name=\"id\"></param>\n        /// <param name=\"inRange\"></param>\n        /// <returns></returns>\n        public static List<Mobile> GetMobilesById(ushort id, bool inRange)\n        {\n            List<Mobile> mobiles = new List<Mobile>();\n\n            mobiles.AddRange(inRange\n                ? World.MobilesInRange().Where(m =>\n                    Utility.InRange(World.Player.Position, m.Position, 2) && m.Body == id &&\n                    !Interpreter.CheckIgnored(m.Serial))\n                : World.MobilesInRange().Where(m => m.Body == id && !Interpreter.CheckIgnored(m.Serial)));\n\n            return mobiles;\n        }\n\n        public static void SendWarning(string command, string message, bool quiet)\n        {\n            if (!quiet)\n            {\n                World.Player.SendMessage(MsgLevel.Warning, $\"{command} - {message}\");\n            }\n        }\n\n        public static void SendMessage(string message, bool quiet)\n        {\n            if (!quiet)\n            {\n                World.Player.SendMessage(MsgLevel.Force, message);\n            }\n        }\n\n        public static void SendInfo(string message, bool quiet)\n        {\n            if (!quiet)\n            {\n                World.Player.SendMessage(MsgLevel.Info, message);\n            }\n        }\n\n        /// <summary>\n        /// Parse the script input to target the correct mobile\n        /// </summary>\n        /// <param name=\"args\"></param>\n        /// <param name=\"closest\"></param>\n        /// <param name=\"random\"></param>\n        /// <param name=\"next\"></param>\n        /// <param name=\"prev\"></param>\n        public static void FindTarget(Variable[] args, bool closest, bool random = false, bool next = false, bool prev = false)\n        {\n            ScriptManager.TargetFound = false;\n\n            // Do a basic t\n            if (args.Length == 1)\n            {\n                if (closest)\n                {\n                    Targeting.TargetClosest();\n                }\n                else if (random)\n                {\n                    Targeting.TargetRandAnyone();\n                }\n                else if (next)\n                {\n                    Targeting.NextTarget();\n                }\n                else\n                {\n                    Targeting.PrevTarget();\n                }\n            }\n            else if ((next || prev) && args.Length == 2)\n            {\n                switch (args[1].AsString())\n                {\n                    case \"human\":\n                    case \"humanoid\":\n\n                        if (next)\n                        {\n                            Targeting.NextTargetHumanoid();\n                        }\n                        else\n                        {\n                            Targeting.PrevTargetHumanoid();\n                        }\n\n                        break;\n                    case \"monster\":\n                        if (next)\n                        {\n                            Targeting.NextTargetMonster();\n                        }\n                        else\n                        {\n                            Targeting.PrevTargetMonster();\n                        }\n\n                        break;\n                    case \"friend\":\n                        if (next)\n                        {\n                            Targeting.NextTargetFriend();\n                        }\n                        else\n                        {\n                            Targeting.PrevTargetFriend();\n                        }\n\n                        break;\n                    case \"friendly\":\n                        if (next)\n                        {\n                            Targeting.NextTargetFriendly();\n                        }\n                        else\n                        {\n                            Targeting.PrevTargetFriendly();\n                        }\n\n                        break;\n                    case \"nonfriendly\":\n                        if (next)\n                        {\n                            Targeting.NextTargetNonFriend();\n                        }\n                        else\n                        {\n                            Targeting.PrevTargetNonFriend();\n                        }\n\n                        break;\n                    default:\n                        throw new RunTimeError($\"Unknown target type: '{args[1].AsString()}' - Missing type? (human/monster)\");\n                }\n            }\n            else if (args.Length > 1)\n            {\n                string list = args[1].AsString();\n\n                if (list.IndexOf('!') != -1)\n                {\n                    FindTargetPriority(args, closest, random, next);\n                }\n                else if (list.IndexOf(',') != -1)\n                {\n                    FindTargetNotoriety(args, closest, random, next);\n                }\n                else\n                {\n                    FindTargetPriority(args, closest, random, next);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Find targets based on notoriety\n        /// </summary>\n        /// <param name=\"args\"></param>\n        /// <param name=\"closest\"></param>\n        /// <param name=\"random\"></param>\n        /// <param name=\"next\"></param>\n        private static void FindTargetNotoriety(Variable[] args, bool closest, bool random, bool next)\n        {\n            string[] notoList = args[1].AsString().Split(',');\n\n            List<int> notoTypes = new List<int>();\n\n            foreach (string noto in notoList)\n            {\n                Targeting.TargetType type = (Targeting.TargetType)Enum.Parse(typeof(Targeting.TargetType), noto, true);\n\n                /*NonFriendly, //Attackable, Criminal, Enemy, Murderer\n                Friendly, //Innocent, Guild/Ally \n                Red, //Murderer\n                Blue, //Innocent\n                Gray, //Attackable, Criminal\n                Grey, //Attackable, Criminal\n                Green, //GuildAlly\n                Guild, //GuildAlly*/\n\n                switch (type)\n                {\n                    case Targeting.TargetType.Friendly:\n                        notoTypes.Add((int) Targeting.TargetType.Innocent);\n                        notoTypes.Add((int) Targeting.TargetType.GuildAlly);\n                        break;\n                    case Targeting.TargetType.NonFriendly:\n                        notoTypes.Add((int)Targeting.TargetType.Attackable);\n                        notoTypes.Add((int)Targeting.TargetType.Criminal);\n                        notoTypes.Add((int)Targeting.TargetType.Enemy);\n                        notoTypes.Add((int)Targeting.TargetType.Murderer);\n                        break;\n                    case Targeting.TargetType.Red:\n                        notoTypes.Add((int)Targeting.TargetType.Murderer);\n                        break;\n                    case Targeting.TargetType.Blue:\n                        notoTypes.Add((int)Targeting.TargetType.Innocent);\n                        break;\n                    case Targeting.TargetType.Gray:\n                    case Targeting.TargetType.Grey:\n                        notoTypes.Add((int)Targeting.TargetType.Attackable);\n                        notoTypes.Add((int)Targeting.TargetType.Criminal);\n                        break;\n                    case Targeting.TargetType.Green:\n                    case Targeting.TargetType.Guild:\n                        notoTypes.Add((int)Targeting.TargetType.GuildAlly);\n                        break;\n                    default:\n                        notoTypes.Add((int)type);\n                        break;\n                }\n            }\n\n            if (args.Length == 3)\n            {\n                if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    if (closest)\n                    {\n                        Targeting.ClosestHumanoidTarget(notoTypes.ToArray());\n                    }\n                    else if (random)\n                    {\n                        Targeting.RandomHumanoidTarget(notoTypes.ToArray());\n                    } \n                    else if (next)\n                    {\n                        Targeting.NextPrevTargetNotorietyHumanoid(true, notoTypes.ToArray());\n                    }\n                    else\n                    {\n                        Targeting.NextPrevTargetNotorietyHumanoid(false, notoTypes.ToArray());\n                    }\n                }\n                else if (args[2].AsString().IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    if (closest)\n                    {\n                        Targeting.ClosestMonsterTarget(notoTypes.ToArray());\n                    }\n                    else if (random)\n                    {\n                        Targeting.RandomMonsterTarget(notoTypes.ToArray());\n                    }\n                    else if (next)\n                    {\n                        Targeting.NextPrevTargetNotorietyMonster(true, notoTypes.ToArray());\n                    }\n                    else\n                    {\n                        Targeting.NextPrevTargetNotorietyMonster(false, notoTypes.ToArray());\n                    }\n                }\n            }\n            else\n            {\n                if (closest)\n                {\n                    Targeting.ClosestTarget(notoTypes.ToArray());\n                }\n                else if (random)\n                {\n                    Targeting.RandomTarget(notoTypes.ToArray());\n                }\n                else if (next)\n                {\n                    Targeting.NextPrevTargetNotoriety(true, notoTypes.ToArray());\n                }\n                else\n                {\n                    Targeting.NextPrevTargetNotoriety(false, notoTypes.ToArray());\n                }\n            }\n        }\n\n        /// <summary>\n        /// Find a target based on a priority list of notorieties \n        /// </summary>\n        /// <param name=\"args\"></param>\n        /// <param name=\"closest\"></param>\n        /// <param name=\"random\"></param>\n        /// <param name=\"next\"></param>\n        private static void FindTargetPriority(Variable[] args, bool closest, bool random, bool next)\n        {\n            string[] notoList = args[1].AsString().Split('!');\n\n            foreach (string noto in notoList)\n            {\n                if (ScriptManager.TargetFound)\n                {\n                    break;\n                }\n\n                switch (noto)\n                {\n                    case \"enemy\":\n                        if (args.Length == 3)\n                        {\n                            if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseEnemyHumanoid();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandEnemyHumanoid();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetEnemyHumanoid();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetEnemyHumanoid();\n                                }\n                            }\n                            else if (args[2].AsString()\n                                .IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseEnemyMonster();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandEnemyMonster();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetEnemyMonster();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetEnemyMonster();\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (closest)\n                            {\n                                Targeting.TargetCloseEnemy();\n                            }\n                            else if (random)\n                            {\n                                Targeting.TargetRandEnemy();\n                            }\n                        }\n\n                        break;\n                    case \"friend\":\n                        if (closest)\n                        {\n                            Targeting.TargetClosestFriend();\n                        }\n                        else if (random)\n                        {\n                            Targeting.TargetRandFriend();\n                        }\n                        else if (next)\n                        {\n                            Targeting.NextTargetFriend();\n                        }\n                        else\n                        {\n                            Targeting.PrevTargetFriend();\n                        }\n\n                        break;\n                    case \"friendly\":\n                        if (args.Length == 3)\n                        {\n                            if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseFriendlyHumanoid();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandFriendlyHumanoid();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetFriendlyHumanoid();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetFriendlyHumanoid();\n                                }\n                            }\n                            else if (args[2].AsString()\n                                .IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseFriendlyMonster();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandFriendlyMonster();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetFriendlyMonster();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetFriendlyMonster();\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (closest)\n                            {\n                                Targeting.TargetCloseFriendly();\n                            }\n                            else if (random)\n                            {\n                                Targeting.TargetRandFriendly();\n                            }\n                        }\n\n                        break;\n                    case \"gray\":\n                    case \"grey\":\n                        if (args.Length == 3)\n                        {\n                            if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseGreyHumanoid();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandGreyHumanoid();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetGreyHumanoid();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetGreyHumanoid();\n                                }\n                            }\n                            else if (args[2].AsString()\n                                .IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseGreyMonster();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandGreyMonster();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetGreyMonster();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetGreyMonster();\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (closest)\n                            {\n                                Targeting.TargetCloseGrey();\n                            }\n                            else if (random)\n                            {\n                                Targeting.TargetRandGrey();\n                            }\n                        }\n\n                        break;\n                    case \"criminal\":\n                        if (args.Length == 3)\n                        {\n                            if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseCriminalHumanoid();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandCriminalHumanoid();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetCriminalHumanoid();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetCriminalHumanoid();\n                                }\n                            }\n                            else if (args[2].AsString()\n                                .IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseCriminalMonster();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandCriminalMonster();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetCriminalMonster();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetCriminalMonster();\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (closest)\n                            {\n                                Targeting.TargetCloseCriminal();\n                            }\n                            else if (random)\n                            {\n                                Targeting.TargetRandCriminal();\n                            }\n                        }\n\n                        break;\n                    case \"blue\":\n                    case \"innocent\":\n                        if (args.Length == 3)\n                        {\n                            if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseInnocentHumanoid();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandInnocentHumanoid();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetInnocentHumanoid();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetInnocentHumanoid();\n                                }\n                            }\n                            else if (args[2].AsString()\n                                .IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseInnocentMonster();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandInnocentMonster();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetInnocentMonster();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetInnocentMonster();\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (closest)\n                            {\n                                Targeting.TargetCloseInnocent();\n                            }\n                            else if (random)\n                            {\n                                Targeting.TargetRandInnocent();\n                            }\n                        }\n\n                        break;\n                    case \"red\":\n                    case \"murderer\":\n                        if (args.Length == 3)\n                        {\n                            if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseRedHumanoid();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandRedHumanoid();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetMurdererHumanoid();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetMurdererHumanoid();\n                                }\n                            }\n                            else if (args[2].AsString()\n                                .IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseRedMonster();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandRedMonster();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetMurdererMonster();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetMurdererMonster();\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (closest)\n                            {\n                                Targeting.TargetCloseRed();\n                            }\n                            else if (random)\n                            {\n                                Targeting.TargetRandRed();\n                            }\n                        }\n\n                        break;\n                    case \"nonfriendly\":\n                        if (args.Length == 3)\n                        {\n                            if (args[2].AsString().IndexOf(\"human\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseNonFriendlyHumanoid();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandNonFriendlyHumanoid();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetNonFriendlyHumanoid();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetNonFriendlyHumanoid();\n                                }\n                            }\n                            else if (args[2].AsString()\n                                .IndexOf(\"monster\", StringComparison.OrdinalIgnoreCase) != -1)\n                            {\n                                if (closest)\n                                {\n                                    Targeting.TargetCloseNonFriendlyMonster();\n                                }\n                                else if (random)\n                                {\n                                    Targeting.TargetRandNonFriendlyMonster();\n                                }\n                                else if (next)\n                                {\n                                    Targeting.NextTargetNonFriendlyMonster();\n                                }\n                                else\n                                {\n                                    Targeting.PrevTargetNonFriendlyMonster();\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (closest)\n                            {\n                                Targeting.TargetCloseNonFriendly();\n                            }\n                            else if (random)\n                            {\n                                Targeting.TargetRandNonFriendly();\n                            }\n                        }\n\n                        break;\n                    default:\n                        throw new RunTimeError($\"Unknown target type: '{args[1].AsString()}'\");\n                }\n            }\n        }\n        \n        public static string ReplaceStringInterpolations(string stringWithPossibleInterpolation)\n        {\n            Regex regex = new Regex(@\"\\{{(.*?)\\}}\");\n            return regex.Replace(stringWithPossibleInterpolation, match =>\n            {\n                string varName = match.Groups[1].Value;\n                Variable varContent = Interpreter.GetVariable(varName);\n\n                return varContent?.AsString() ?? \"<not found>\";\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Scripts/RazorScript.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Assistant.Scripts\n{\n    public sealed class RazorScript\n    {\n        public string Path { get; set; }\n        public string[] Lines { get; set; }\n        public string Name { get; set; }\n        public string Category { get; set; }\n\n        public override string ToString()\n        {\n            return string.IsNullOrEmpty(Category) ? Name : $\"{Category}\\\\{Name}\";\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Scripts/ScriptManager.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\nusing System.Windows.Forms;\nusing Assistant.Gumps.Internal;\nusing Assistant.Macros;\nusing Assistant.Scripts.Engine;\nusing Assistant.UI;\nusing FastColoredTextBoxNS;\n\nnamespace Assistant.Scripts\n{\n    public static class ScriptManager\n    {\n        public static bool Recording { get; set; }\n\n        public static bool Paused => ScriptPaused;\n\n        private static bool ScriptPaused { get; set; }\n\n        public static bool Running => ScriptRunning;\n\n        private static bool ScriptRunning { get; set; }\n\n        public static DateTime LastWalk { get; set; }\n\n        public static bool SetVariableActive { get; set; }\n        \n        public static bool TargetFound { get; set; }\n\n        public static string ScriptPath => Config.GetUserDirectory(\"Scripts\");\n\n        private static FastColoredTextBox ScriptEditor { get; set; }\n\n        private static TreeView ScriptTree { get; set; }\n\n        private static ListBox ScriptVariableList { get; set; }\n\n        private static Script _queuedScript;\n\n        private static string _queuedScriptName;\n\n        public static bool BlockPopupMenu { get; set; }\n\n        private static bool EnableHighlight { get; set; }\n\n        public enum HighlightType\n        {\n            Error,\n            Execution\n        }\n\n        private static Dictionary<HighlightType, List<int>> HighlightLines { get; } = new Dictionary<HighlightType, List<int>>();\n\n        private static Dictionary<HighlightType, Brush> HighlightLineColors { get; } = new Dictionary<HighlightType, Brush>()\n        {\n            { HighlightType.Error, new SolidBrush(Color.Red) },\n            { HighlightType.Execution, new SolidBrush(Color.Blue) }\n        };\n\n        private static HighlightType[] GetHighlightTypes()\n        {\n            return (HighlightType[])Enum.GetValues(typeof(HighlightType));\n        }\n\n        public static RazorScript SelectedScript { get; set; }\n\n        private static Stopwatch Stopwatch { get; } = new Stopwatch();\n        \n        private class ScriptTimer : Timer\n        {\n            // Only run scripts once every 25ms to avoid spamming.\n            public ScriptTimer(int delay) : base(TimeSpan.FromMilliseconds(delay), TimeSpan.FromMilliseconds(delay))\n            {\n            }\n\n            protected override void OnTick()\n            {\n                try\n                {\n                    if (!Client.Instance.ClientRunning)\n                    {\n                        if (ScriptRunning)\n                        {\n                            ScriptRunning = false;\n                            Interpreter.StopScript();\n                        }\n\n                        return;\n                    }\n\n                    bool running;\n\n                    if (_queuedScript != null)\n                    {\n                        // Starting a new script. This relies on the atomicity for references in CLR\n                        Script script = _queuedScript;\n\n                        running = Interpreter.StartScript(script);\n                        UpdateLineNumber(Interpreter.CurrentLine);\n\n                        _queuedScript = null;\n                    }\n                    else\n                    {\n                        running = Interpreter.ExecuteScript();\n\n                        if (running)\n                        {\n                            UpdateLineNumber(Interpreter.CurrentLine);\n                        }\n                    }\n\n\n                    if (running)\n                    {\n                        if (ScriptManager.Running == false)\n                        {\n                            if (!Config.GetBool(\"ScriptDisablePlayFinish\"))\n                            {\n                                if (!Config.GetBool(\"DisableScriptStopwatch\"))\n                                {\n                                    Stopwatch.Start();    \n                                }\n                                \n                                World.Player?.SendMessage(LocString.ScriptPlaying, _queuedScriptName);\n                            }\n\n                            Assistant.Engine.MainWindow.LockScriptUI(true);\n                            ScriptRunning = true;\n                        }\n                    }\n                    else\n                    {\n                        if (ScriptManager.Running)\n                        {\n                            if (!Config.GetBool(\"ScriptDisablePlayFinish\"))\n                            {\n                                if (!Config.GetBool(\"DisableScriptStopwatch\"))\n                                {\n                                    Stopwatch.Stop();\n                                    TimeSpan elapsed = Stopwatch.Elapsed;\n                                    Stopwatch.Reset();\n                                \n                                    World.Player?.SendMessage(LocString.ScriptFinishedStopwatch, _queuedScriptName, elapsed.TotalMilliseconds);    \n                                }\n                                else\n                                {\n                                    World.Player?.SendMessage(LocString.ScriptFinished, _queuedScriptName);\n                                }\n                                \n                            }\n\n                            Assistant.Engine.MainWindow.LockScriptUI(false);\n                            ScriptRunning = false;\n\n                            ClearHighlightLine(HighlightType.Execution);\n                        }\n                    }\n                }\n                catch (Exception ex)\n                {\n                    World.Player?.SendMessage(MsgLevel.Error, $\"Script Error: {ex.Message} (Line: {Interpreter.CurrentLine + 1})\");\n\n                    if (EnableHighlight)\n                    {\n                        SetHighlightLine(Interpreter.CurrentLine, HighlightType.Error);\n                    }\n\n                    StopScript();\n                }\n            }\n        }\n\n        /// <summary>\n        /// This is called via reflection when the application starts up\n        /// </summary>\n        public static void Initialize()\n        {\n            HotKey.Add(HKCategory.Scripts, HKSubCat.None, LocString.StopScript, HotkeyStopScript);\n            HotKey.Add(HKCategory.Scripts, HKSubCat.None, LocString.PauseScript, HotkeyPauseScript);\n            HotKey.Add(HKCategory.Scripts, HKSubCat.None, LocString.ScriptDClickType, HotkeyDClickTypeScript);\n            HotKey.Add(HKCategory.Scripts, HKSubCat.None, LocString.ScriptTargetType, HotkeyTargetTypeScript);\n\n\n            _scriptList = new List<RazorScript>();\n\n            Recurse(null, Config.GetUserDirectory(\"Scripts\"));\n            \n            foreach (HighlightType type in GetHighlightTypes())\n            {\n                HighlightLines[type] = new List<int>();\n            }\n\n            Lexer.AllowLoop = Client.Instance.AllowBit(FeatureBit.LoopingMacros);\n        }\n\n        private static void HotkeyTargetTypeScript()\n        {\n            if (World.Player != null)\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.ScriptTargetType);\n                Targeting.OneTimeTarget(OnTargetTypeScript);\n            }\n        }\n\n        private static void OnTargetTypeScript(bool loc, Serial serial, Point3D pt, ushort itemId)\n        {\n            Item item = World.FindItem(serial);\n\n            if (item != null && item.Serial.IsItem && item.Movable && item.Visible)\n            {\n                string cmd = $\"targettype '{item.ItemID.ItemData.Name}'\";\n\n                Clipboard.SetDataObject(cmd);\n                World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, cmd), false);\n            }\n            else\n            {\n                Mobile m = World.FindMobile(serial);\n\n                if (m != null)\n                {\n                    string cmd = $\"targettype '{m.Body}'\";\n\n                    Clipboard.SetDataObject(cmd);\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, cmd), false);\n                }\n            }\n        }\n\n        private static void HotkeyDClickTypeScript()\n        {\n            if (World.Player != null)\n            {\n                World.Player.SendMessage(MsgLevel.Force, LocString.ScriptTargetType);\n                Targeting.OneTimeTarget(OnDClickTypeScript);\n            }\n        }\n\n        private static void OnDClickTypeScript(bool loc, Serial serial, Point3D pt, ushort itemId)\n        {\n            Item item = World.FindItem(serial);\n\n            if (item != null && item.Serial.IsItem && item.Movable && item.Visible)\n            {\n                string cmd = $\"dclicktype '{item.ItemID.ItemData.Name}'\";\n\n                Clipboard.SetDataObject(cmd);\n                World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, cmd), false);\n            }\n            else\n            {\n                Mobile m = World.FindMobile(serial);\n\n                if (m != null)\n                {\n                    string cmd = $\"dclicktype '{m.Body}'\";\n\n                    Clipboard.SetDataObject(cmd);\n                    World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ScriptCopied, cmd), false);\n                }\n            }\n        }\n\n        private static void HotkeyStopScript()\n        {\n            StopScript();\n        }\n\n        private static void HotkeyPauseScript()\n        {\n            if (!ScriptRunning)\n            {\n                return;\n            }\n\n            if (ScriptPaused)\n            {\n                ResumeScript();\n                World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.ResumeScriptMessage, Interpreter.CurrentLine), false);\n            }\n            else\n            {\n                World.Player.SendMessage(MsgLevel.Force, Language.Format(LocString.PauseScriptMessage, Interpreter.CurrentLine), false);\n                PauseScript();\n            }\n        }\n\n        private static void AddHotkey(RazorScript script)\n        {\n            HotKey.Add(HKCategory.Scripts, HKSubCat.None, Language.Format(LocString.PlayScript, script), OnHotKey,\n                script);\n        }\n\n        private static void RemoveHotkey(RazorScript script)\n        {\n            HotKey.Remove(Language.Format(LocString.PlayScript, script.ToString()));\n        }\n\n        public static void OnHotKey(ref object state)\n        {\n            RazorScript script = (RazorScript) state;\n            \n            PlayScript(script.Lines, script.Name);\n        }\n\n        public static void StopScript()\n        {\n            _queuedScript = null;\n            ScriptPaused = false;\n\n            Interpreter.StopScript();\n        }\n\n        public static void PauseScript()\n        {\n            ScriptPaused = true;\n            Interpreter.PauseScript();\n        }\n\n        public static void ResumeScript()\n        {\n            ScriptPaused = false;\n            Interpreter.ResumeScript();\n        }\n\n        public static RazorScript AddScript(string file)\n        {\n            RazorScript script = new RazorScript\n            {\n                Lines = File.ReadAllLines(file),\n                Name = Path.GetFileNameWithoutExtension(file),\n                Path = file\n            };\n\n            if (Path.GetDirectoryName(script.Path).Equals(Config.GetUserDirectory(\"Scripts\")))\n            {\n                script.Category = string.Empty;\n            }\n            else\n            {\n                string cat = file.Replace(Config.GetUserDirectory(\"Scripts\"), \"\").Substring(1);\n                script.Category = Path.GetDirectoryName(cat).Replace(\"/\", \"\\\\\");\n            }\n\n            AddHotkey(script);\n\n            _scriptList.Add(script);\n\n            return script;\n        }\n\n        public static void RemoveScript(RazorScript script)\n        {\n            RemoveHotkey(script);\n\n            _scriptList.Remove(script);\n        }\n        \n        public static void PlayScript(string scriptName)\n        {\n            foreach (RazorScript razorScript in _scriptList)\n            {\n                if (razorScript.ToString().IndexOf(scriptName, StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    PlayScript(razorScript.Lines, scriptName);\n                    break;\n                }\n            }\n        }\n\n        public static void PlayScript(string[] lines, string name)\n        {\n            if (World.Player == null || lines == null)\n                return;\n\n            if (MacroManager.Playing || MacroManager.StepThrough)\n                MacroManager.Stop();\n\n            StopScript();\n            \n            EnableHighlight = false;\n            \n            SetVariableActive = false;\n\n            if (_queuedScript != null)\n                return;\n\n            if (!Client.Instance.ClientRunning)\n                return;\n\n            try\n            {\n                Script script = new Script(Lexer.Lex(lines));\n                \n                _queuedScript = script;\n                _queuedScriptName = name;\n            }\n            catch (SyntaxError syntaxError)\n            {\n                World.Player.SendMessage(MsgLevel.Error, $\"{syntaxError.Message}: '{syntaxError.Line}' (Line #{syntaxError.LineNumber + 1})\");\n            }\n        }\n        \n        public static void PlayScriptFromUI(string[] lines, string name, bool highlight)\n        {\n            if (World.Player == null || ScriptEditor == null || lines == null)\n                return;\n\n            EnableHighlight = highlight;\n\n            if (EnableHighlight)\n            {\n                ClearAllHighlightLines();\n            }\n\n            if (MacroManager.Playing || MacroManager.StepThrough)\n                MacroManager.Stop();\n\n            StopScript(); // be sure nothing is running\n            \n            SetVariableActive = false;\n\n            if (_queuedScript != null)\n                return;\n\n            if (!Client.Instance.ClientRunning)\n                return;\n\n            try\n            {\n                Script script = new Script(Lexer.Lex(lines));\n                \n                _queuedScript = script;\n                _queuedScriptName = name;\n            }\n            catch (SyntaxError syntaxError)\n            {\n                World.Player.SendMessage(MsgLevel.Error, $\"{syntaxError.Message}: '{syntaxError.Line}' (Line #{syntaxError.LineNumber + 1})\");\n\n                if (EnableHighlight)\n                {\n                    SetHighlightLine(syntaxError.LineNumber, HighlightType.Error);\n                }\n            }\n        }\n\n        /*private static void ActiveScriptStatementExecuted(ASTNode statement)\n        {\n            if (EnableHighlight && statement != null)\n            {\n                var lineNum = statement.LineNumber;\n\n                SetHighlightLine(lineNum, HighlightType.Execution);\n                // Scrolls to relevant line, per this suggestion: https://github.com/PavelTorgashov/FastColoredTextBox/issues/115\n                ScriptEditor.Selection.Start = new Place(0, lineNum);\n                ScriptEditor.DoSelectionVisible();\n            }\n        }*/\n\n        private static ScriptTimer Timer { get; set; }\n\n        static ScriptManager()\n        {\n            Timer = new ScriptTimer(Config.GetBool(\"DefaultScriptDelay\") ? 25 : 0);\n        }\n\n        public static void ResetTimer()\n        {\n            Timer.Stop();\n            Timer = new ScriptTimer(Config.GetBool(\"DefaultScriptDelay\") ? 25 : 0);\n            Timer.Start();\n        }\n\n        private static void UpdateLineNumber(int lineNum)\n        {\n            if (EnableHighlight)\n            {\n                SetHighlightLine(lineNum, HighlightType.Execution);\n                // Scrolls to relevant line, per this suggestion: https://github.com/PavelTorgashov/FastColoredTextBox/issues/115\n                ScriptEditor.Selection.Start = new Place(0, lineNum);\n                ScriptEditor.DoSelectionVisible();\n            }\n        }\n\n        public static void SetEditor(FastColoredTextBox scriptEditor)\n        {\n            ScriptEditor = scriptEditor;\n\n            InitScriptEditor();\n\n            if (SelectedScript != null)\n            {\n                SetEditorText(SelectedScript);\n            }\n        }\n\n        public static void SetEditorText(RazorScript selectedScript)\n        {\n            SelectedScript = selectedScript;\n\n            ScriptEditor.Text = string.Join(\"\\n\", SelectedScript.Lines);\n        }\n\n        public static void SetControls(FastColoredTextBox scriptEditor, TreeView scriptTree, ListBox scriptVariables)\n        {\n            ScriptEditor = scriptEditor;\n            ScriptTree = scriptTree;\n            ScriptVariableList = scriptVariables;\n        }\n\n        public static void OnLogin()\n        {\n            Commands.Register();\n            AgentCommands.Register();\n            SpeechCommands.Register();\n            TargetCommands.Register();\n\n            Aliases.Register();\n            Expressions.Register();\n\n            Timer.Start();\n        }\n\n        public static void OnLogout()\n        {\n            StopScript();\n            Timer.Stop();\n            Assistant.Engine.MainWindow.LockScriptUI(false);\n        }\n\n        public static void StartEngine()\n        {\n            Timer.Start();\n        }\n\n        private static List<RazorScript> _scriptList { get; set; }\n\n        public static void RedrawScriptVariables()\n        {\n            ScriptVariableList?.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Items.Clear();\n\n                foreach (KeyValuePair<string, Serial> variable in ScriptVariables.Variables)\n                {\n                    s.Items.Add($\"{variable.Key} ({variable.Value})\");\n                }\n\n                s.EndUpdate();\n                s.Refresh();\n                s.Update();\n            });\n        }\n\n        public static bool AddToScript(string command)\n        {\n            if (Recording)\n            {\n                ScriptEditor?.AppendText(command + Environment.NewLine);\n\n                return true;\n            }\n\n            return false;\n        }\n\n        private static int GetScriptIndex(string script)\n        {\n            for (int i = 0; i < _scriptList.Count; i++)\n            {\n                if (_scriptList[i].Name.Equals(script, StringComparison.OrdinalIgnoreCase))\n                    return i;\n            }\n\n            return -1;\n        }\n\n        public static void Error(bool quiet, string statement, string message, bool throwError = false)\n        {\n            if (quiet)\n                return;\n\n            World.Player?.SendMessage(MsgLevel.Error, $\"{statement}: {message}\");\n        }\n\n        public static List<ASTNode> ParseArguments(ref ASTNode node)\n        {\n            List<ASTNode> args = new List<ASTNode>();\n            while (node != null)\n            {\n                args.Add(node);\n                node = node.Next();\n            }\n\n            return args;\n        }\n\n        private delegate void SetHighlightLineDelegate(int iline, Color color);\n\n        /// <summary>\n        /// Adds a new highlight of specified type\n        /// </summary>\n        /// <param name=\"iline\">Line number to highlight</param>\n        /// <param name=\"type\">Type of highlight to set</param>\n        private static void AddHighlightLine(int iline, HighlightType type)\n        {\n            HighlightLines[type].Add(iline);\n            RefreshHighlightLines();\n        }\n\n        /// <summary>\n        /// Clears existing highlight lines of this type, and adds a new one at specified line number\n        /// </summary>\n        /// <param name=\"iline\">Line number to highlight</param>\n        /// <param name=\"type\">Type of highlight to set</param>\n        private static void SetHighlightLine(int iline, HighlightType type)\n        {\n            ClearHighlightLine(type);\n            AddHighlightLine(iline, type);\n        }\n\n        public static void ClearHighlightLine(HighlightType type)\n        {\n            HighlightLines[type].Clear();\n            RefreshHighlightLines();\n        }\n\n        public static void ClearAllHighlightLines()\n        {\n            foreach (HighlightType type in GetHighlightTypes())\n            {\n                HighlightLines[type].Clear();\n            }\n\n            RefreshHighlightLines();\n        }\n\n        private static void RefreshHighlightLines()\n        {\n            for (int i = 0; i < ScriptEditor.LinesCount; i++)\n            {\n                ScriptEditor[i].BackgroundBrush = ScriptEditor.BackBrush;\n            }\n\n            foreach (HighlightType type in GetHighlightTypes())\n            {\n                foreach (int lineNum in HighlightLines[type])\n                {\n                    ScriptEditor[lineNum].BackgroundBrush = HighlightLineColors[type];\n                }\n            }\n\n            ScriptEditor.Invalidate();\n        }\n\n        private static FastColoredTextBoxNS.AutocompleteMenu _autoCompleteMenu;\n\n        public static void InitScriptEditor()\n        {\n            _autoCompleteMenu = new AutocompleteMenu(ScriptEditor)\n            {\n                SearchPattern = @\"[\\w\\.:=!<>]\",\n                AllowTabKey = true,\n                ToolTipDuration = 5000,\n                AppearInterval = 100\n            };\n\n            #region Keywords\n\n            string[] keywords =\n            {\n                    \"if\", \"elseif\", \"else\", \"endif\", \"while\", \"endwhile\", \"for\", \"endfor\", \"break\", \"continue\", \"stop\",\n                    \"replay\", \"not\", \"and\", \"or\"\n                };\n\n            #endregion\n\n            #region Commands auto-complete\n\n            string[] commands =\n            {\n                \"alliance\", \"clearall\", \"cleardragdrop\", \"clearhands\", \"emote\", \"guild\", \"attack\", \"interrupt\", \"virtue\", \"yell\",\n                \"cast\", \"dclick\", \"dclicktype\",\n                \"dress\", \"drop\", \"droprelloc\", \"gumpresponse\", \"gumpclose\", \"hotkey\", \"lasttarget\", \"lift\", \"lifttype\",\n                \"menu\", \"menuresponse\", \"organizer\", \"overhead\", \"potion\", \"promptresponse\", \"restock\", \"say\",\n                \"whisper\", \"yell\", \"emote\", \"script\", \"scavenger\", \"sell\", \"setability\", \"setlasttarget\", \"setvar\",\n                \"skill\", \"sysmsg\", \"target\", \"targettype\", \"targetrelloc\", \"undress\", \"useonce\", \"walk\", \"wait\",\n                \"pause\", \"waitforgump\", \"waitformenu\", \"waitforprompt\", \"waitfortarget\", \"waitforsysmsg\", \"clearsysmsg\", \"clearjournal\",\n                \"waitforsysmsg\", \"random\"\n            };\n\n            #endregion\n\n            Dictionary<string, ToolTipDescriptions> descriptionCommands = new Dictionary<string, ToolTipDescriptions>();\n\n            #region CommandToolTips\n\n            var tooltip = new ToolTipDescriptions(\"attack\", new[] { \"attack (serial) or attack ('variablename')\" },\n                \"N/A\", \"Attack a specific serial or variable tied to a serial.\", \"attack 0x2AB4\\n\\tattack 'attackdummy'\");\n            descriptionCommands.Add(\"attack\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"clearall\", new[] { \"clearall\" }, \"N/A\", \"Clear target, clear queues, drop anything you're holding\",\n                \"clearall\");\n            descriptionCommands.Add(\"clearall\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"clearhands\", new[] { \"clearhands ('right'/'left'/'hands')\" }, \"N/A\", \"Use the item in your hands\",\n                \"clearhands\");\n            descriptionCommands.Add(\"clearhands\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"virtue\", new[] { \"virtue ('honor'/'sacrifice'/'valor')\" }, \"N/A\", \"Invoke a specific virtue\",\n                \"virtue 'honor'\");\n            descriptionCommands.Add(\"virtue\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"cast\", new[] { \"cast ('name of spell')\" }, \"N/A\", \"Cast a spell by name\",\n                \"cast 'blade spirits'\");\n            descriptionCommands.Add(\"cast\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"dclick\", new[] { \"dclick (serial) or useobject (serial)\" }, \"N/A\",\n                \"This command will use (double-click) a specific item or mobile.\", \"dclick 0x34AB\");\n            descriptionCommands.Add(\"dclick\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"dclicktype\",\n                new[]\n                {\n                        \"dclicktype ('name of item') OR (graphicID) [inrange] or usetype ('name of item') OR (graphicID) [inrange/backpack] [hue]\"\n                }, \"N/A\",\n                \"This command will use (double-click) an item type either provided by the name or the graphic ID.\\n\\t\\tIf you include the optional true parameter, items within range (2 tiles) will only be considered.\",\n                \"dclicktype 'dagger'\\n\\t\\twaitfortarget\\n\\t\\ttargettype 'robe'\");\n            descriptionCommands.Add(\"dclicktype\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"dress\", new[] { \"dress ('name of dress list')\" }, \"N/A\",\n                \"This command will execute a spec dress list you have defined in Razor.\", \"dress 'My Sunday Best'\");\n            descriptionCommands.Add(\"dress\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"drop\", new[] { \"drop (serial) (x/y/z/layername)\" }, \"N/A\",\n                \"This command will drop the item you are holding either at your feet,\\n\\t\\ton a specific layer or at a specific X / Y / Z location.\",\n                \"lift 0x400D54A7 1\\n\\t\\tdrop 0x6311 InnerTorso\");\n            descriptionCommands.Add(\"drop\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"\", new[] { \"\" }, \"N/A\", \"\",\n                \"lift 0x400D54A7 1\\n\\twait 5000\\n\\tdrop 0xFFFFFFFF 5926 1148 0\");\n            descriptionCommands.Add(\"\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"droprelloc\", new[] { \"droprelloc (x) (y)\" }, \"N/A\",\n                \"This command will drop the item you're holding to a location relative to your position.\",\n                \"lift 0x400EED2A 1\\n\\twait 1000\\n\\tdroprelloc 1 1\");\n            descriptionCommands.Add(\"droprelloc\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"gumpresponse\", new[] { \"gumpresponse (buttonID)\" }, \"N/A\",\n                \"Responds to a specific gump button\", \"gumpresponse 4\");\n            descriptionCommands.Add(\"gumpresponse\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"gumpclose\", new[] { \"gumpclose\" }, \"N/A\",\n                \"This command will close the last gump that opened.\", \"gumpclose\");\n            descriptionCommands.Add(\"gumpclose\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"hotkey\", new[] { \"hotkey ('name of hotkey')\" }, \"N/A\",\n                \"This command will execute any Razor hotkey by name.\",\n                \"skill 'detect hidden'\\n\\twaitfortarget\\n\\thotkey 'target self'\");\n            descriptionCommands.Add(\"hotkey\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"lasttarget\", new[] { \"lasttarget\" }, \"N/A\",\n                \"This command will target your last target set in Razor.\",\n                \"cast 'magic arrow'\\n\\twaitfortarget\\n\\tlasttarget\");\n            descriptionCommands.Add(\"lasttarget\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"lift\", new[] { \"lift (serial) [amount]\" }, \"N/A\",\n                \"This command will lift a specific item and amount. If no amount is provided, 1 is defaulted.\",\n                \"lift 0x400EED2A 1\\n\\twait 1000\\n\\tdroprelloc 1 1 0\");\n            descriptionCommands.Add(\"lift\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"lifttype\",\n                new[] { \"lifttype (gfx) [amount] or lifttype ('name of item') [amount] [hue]\" }, \"N/A\",\n                \"This command will lift a specific item by type either by the graphic id or by the name.\\n\\tIf no amount is provided, 1 is defaulted.\",\n                \"lifttype 'robe'\\n\\twait 1000\\n\\tdroprelloc 1 1 0\\n\\tlifttype 0x1FCD\\n\\twait 1000\\n\\tdroprelloc 1 1\");\n            descriptionCommands.Add(\"lifttype\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"menu\", new[] { \"menu (serial) (index) [false]\" }, \"N/A\",\n                \"Selects a specific index within a context menu\", \"# open backpack\\n\\tmenu 0 1\");\n            descriptionCommands.Add(\"menu\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"menuresponse\", new[] { \"menuresponse (index) (menuId) [hue]\" }, \"N/A\",\n                \"Responds to a specific menu and menu ID (not a context menu)\", \"menuresponse 3 4\");\n            descriptionCommands.Add(\"menuresponse\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"organizer\", new[] { \"organizer (number) ['set']\" }, \"N/A\",\n                \"This command will execute a specific organizer agent. If the set parameter is included,\\n\\tyou will instead be prompted to set the organizer agent's hotbag.\",\n                \"organizer 1\\n\\torganizer 4 'set'\");\n            descriptionCommands.Add(\"organizer\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"overhead\", new[] { \"overhead ('text') [color] [serial]\" }, \"N/A\",\n                \"This command will display a message over your head. Only you can see this.\",\n                \"if stam = 100\\n\\t    overhead 'ready to go!'\\n\\tendif\");\n            descriptionCommands.Add(\"overhead\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"potion\", new[] { \"potion ('potion type')\" }, \"N/A\",\n                \"This command will use a specific potion based on the type.\", \"potion 'agility'\\n\\tpotion 'heal'\");\n            descriptionCommands.Add(\"potion\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"promptresponse\", new[] { \"promptresponse ('prompt response')\" }, \"N/A\",\n                \"This command will respond to a prompt triggered from actions such as renaming runes or giving a guild title.\",\n                \"dclicktype 'rune'\\n\\twaitforprompt\\n\\tpromptresponse 'to home'\");\n            descriptionCommands.Add(\"promptresponse\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"restock\", new[] { \"restock (number) ['set']\" }, \"N/A\",\n                \"This command will execute a specific restock agent.\\n\\tIf the set parameter is included, you will instead be prompted to set the restock agent's hotbag.\",\n                \"restock 1\\n\\trestock 4 'set'\");\n            descriptionCommands.Add(\"restock\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"say\",\n                new[] { \"say ('message to send') [hue] or msg ('message to send') [hue]\" }, \"N/A\",\n                \"This command will force your character to say the message passed as the parameter.\",\n                \"say 'Hello world!'\\n\\tsay 'Hello world!' 454\");\n            descriptionCommands.Add(\"say\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"whisper\",\n                new[] { \"whisper ('message to send') [hue]\" }, \"N/A\",\n                \"This command will force your character to whisper the message passed as the parameter.\",\n                \"whisper 'Hello world!'\\n\\twhisper 'Hello world!' 454\");\n            descriptionCommands.Add(\"whisper\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"yell\",\n                new[] { \"yell ('message to send') [hue]\" }, \"N/A\",\n                \"This command will force your character to yell the message passed as the parameter.\",\n                \"yell 'Hello world!'\\n\\tyell 'Hello world!' 454\");\n            descriptionCommands.Add(\"yell\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"emote\",\n                new[] { \"emote ('message to send') [hue]\" }, \"N/A\",\n                \"This command will force your character to emote the message passed as the parameter.\",\n                \"emote 'Hello world!'\\n\\temote 'Hello world!' 454\");\n            descriptionCommands.Add(\"emote\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"script\", new[] { \"script 'name'\" }, \"N/A\",\n                \"This command will call another script.\", \"if hp = 40\\n\\t   script 'healself'\\n\\tendif\");\n            descriptionCommands.Add(\"script\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"scavenger\", new[] { \"scavenger ['clear'/'add'/'on'/'off'/'set']\" },\n                \"N/A\", \"This command will control the scavenger agent.\", \"scavenger 'off'\");\n            descriptionCommands.Add(\"scavenger\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"sell\", new[] { \"sell\" }, \"N/A\",\n                \"This command will set the Sell agent's hotbag.\", \"sell\");\n            descriptionCommands.Add(\"sell\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"setability\",\n                new[] { \"setability ('primary'/'secondary'/'stun'/'disarm') ['on'/'off']\" }, \"N/A\",\n                \"This will set a specific ability on or off. If on or off is missing, on is defaulted.\",\n                \"setability stun\");\n            descriptionCommands.Add(\"setability\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"setlasttarget\", new[] { \"setlasttarget\" }, \"N/A\",\n                \"This command will pause the script until you select a target to be set as Last Target.\",\n                \"overhead 'set last target'\\n\\tsetlasttarget\\n\\toverhead 'set!'\\n\\tcast 'magic arrow'\\n\\twaitfortarget\\n\\ttarget 'last'\");\n            descriptionCommands.Add(\"setlasttarget\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"setvar\", new[] { \"setvar ('variable') or setvariable ('variable')\" },\n                \"N/A\",\n                \"This command will pause the script until you select a target to be assigned a variable.\\n\\tPlease note, the variable must exist before you can assign values to it.\",\n                \"setvar 'dummy'\\n\\tcast 'magic arrow'\\n\\twaitfortarget\\n\\ttarget 'dummy'\");\n            descriptionCommands.Add(\"setvar\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"skill\", new[] { \"skill 'name of skill' or skill last\" }, \"N/A\",\n                \"This command will use a specific skill (assuming it's a usable skill).\",\n                \"while mana < maxmana\\n\\t    say 'mediation!'\\n\\t    skill 'meditation'\\n\\t    wait 11000\\n\\tendwhile\");\n            descriptionCommands.Add(\"skill\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"sysmsg\", new[] { \"sysmsg ('message to display in system message')\" },\n                \"N/A\", \"This command will display a message in the lower-left of the client.\",\n                \"if stam = 100\\n\\t    sysmsg 'ready to go!'\\n\\tendif\");\n            descriptionCommands.Add(\"sysmsg\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"target\", new[] { \"target (serial) or target (x) (y) (z)\" }, \"N/A\",\n                \"This command will target a specific mobile or item or target a specific location based on X/Y/Z coordinates.\",\n                \"cast 'lightning'\\n\\twaitfortarget\\n\\ttarget 0xBB3\\n\\tcast 'fire field'\\n\\twaitfortarget\\n\\ttarget 5923 1145 0\");\n            descriptionCommands.Add(\"target\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"targettype\",\n                new[] { \"targettype (graphic) or targettype ('name of item or mobile type') [inrangecheck/backpack] [hue]\" }, \"N/A\",\n                \"This command will target a specific type of mobile or item based on the graphic id or based on\\n\\tthe name of the item or mobile. If the optional parameter is passed\\n\\tin as true only items within the range of 2 tiles will be considered.\",\n                \"usetype 'dagger'\\n\\twaitfortarget\\n\\ttargettype 'robe'\\n\\tuseobject 0x4005ECAF\\n\\twaitfortarget\\n\\ttargettype 0x1f03\\n\\tuseobject 0x4005ECAF\\n\\twaitfortarget\\n\\ttargettype 0x1f03 true\");\n            descriptionCommands.Add(\"targettype\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"targetrelloc\", new[] { \"targetrelloc (x-offset) (y-offset)\" }, \"N/A\",\n                \"This command will target a specific location on the map relative to your position.\",\n                \"cast 'fire field'\\n\\twaitfortarget\\n\\ttargetrelloc 1 1\");\n            descriptionCommands.Add(\"targetrelloc\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"undress\",\n                new[] { \"undress ['name of dress list']' or undress 'LayerName'\" }, \"N/A\",\n                \"This command will either undress you completely if no dress list is provided.\\n\\tIf you provide a dress list, only those specific items will be undressed. Lastly, you can define a layer name to undress.\",\n                \"undress\\n\\tundress 'My Sunday Best'\\n\\tundress 'Shirt'\\n\\tundrsss 'Pants'\");\n            descriptionCommands.Add(\"undress\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"useonce\", new[] { \"useonce ['add'/'addcontainer']\" }, \"N/A\",\n                \"This command will execute the UseOnce agent. If the add parameter is included, you can add items to your UseOnce list.\\n\\tIf the addcontainer parameter is included, you can add all items in a container to your UseOnce list.\",\n                \"useonce\\n\\tuseonce 'add'\\n\\tuseonce 'addcontainer'\");\n            descriptionCommands.Add(\"useonce\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"walk\", new[] { \"walk ('direction')\" }, \"N/A\",\n                \"This command will turn and/or walk your player in a certain direction.\",\n                \"walk 'North'\\n\\twalk 'Up'\\n\\twalk 'West'\\n\\twalk 'Left'\\n\\twalk 'South'\\n\\twalk 'Down'\\n\\twalk 'East'\\n\\twalk 'Right'\");\n            descriptionCommands.Add(\"walk\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"wait\",\n                new[] { \"wait [time in milliseconds or pause [time in milliseconds]\" }, \"N/A\",\n                \"This command will pause the execution of a script for a given time.\",\n                \"while stam < 100\\n\\t    wait 5000\\n\\tendwhile\");\n            descriptionCommands.Add(\"wait\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"pause\",\n                new[] { \"pause [time in milliseconds or pause [time in milliseconds]\" }, \"N/A\",\n                \"This command will pause the execution of a script for a given time.\",\n                \"while stam < 100\\n\\t    wait 5000\\n\\tendwhile\");\n            descriptionCommands.Add(\"pause\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"waitforgump\", new[] { \"waitforgump [gump id]\" }, \"N/A\",\n                \"This command will wait for a gump. If no gump id is provided, it will wait for **any * *gump.\",\n                \"waitforgump\\n\\twaitforgump 4\");\n            descriptionCommands.Add(\"waitforgump\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"waitformenu\", new[] { \"waitformenu [menu id]\" }, \"N/A\",\n                \"This command will wait for menu (not a context menu). If no menu id is provided, it will wait for **any * *menu.\",\n                \"waitformenu\\n\\twaitformenu 4\");\n            descriptionCommands.Add(\"waitformenu\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"waitforprompt\", new[] { \"waitforprompt\" }, \"N/A\",\n                \"This command will wait for a prompt before continuing.\",\n                \"dclicktype 'rune'\\n\\twaitforprompt\\n\\tpromptresponse 'to home'\");\n            descriptionCommands.Add(\"waitforprompt\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"waitfortarget\",\n                new[] { \"waitfortarget [pause in milliseconds] or wft [pause in milliseconds]\" }, \"N/A\",\n                \"This command will cause the script to pause until you have a target cursor.\\n\\tBy default it will wait 30 seconds but you can define a specific wait time if you prefer.\",\n                \"cast 'energy bolt'\\n\\twaitfortarget\\n\\thotkey 'Target Closest Enemy'\");\n            descriptionCommands.Add(\"waitfortarget\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"clearsysmsg\",\n                new[] { \"clearsysmsg\" }, \"N/A\",\n                \"This command will clear the internal system message queue used with insysmsg.\",\n                \"clearsysmsg\\n\");\n            descriptionCommands.Add(\"clearsysmsg\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"clearjournal\",\n                new[] { \"clearjournal\" }, \"N/A\",\n                \"This command (same as clearjournal) will clear the internal system message queue used with insysmsg.\",\n                \"clearjournal\\n\");\n            descriptionCommands.Add(\"clearjournal\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"waitforsysmsg\",\n                new[] { \"waitforsysmsg\" }, \"N/A\",\n                \"This command will pause the script until the message defined is in the system message queue.\",\n                \"waitforsysmsg 'message here'\\n\");\n            descriptionCommands.Add(\"waitforsysmsg\", tooltip);\n\n            tooltip = new ToolTipDescriptions(\"random\",\n                new[] { \"random [max number]\" }, \"N/A\",\n                \"This command output a random number between 1 and the max number provided.\",\n                \"random '15'\\n\");\n            descriptionCommands.Add(\"random\", tooltip);\n\n            #endregion\n\n            if (!Config.GetBool(\"DisableScriptTooltips\"))\n            {\n                List<AutocompleteItem> items = new List<AutocompleteItem>();\n\n                foreach (var item in keywords)\n                {\n                    items.Add(new AutocompleteItem(item));\n                }\n\n                foreach (var item in commands)\n                {\n                    descriptionCommands.TryGetValue(item, out ToolTipDescriptions element);\n\n                    if (element != null)\n                    {\n                        items.Add(new MethodAutocompleteItemAdvance(item)\n                        {\n                            ImageIndex = 2,\n                            ToolTipTitle = element.Title,\n                            ToolTipText = element.ToolTipDescription()\n                        });\n                    }\n                    else\n                    {\n                        items.Add(new MethodAutocompleteItemAdvance(item)\n                        {\n                            ImageIndex = 2\n                        });\n                    }\n                }\n\n                _autoCompleteMenu.Items.SetAutocompleteItems(items);\n                _autoCompleteMenu.Items.MaximumSize =\n                    new Size(_autoCompleteMenu.Items.Width + 20, _autoCompleteMenu.Items.Height);\n                _autoCompleteMenu.Items.Width = _autoCompleteMenu.Items.Width + 20;\n            }\n            else\n            {\n                _autoCompleteMenu.Items.SetAutocompleteItems(new List<AutocompleteItem>());\n            }\n\n            ScriptEditor.Language = FastColoredTextBoxNS.Language.Razor;\n        }\n\n        public class ToolTipDescriptions\n        {\n            public string Title;\n            public string[] Parameters;\n            public string Returns;\n            public string Description;\n            public string Example;\n\n            public ToolTipDescriptions(string title, string[] parameter, string returns, string description,\n                string example)\n            {\n                Title = title;\n                Parameters = parameter;\n                Returns = returns;\n                Description = description;\n                Example = example;\n            }\n\n            public string ToolTipDescription()\n            {\n                string complete_description = string.Empty;\n\n                complete_description += \"Parameter(s): \";\n\n                foreach (string parameter in Parameters)\n                    complete_description += \"\\n\\t\" + parameter;\n\n                complete_description += \"\\nDescription:\";\n\n                complete_description += \"\\n\\t\" + Description;\n\n                complete_description += \"\\nExample(s):\";\n\n                complete_description += \"\\n\\t\" + Example;\n\n                return complete_description;\n            }\n        }\n\n        public class MethodAutocompleteItemAdvance : MethodAutocompleteItem\n        {\n            string firstPart;\n            string lastPart;\n\n            public MethodAutocompleteItemAdvance(string text)\n                : base(text)\n            {\n                var i = text.LastIndexOf(' ');\n                if (i < 0)\n                    firstPart = text;\n                else\n                {\n                    firstPart = text.Substring(0, i);\n                    lastPart = text.Substring(i + 1);\n                }\n            }\n\n            public override CompareResult Compare(string fragmentText)\n            {\n                int i = fragmentText.LastIndexOf(' ');\n\n                if (i < 0)\n                {\n                    if (firstPart.StartsWith(fragmentText) && string.IsNullOrEmpty(lastPart))\n                        return CompareResult.VisibleAndSelected;\n                    //if (firstPart.ToLower().Contains(fragmentText.ToLower()))\n                    //  return CompareResult.Visible;\n                }\n                else\n                {\n                    var fragmentFirstPart = fragmentText.Substring(0, i);\n                    var fragmentLastPart = fragmentText.Substring(i + 1);\n\n\n                    if (firstPart != fragmentFirstPart)\n                        return CompareResult.Hidden;\n\n                    if (lastPart != null && lastPart.StartsWith(fragmentLastPart))\n                        return CompareResult.VisibleAndSelected;\n\n                    if (lastPart != null && lastPart.ToLower().Contains(fragmentLastPart.ToLower()))\n                        return CompareResult.Visible;\n                }\n\n                return CompareResult.Hidden;\n            }\n\n            public override string GetTextForReplace()\n            {\n                if (lastPart == null)\n                    return firstPart;\n\n                return firstPart + \" \" + lastPart;\n            }\n\n            public override string ToString()\n            {\n                if (lastPart == null)\n                    return firstPart;\n\n                return lastPart;\n            }\n        }\n\n        public static void RedrawScripts()\n        {\n            ScriptTree.SafeAction(s =>\n            {\n                s.BeginUpdate();\n                s.Nodes.Clear();\n                Recurse(s.Nodes, Config.GetUserDirectory(\"Scripts\"));\n                s.EndUpdate();\n                s.Refresh();\n                s.Update();\n            });\n\n            RedrawScriptVariables();\n        }\n\n        public static TreeNode GetScriptDirNode()\n        {\n            if (ScriptTree.SelectedNode == null)\n            {\n                return null;\n            }\n\n            if (ScriptTree.SelectedNode.Tag is string)\n                return ScriptTree.SelectedNode;\n                \n            if (!(ScriptTree.SelectedNode.Parent?.Tag is string))\n                return null;\n                \n            return ScriptTree.SelectedNode.Parent;\n        }\n\n        public static void AddScriptNode(TreeNode node)\n        {\n            if (node == null)\n            {\n                ScriptTree.Nodes.Add(node);\n            }\n            else\n            {\n                node.Nodes.Add(node);\n            }\n\n            ScriptTree.SelectedNode = node;\n        }\n\n        private static void Recurse(TreeNodeCollection nodes, string path)\n        {\n            try\n            {\n                var razorFiles = Directory.GetFiles(path, \"*.razor\");\n                razorFiles = razorFiles.OrderBy(fileName => fileName).ToArray();\n\n                foreach (var file in razorFiles)\n                {\n                    RazorScript script = null;\n\n                    foreach (RazorScript razorScript in _scriptList)\n                    {\n                        if (razorScript.Path.Equals(file))\n                        {\n                            script = razorScript;\n                            script.Lines = File.ReadAllLines(script.Path);\n                        }\n                    }\n\n                    if (script == null)\n                    {\n                        script = AddScript(file);\n                    }\n\n                    if (nodes != null)\n                    {\n                        TreeNode node = new TreeNode(script.Name)\n                        {\n                            Tag = script\n                        };\n\n                        nodes.Add(node);\n                    }\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n\n            try\n            {\n\n                foreach (string directory in Directory.GetDirectories(path))\n                {\n                    if (!string.IsNullOrEmpty(directory) && !directory.Equals(\".\") && !directory.Equals(\"..\"))\n                    {\n                        if (nodes != null)\n                        {\n                            TreeNode node = new TreeNode($\"[{Path.GetFileName(directory)}]\")\n                            {\n                                Tag = directory\n                            };\n\n                            nodes.Add(node);\n\n                            Recurse(node.Nodes, directory);\n                        }\n                        else\n                        {\n                            Recurse(null, directory);\n                        }\n                    }\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        public static void GetGumpInfo(string[] param)\n        {\n            Targeting.OneTimeTarget(OnGetItemInfoTarget);\n            Client.Instance.SendToClient(new UnicodeMessage(0xFFFFFFFF, -1, MessageType.Regular, 0x3B2, 3,\n                Language.CliLocName, \"System\", \"Select an item or mobile to view/inspect\"));\n        }\n\n        private static void OnGetItemInfoTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\n        {\n            Item item = World.FindItem(serial);\n\n            if (item == null)\n            {\n                Mobile mobile = World.FindMobile(serial);\n\n                if (mobile == null)\n                    return;\n\n                MobileInfoGump gump = new MobileInfoGump(mobile);\n                gump.SendGump();\n            }\n            else\n            {\n                ItemInfoGump gump = new ItemInfoGump(item);\n                gump.SendGump();\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/Scripts/ScriptVariables.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Xml;\nusing Assistant.Scripts.Engine;\n\nnamespace Assistant.Scripts\n{\n    public class ScriptVariables\n    {\n        private static Dictionary<string, Serial> _variables = new Dictionary<string, Serial>();\n        public static IEnumerable<KeyValuePair<string, Serial>> Variables => _variables;\n\n        public static void Save(XmlTextWriter xml)\n        {\n            foreach (KeyValuePair<string, Serial> kv in _variables)\n            {\n                xml.WriteStartElement(\"scriptvariable\");\n                xml.WriteAttributeString(\"serial\", kv.Value.ToString());\n                xml.WriteAttributeString(\"name\", kv.Key);\n                xml.WriteEndElement();\n            }\n        }\n\n        public static void Load(XmlElement node)\n        {\n            ClearAll();\n\n            try\n            {\n                foreach (XmlElement el in node.GetElementsByTagName(\"scriptvariable\"))\n                {\n                    string name = el.GetAttribute(\"name\");\n                    Serial serial = Serial.Parse(el.GetAttribute(\"serial\"));\n\n                    RegisterVariable(name, serial);\n                }\n            }\n            catch\n            {\n                // ignored\n            }\n        }\n\n        public static void RegisterVariable(string name, Serial serial)\n        {\n            name = name.Trim();\n\n            _variables[name] = serial;\n            Interpreter.SetAlias(name, serial);\n        }\n\n        public static void UnregisterVariable(string name)\n        {\n            name = name.Trim();\n            Interpreter.ClearAlias(name);\n            _variables.Remove(name);\n        }\n\n        public static void ClearAll()\n        {\n            foreach (string key in new List<string>(_variables.Keys))\n            {\n                UnregisterVariable(key);\n            }\n\n            _variables.Clear();\n        }\n\n        public static Serial GetVariable(string name)\n        {\n            name = name.Trim();\n\n            if (_variables.TryGetValue(name, out var val))\n            {\n                return val;\n            }\n\n            return Serial.MinusOne;\n        }\n    }\n}"
  },
  {
    "path": "Razor/Scripts/SpeechCommands.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing Assistant.Scripts.Engine;\n\nnamespace Assistant.Scripts\n{\n    public static class SpeechCommands\n    {\n        public static void Register()\n        {\n            // Messages\n            Interpreter.RegisterCommandHandler(\"say\", Say);\n            Interpreter.RegisterCommandHandler(\"msg\", Say);\n            Interpreter.RegisterCommandHandler(\"yell\", Yell);\n            Interpreter.RegisterCommandHandler(\"whisper\", Whisper);\n            Interpreter.RegisterCommandHandler(\"emote\", Emote);\n            Interpreter.RegisterCommandHandler(\"guild\", Guild);\n            Interpreter.RegisterCommandHandler(\"alliance\", Alliance);\n        }\n\n        private static bool Say(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: say ('text') [color]\");\n            }\n\n            if (vars.Length == 1)\n                World.Player.Say(Config.GetInt(\"SysColor\"), vars[0].AsString());\n            else\n                World.Player.Say(Utility.ToInt32(vars[1].AsString(), 0), vars[0].AsString());\n\n            return true;\n        }\n\n        private static bool Whisper(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: whisper ('text') [color]\");\n            }\n\n            MessageType type = MessageType.Whisper & ~MessageType.Encoded;\n\n            if (vars.Length == 1)\n                World.Player.Whisper(vars[0].AsString(), World.Player.SpeechHue);\n            else\n                World.Player.Whisper(vars[0].AsString(), Utility.ToInt32(vars[1].AsString(), 0));\n\n            return true;\n        }\n\n        private static bool Yell(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: yell ('text') [color]\");\n            }\n\n            if (vars.Length == 1)\n                World.Player.Yell(vars[0].AsString(), World.Player.SpeechHue);\n            else\n                World.Player.Yell(vars[0].AsString(), Utility.ToInt32(vars[1].AsString(), 0));\n\n            return true;\n        }\n\n        private static bool Emote(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: emote ('text') [color]\");\n            }\n\n            if (vars.Length == 1)\n                World.Player.Emote(vars[0].AsString(), World.Player.SpeechHue);\n            else\n                World.Player.Emote(vars[0].AsString(), Utility.ToInt32(vars[1].AsString(), 0));\n\n            return true;\n        }\n\n        private static bool Guild(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: guild ('text')\");\n            }\n\n            if (vars.Length == 1)\n                World.Player.Guild(vars[0].AsString(), World.Player.SpeechHue);\n            else\n                World.Player.Guild(vars[0].AsString(), Utility.ToInt32(vars[1].AsString(), 0));\n\n            return true;\n        }\n\n        private static bool Alliance(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length == 0)\n            {\n                throw new RunTimeError(\"Usage: alliance ('text')\");\n            }\n\n            if (vars.Length == 1)\n                World.Player.Alliance(vars[0].AsString(), World.Player.SpeechHue);\n            else\n                World.Player.Alliance(vars[0].AsString(), Utility.ToInt32(vars[1].AsString(), 0));\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/Scripts/TargetCommands.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing Assistant.Scripts.Engine;\nusing Assistant.Scripts.Helpers;\n\nnamespace Assistant.Scripts\n{\n    public static class TargetCommands\n    {\n        public static void Register()\n        {\n            // Targets\n            Interpreter.RegisterCommandHandler(\"target\", Target); //Absolute Target\n\n            Interpreter.RegisterCommandHandler(\"targettype\", TargetType); //TargetTypeAction\n            Interpreter.RegisterCommandHandler(\"targetrelloc\", TargetRelLoc); //TargetRelLocAction\n            Interpreter.RegisterCommandHandler(\"targetloc\", TargetLocation);\n\n            Interpreter.RegisterCommandHandler(\"waitfortarget\", WaitForTarget); //WaitForTargetAction\n            Interpreter.RegisterCommandHandler(\"wft\", WaitForTarget); //WaitForTargetAction\n        }\n\n        private static bool Target(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: target (serial) OR target (closest/random/next/prev [noto] [type]\");\n            }\n\n            switch (vars[0].AsString())\n            {\n                case \"close\":\n                case \"closest\":\n                    CommandHelper.FindTarget(vars, true);\n\n                    break;\n\n                case \"rand\":\n                case \"random\":\n                    CommandHelper.FindTarget(vars, false, true);\n\n                    break;\n\n                case \"next\":\n                    CommandHelper.FindTarget(vars, false, false, true);\n\n                    break;\n\n                case \"prev\":\n                case \"previous\":\n                    CommandHelper.FindTarget(vars, false, false, false, true);\n\n                    break;\n\n                case \"cancel\":\n                    Targeting.CancelTarget();\n\n                    break;\n\n                case \"clear\":\n                    Targeting.OnClearQueue();\n\n                    break;\n\n                default:\n                    Serial serial = vars[0].AsSerial();\n\n                    if (serial != Serial.Zero) // Target a specific item or mobile\n                    {\n                        Item item = World.FindItem(serial);\n\n                        if (item != null)\n                        {\n                            Targeting.Target(item);\n                            return true;\n                        }\n\n                        Mobile mobile = World.FindMobile(serial);\n\n                        if (mobile != null)\n                        {\n                            Targeting.Target(mobile);\n                        }\n                    }\n\n                    break;\n            }\n\n            return true;\n        }\n\n        private static bool TargetType(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (Targeting.FromGrabHotKey)\n                return false;\n\n            if (vars.Length < 1)\n            {\n                throw new RunTimeError(\"Usage: targettype ('name of item or mobile type'/'graphicId') [inrangecheck (true/false)/backpack] [hue]\");\n            }\n\n            string gfxStr = vars[0].AsString();\n            Serial gfx = Utility.ToUInt16(gfxStr, 0);\n            List<Item> items;\n            List<Mobile> mobiles = new List<Mobile>();\n\n            bool inRangeCheck = false;\n            bool backpack = false;\n            int hue = -1;\n\n            if (vars.Length > 1)\n            {\n                if (vars.Length == 3)\n                {\n                    hue = vars[2].AsInt();\n                }\n\n                if (vars[1].AsString().IndexOf(\"pack\", StringComparison.OrdinalIgnoreCase) != -1)\n                {\n                    backpack = true;\n                }\n                else\n                {\n                    inRangeCheck = vars[1].AsBool();\n                }\n            }\n\n            // No graphic id, maybe searching by name?\n            if (gfx == 0)\n            {\n                items = CommandHelper.GetItemsByName(gfxStr, backpack, inRangeCheck, hue);\n\n                if (items.Count == 0) // no item found, search mobile by name\n                {\n                    mobiles = CommandHelper.GetMobilesByName(gfxStr, inRangeCheck);\n                }\n            }\n            else // Provided graphic id for type, check backpack first (same behavior as DoubleClickAction in macros\n            {\n                ushort id = Utility.ToUInt16(gfxStr, 0);\n\n                items = CommandHelper.GetItemsById(id, backpack, inRangeCheck, hue);\n\n                // Still no item? Mobile check!\n                if (items.Count == 0)\n                {\n                    mobiles = CommandHelper.GetMobilesById(id, inRangeCheck);\n                }\n            }\n\n            if (items.Count > 0)\n            {\n                Targeting.Target(items[Utility.Random(items.Count)]);\n            }\n            else if (mobiles.Count > 0)\n            {\n                Targeting.Target(mobiles[Utility.Random(mobiles.Count)]);\n            }\n            else\n            {\n                CommandHelper.SendWarning(command, $\"Item or mobile type '{gfxStr}' not found\", quiet);\n            }\n\n            return true;\n        }\n\n        private static bool TargetRelLoc(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (Targeting.FromGrabHotKey)\n                return false;\n\n            if (vars.Length < 2)\n            {\n                throw new RunTimeError(\"Usage: targetrelloc (x-offset) (y-offset)\");\n            }\n\n            int xoffset = Utility.ToInt32(vars[0].AsString(), 0);\n            int yoffset = Utility.ToInt32(vars[1].AsString(), 0);\n\n            ushort x = (ushort) (World.Player.Position.X + xoffset);\n            ushort y = (ushort) (World.Player.Position.Y + yoffset);\n            short z = (short) World.Player.Position.Z;\n\n            try\n            {\n                Ultima.HuedTile tile = Map.GetTileNear(World.Player.Map, x, y, z);\n                Targeting.Target(new Point3D(x, y, tile.Z), tile.ID);\n            }\n            catch (Exception e)\n            {\n                throw new RunTimeError($\"{command} - Error Executing: {e.Message}\");\n            }\n\n            return true;\n        }\n\n        private static bool TargetLocation(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (vars.Length < 2)\n            {\n                throw new RunTimeError(\"Usage: targetloc (x) (y) (z)\");\n            }\n\n            Targeting.Target(new TargetInfo\n            {\n                Type = 1,\n                Flags = 0,\n                Serial = Serial.Zero,\n                X = vars[0].AsInt(),\n                Y = vars[1].AsInt(),\n                Z = vars.Length == 3 ? vars[2].AsInt() : 0,\n                Gfx = 0\n            });\n\n            return true;\n        }\n\n        private static bool WaitForTarget(string command, Variable[] vars, bool quiet, bool force)\n        {\n            if (Targeting.HasTarget)\n            {\n                Interpreter.ClearTimeout();\n                return true;\n            }\n\n            Interpreter.Timeout(vars.Length > 0 ? vars[0].AsUInt() : 30000, () => { return true; });\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/AddCounter.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Windows.Forms;\r\nusing Assistant.UI;\r\n\r\nnamespace Assistant\r\n{\r\n    /// <summary>\r\n    /// Summary description for AddCounter.\r\n    /// </summary>\r\n    public class AddCounter : System.Windows.Forms.Form\r\n    {\r\n        private System.Windows.Forms.Label label1;\r\n        private System.Windows.Forms.TextBox name;\r\n        private System.Windows.Forms.Label label2;\r\n        private System.Windows.Forms.TextBox format;\r\n        private System.Windows.Forms.Label label3;\r\n        private System.Windows.Forms.TextBox itemid;\r\n        private System.Windows.Forms.Label label4;\r\n        private System.Windows.Forms.TextBox hue;\r\n        private System.Windows.Forms.Button Add;\r\n        private System.Windows.Forms.Button cancel;\r\n        private System.Windows.Forms.Button target;\r\n        private System.Windows.Forms.Button delete;\r\n        private System.Windows.Forms.CheckBox dispImg;\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        public AddCounter()\r\n        {\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n        }\r\n\r\n        public AddCounter(Counter c) : this()\r\n        {\r\n            name.Text = c.Name;\r\n            format.Text = c.Format;\r\n            itemid.Text = c.ItemID.ToString();\r\n            hue.Text = c.Hue.ToString();\r\n            dispImg.Checked = c.DisplayImage;\r\n\r\n            delete.Visible = true;\r\n            this.Text = \"Edit Counter\";\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            this.label1 = new System.Windows.Forms.Label();\r\n            this.name = new System.Windows.Forms.TextBox();\r\n            this.label2 = new System.Windows.Forms.Label();\r\n            this.format = new System.Windows.Forms.TextBox();\r\n            this.label3 = new System.Windows.Forms.Label();\r\n            this.itemid = new System.Windows.Forms.TextBox();\r\n            this.label4 = new System.Windows.Forms.Label();\r\n            this.hue = new System.Windows.Forms.TextBox();\r\n            this.Add = new System.Windows.Forms.Button();\r\n            this.cancel = new System.Windows.Forms.Button();\r\n            this.target = new System.Windows.Forms.Button();\r\n            this.delete = new System.Windows.Forms.Button();\r\n            this.dispImg = new System.Windows.Forms.CheckBox();\r\n            this.SuspendLayout();\r\n            // \r\n            // label1\r\n            // \r\n            this.label1.AutoSize = true;\r\n            this.label1.Location = new System.Drawing.Point(12, 9);\r\n            this.label1.Name = \"label1\";\r\n            this.label1.Size = new System.Drawing.Size(42, 15);\r\n            this.label1.TabIndex = 0;\r\n            this.label1.Text = \"Name:\";\r\n            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\r\n            // \r\n            // name\r\n            // \r\n            this.name.Location = new System.Drawing.Point(60, 6);\r\n            this.name.Name = \"name\";\r\n            this.name.Size = new System.Drawing.Size(85, 23);\r\n            this.name.TabIndex = 1;\r\n            // \r\n            // label2\r\n            // \r\n            this.label2.AutoSize = true;\r\n            this.label2.Location = new System.Drawing.Point(151, 9);\r\n            this.label2.Name = \"label2\";\r\n            this.label2.Size = new System.Drawing.Size(48, 15);\r\n            this.label2.TabIndex = 2;\r\n            this.label2.Text = \"Format:\";\r\n            this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\r\n            // \r\n            // format\r\n            // \r\n            this.format.Location = new System.Drawing.Point(205, 6);\r\n            this.format.Name = \"format\";\r\n            this.format.Size = new System.Drawing.Size(94, 23);\r\n            this.format.TabIndex = 3;\r\n            // \r\n            // label3\r\n            // \r\n            this.label3.AutoSize = true;\r\n            this.label3.Location = new System.Drawing.Point(6, 38);\r\n            this.label3.Name = \"label3\";\r\n            this.label3.Size = new System.Drawing.Size(48, 15);\r\n            this.label3.TabIndex = 4;\r\n            this.label3.Text = \"Item ID:\";\r\n            this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\r\n            // \r\n            // itemid\r\n            // \r\n            this.itemid.Location = new System.Drawing.Point(60, 35);\r\n            this.itemid.Name = \"itemid\";\r\n            this.itemid.Size = new System.Drawing.Size(85, 23);\r\n            this.itemid.TabIndex = 5;\r\n            // \r\n            // label4\r\n            // \r\n            this.label4.AutoSize = true;\r\n            this.label4.Location = new System.Drawing.Point(151, 38);\r\n            this.label4.Name = \"label4\";\r\n            this.label4.Size = new System.Drawing.Size(88, 15);\r\n            this.label4.TabIndex = 6;\r\n            this.label4.Text = \"Color (Any: -1):\";\r\n            this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\r\n            // \r\n            // hue\r\n            // \r\n            this.hue.Location = new System.Drawing.Point(245, 35);\r\n            this.hue.Name = \"hue\";\r\n            this.hue.Size = new System.Drawing.Size(54, 23);\r\n            this.hue.TabIndex = 7;\r\n            // \r\n            // Add\r\n            // \r\n            this.Add.DialogResult = System.Windows.Forms.DialogResult.OK;\r\n            this.Add.Location = new System.Drawing.Point(9, 90);\r\n            this.Add.Name = \"Add\";\r\n            this.Add.Size = new System.Drawing.Size(68, 34);\r\n            this.Add.TabIndex = 8;\r\n            this.Add.Text = \"&Okay\";\r\n            this.Add.Click += new System.EventHandler(this.Add_Click);\r\n            // \r\n            // cancel\r\n            // \r\n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\r\n            this.cancel.Location = new System.Drawing.Point(83, 90);\r\n            this.cancel.Name = \"cancel\";\r\n            this.cancel.Size = new System.Drawing.Size(68, 34);\r\n            this.cancel.TabIndex = 9;\r\n            this.cancel.Text = \"Cancel\";\r\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\r\n            // \r\n            // target\r\n            // \r\n            this.target.Location = new System.Drawing.Point(231, 90);\r\n            this.target.Name = \"target\";\r\n            this.target.Size = new System.Drawing.Size(68, 34);\r\n            this.target.TabIndex = 10;\r\n            this.target.Text = \"Target \";\r\n            this.target.Click += new System.EventHandler(this.target_Click);\r\n            // \r\n            // delete\r\n            // \r\n            this.delete.Location = new System.Drawing.Point(157, 90);\r\n            this.delete.Name = \"delete\";\r\n            this.delete.Size = new System.Drawing.Size(68, 34);\r\n            this.delete.TabIndex = 11;\r\n            this.delete.Text = \"Delete\";\r\n            this.delete.Visible = false;\r\n            this.delete.Click += new System.EventHandler(this.delete_Click);\r\n            // \r\n            // dispImg\r\n            // \r\n            this.dispImg.Checked = true;\r\n            this.dispImg.CheckState = System.Windows.Forms.CheckState.Checked;\r\n            this.dispImg.Location = new System.Drawing.Point(9, 64);\r\n            this.dispImg.Name = \"dispImg\";\r\n            this.dispImg.Size = new System.Drawing.Size(160, 20);\r\n            this.dispImg.TabIndex = 12;\r\n            this.dispImg.Text = \"Display image in titlebar\";\r\n            // \r\n            // AddCounter\r\n            // \r\n            this.AcceptButton = this.Add;\r\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\r\n            this.ClientSize = new System.Drawing.Size(308, 133);\r\n            this.ControlBox = false;\r\n            this.Controls.Add(this.dispImg);\r\n            this.Controls.Add(this.hue);\r\n            this.Controls.Add(this.itemid);\r\n            this.Controls.Add(this.format);\r\n            this.Controls.Add(this.name);\r\n            this.Controls.Add(this.delete);\r\n            this.Controls.Add(this.target);\r\n            this.Controls.Add(this.cancel);\r\n            this.Controls.Add(this.Add);\r\n            this.Controls.Add(this.label4);\r\n            this.Controls.Add(this.label3);\r\n            this.Controls.Add(this.label2);\r\n            this.Controls.Add(this.label1);\r\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\r\n            this.Name = \"AddCounter\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\r\n            this.Text = \"Add a Counter\";\r\n            this.Load += new System.EventHandler(this.AddCounter_Load);\r\n            this.ResumeLayout(false);\r\n            this.PerformLayout();\r\n        }\r\n\r\n        #endregion\r\n\r\n        public string NameStr, FmtStr;\r\n        public int ItemID, Hue;\r\n        public bool DisplayImage;\r\n\r\n        private void Add_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (name.Text.Trim().Length > 0 && format.Text.Trim().Length > 0)\r\n            {\r\n                NameStr = name.Text.Trim();\r\n                FmtStr = format.Text.Trim();\r\n            }\r\n            else\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.InvalidAbrev), \"Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Information);\r\n                return;\r\n            }\r\n\r\n            try\r\n            {\r\n                if (itemid.Text.StartsWith(\"0x\"))\r\n                    ItemID = Convert.ToUInt16(itemid.Text.Substring(2).Trim(), 16);\r\n                else\r\n                    ItemID = Convert.ToUInt16(itemid.Text.Trim());\r\n            }\r\n            catch\r\n            {\r\n                ItemID = 0;\r\n            }\r\n\r\n            if (ItemID == 0)\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.InvalidIID), \"Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Information);\r\n                return;\r\n            }\r\n\r\n            Hue = Utility.ToInt32(hue.Text, -1);\r\n\r\n            if (Hue < -1 || Hue > 0xFFFF)\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.InvalidHue), \"Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Information);\r\n                Hue = 0;\r\n                return;\r\n            }\r\n\r\n            DisplayImage = dispImg.Checked;\r\n        }\r\n\r\n        private void cancel_Click(object sender, System.EventArgs e)\r\n        {\r\n            Targeting.CancelOneTimeTarget();\r\n        }\r\n\r\n        private void target_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnTarget));\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.SelItem2Count);\r\n            }\r\n        }\r\n\r\n        private void OnTarget(bool loc, Serial serial, Point3D p, ushort graphic)\r\n        {\r\n            Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n            this.BringToFront();\r\n            this.Show();\r\n            this.Focus();\r\n            if (loc)\r\n                return;\r\n\r\n            Item item = World.FindItem(serial);\r\n            if (item != null)\r\n            {\r\n                itemid.Text = item.ItemID.Value.ToString();\r\n                hue.Text = item.Hue == 0 ? \"-1\" : item.Hue.ToString();\r\n            }\r\n            else\r\n            {\r\n                itemid.Text = graphic.ToString();\r\n                hue.Text = \"-1\";\r\n            }\r\n        }\r\n\r\n        private void AddCounter_Load(object sender, System.EventArgs e)\r\n        {\r\n            Language.LoadControlNames(this);\r\n        }\r\n\r\n        private void delete_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (MessageBox.Show(this, \"Are you sure you want to delete this counter?\", \"Delete Confirm\",\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                this.DialogResult = DialogResult.Abort;\r\n                this.Close();\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/AddCounter.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n</root>"
  },
  {
    "path": "Razor/UI/ArtViewer.Designer.cs",
    "content": "using System.ComponentModel;\n\nnamespace Assistant.UI\n{\n    partial class ArtViewer\n    {\n        /// <summary> \n        /// Required designer variable.\n        /// </summary>\n        private IContainer components = null;\n\n        /// <summary> \n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        /*protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n\n            base.Dispose(disposing);\n        }\n        */\n\n        #region Component Designer generated code\n\n        /// <summary> \n        /// Required method for Designer support - do not modify \n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            components = new System.ComponentModel.Container();\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Razor/UI/ArtViewer.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.Windows.Forms;\nusing Ultima;\n\nnamespace Assistant.UI\n{\n\tpublic enum Art\n\t{\n\t\t/// <summary>\n\t\t///     Static items\n\t\t/// </summary>\n\t\tItems = 0,\n\n\t\t/// <summary>\n\t\t///     Characters ( animated or not )\n\t\t/// </summary>\n\t\tNPCs = 1,\n\n\t\t/// <summary>\n\t\t///     Gumps\n\t\t/// </summary>\n\t\tGumps = 2,\n\n\t\t/// <summary>\n\t\t///     Images\n\t\t/// </summary>\n\t\tImages = 3\n\t}\n\t\n    public partial class ArtViewer : UserControl\n    {\n       \n        \n\t    #region events\n\t\t/// <summary>\n\t\t///     Occurs when the index of the displayed art is changed\n\t\t/// </summary>\n\t\tpublic event EventHandler ArtIndexChanged;\n\t\t#endregion\n\n\t\t#region Variables\n\t\t/// <summary>\n\t\t///     The art type currently displayed\n\t\t/// </summary>\n\t\tprivate Art m_Art = Art.Items;\n\n\t\t/// <summary>\n\t\t///     The index of the art to display\n\t\t/// </summary>\n\t\tprivate int m_ArtIndex;\n\n\t\t/// <summary>\n\t\t///     Animate characters or not\n\t\t/// </summary>\n\t\tprivate bool m_Animate;\n\n\t\t/// <summary>\n\t\t///     The hue for the current item\n\t\t/// </summary>\n\t\tprivate int m_Hue;\n\n\t\t/// <summary>\n\t\t///     Resize images that are larger than the control area\n\t\t/// </summary>\n\t\tprivate bool m_ResizeTallItems;\n\n\t\t/// <summary>\n\t\t///     Display the axes when showing items\n\t\t/// </summary>\n\t\tprivate bool m_RoomView = true;\n\n\t\t/// <summary>\n\t\t///     The image currently displayed\n\t\t/// </summary>\n\t\tprivate Bitmap m_Image;\n\n\t\t/// <summary>\n\t\t///     Image is invalidated and needs to be redrawn\n\t\t/// </summary>\n\t\tprivate bool m_ImageInvalidated = true;\n\n\t\t/// <summary>\n\t\t///     The bitmaps used for the animation\n\t\t/// </summary>\n\t\tprivate Bitmap[] m_Animation;\n\n\t\t/// <summary>\n\t\t///     The timer for the animation\n\t\t/// </summary>\n\t\tprivate Timer m_Timer;\n\n\t\t/// <summary>\n\t\t///     Current animation index\n\t\t/// </summary>\n\t\tprivate int m_FrameIndex;\n\n\t\t/// <summary>\n\t\t///     Shows the ID in the lower right corner\n\t\t/// </summary>\n\t\tprivate bool m_ShowID = true;\n\n\t\t/// <summary>\n\t\t///     Shows the ID in hex format in the lower left corner\n\t\t/// </summary>\n\t\tprivate bool m_ShowHexID = true;\n\t\t#endregion\n\n\t\t#region Properties\n\t\t/// <summary>\n\t\t///     Sets the image that should be displayed by the viewer\n\t\t/// </summary>\n\t\tpublic Image DisplayedImage\n\t\t{\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (value != null)\n\t\t\t\t{\n\t\t\t\t\t//StopAnimation();\n\n\t\t\t\t\tif (m_Image != null)\n\t\t\t\t\t\tm_Image.Dispose();\n\n\t\t\t\t\tm_Image = new Bitmap(value);\n\n\t\t\t\t\tm_Art = Art.Images;\n\n\t\t\t\t\tm_ImageInvalidated = false;\n\t\t\t\t\tRefresh();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Gets or sets the art type displayed by the control\n\t\t/// </summary>\n\t\tpublic Art Art\n\t\t{\n\t\t\tget { return m_Art; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (m_Art != value)\n\t\t\t\t{\n\t\t\t\t\tif (value == Art.Images)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\tm_Art = value;\n\n\t\t\t\t\t//StopAnimation();\n\t\t\t\t\tm_ImageInvalidated = true;\n\t\t\t\t\tRefresh();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Gets or sets the index of the currently displayed art\n\t\t/// </summary>\n\t\tpublic int ArtIndex\n\t\t{\n\t\t\tget { return m_ArtIndex; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (value != m_ArtIndex)\n\t\t\t\t{\n\t\t\t\t\tm_ArtIndex = value;\n\n\t\t\t\t\t//StopAnimation();\n\t\t\t\t\tm_ImageInvalidated = true;\n\t\t\t\t\tRefresh();\n\n\t\t\t\t\tif (ArtIndexChanged != null)\n\t\t\t\t\t{\n\t\t\t\t\t\tArtIndexChanged(this, new EventArgs());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Gets or sets a value stating whether the character display is going to be animated\n\t\t/// </summary>\n\t\tpublic bool Animate\n\t\t{\n\t\t\tget { return m_Animate; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (m_Animate != value)\n\t\t\t\t{\n\t\t\t\t\tm_Animate = value;\n\n\t\t\t\t\tif (m_Art == Art.NPCs)\n\t\t\t\t\t{\n\t\t\t\t\t\t//StopAnimation();\n\t\t\t\t\t\tm_ImageInvalidated = true;\n\t\t\t\t\t\tRefresh();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Gets or sets the hue for the current image\n\t\t/// </summary>\n\t\tpublic int Hue\n\t\t{\n\t\t\tget { return m_Hue; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (m_Hue == value)\n\t\t\t\t\treturn;\n\n\t\t\t\tm_Hue = value;\n\n\t\t\t\tif (m_Hue < 0)\n\t\t\t\t\tm_Hue = 0;\n\n\t\t\t\tif (m_Hue > 2999)\n\t\t\t\t\tm_Hue = 2999;\n\n\t\t\t\t//StopAnimation();\n\t\t\t\tm_ImageInvalidated = true;\n\t\t\t\tRefresh();\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Gets or sets a value stating whether items larger than the display area should be resized\n\t\t/// </summary>\n\t\tpublic bool ResizeTallItems\n\t\t{\n\t\t\tget { return m_ResizeTallItems; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (m_ResizeTallItems != value)\n\t\t\t\t{\n\t\t\t\t\tm_ResizeTallItems = value;\n\n\t\t\t\t\tRefresh();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Gets or sets a value stating whether the display of static items will show the\n\t\t/// </summary>\n\t\tpublic bool RoomView\n\t\t{\n\t\t\tget { return m_RoomView; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (m_RoomView != value)\n\t\t\t\t{\n\t\t\t\t\tm_RoomView = value;\n\n\t\t\t\t\tRefresh();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool ShowID\n\t\t{\n\t\t\tget { return m_ShowID; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (m_ShowID != value)\n\t\t\t\t{\n\t\t\t\t\tm_ShowID = value;\n\n\t\t\t\t\tRefresh();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic bool ShowHexID\n\t\t{\n\t\t\tget { return m_ShowHexID; }\n\t\t\tset\n\t\t\t{\n\t\t\t\tif (m_ShowHexID != value)\n\t\t\t\t{\n\t\t\t\t\tm_ShowHexID = value;\n\t\t\t\t\tRefresh();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t#endregion\n        \n        public ArtViewer()\n        {\n            InitializeComponent();\n        }\n        \n        /// <summary>\n\t\t///     Clean up any resources being used.\n\t\t/// </summary>\n\t\tprotected override void Dispose(bool disposing)\n\t\t{\n\t\t\tbase.Dispose(disposing);\n\n\t\t\tif (m_Image != null)\n\t\t\t{\n\t\t\t\tm_Image.Dispose();\n\t\t\t\tm_Image = null;\n\t\t\t}\n\t\t}\n\n\t\tprotected override void OnPaint(PaintEventArgs e)\n\t\t{\n\t\t\tbase.OnPaint(e);\n\n\t\t\tif (m_ImageInvalidated)\n\t\t\t\tCreateDisplay();\n\n\t\t\tif (m_Image != null)\n\t\t\t{\n\t\t\t\t// Position image\n\t\t\t\tvar location = Point.Empty;\n\t\t\t\tvar size = Size.Empty;\n\n\t\t\t\tif (m_Image.Width <= Width && m_Image.Height <= Height)\n\t\t\t\t{\n\t\t\t\t\t// Image fits\n\t\t\t\t\tsize = m_Image.Size;\n\t\t\t\t\tlocation.X = (Width - m_Image.Width) / 2;\n\t\t\t\t\tlocation.Y = (Height - m_Image.Height) / 2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (m_ResizeTallItems)\n\t\t\t\t\t{\n\t\t\t\t\t\tsize = m_Image.Size;\n\n\t\t\t\t\t\tvar rate = m_Image.Width / (double)m_Image.Height;\n\n\t\t\t\t\t\t// Resize\n\t\t\t\t\t\tif (size.Width > Width)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsize.Width = Width;\n\t\t\t\t\t\t\tsize.Height = (int)(size.Width / rate);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (size.Height > Height)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsize.Height = Height;\n\t\t\t\t\t\t\tsize.Width = (int)(size.Height * rate);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlocation.X = (Width - size.Width) / 2;\n\t\t\t\t\t\tlocation.Y = (Height - size.Height) / 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tlocation.X = (Width - m_Image.Width) / 2;\n\t\t\t\t\t\tlocation.Y = (Height - m_Image.Height) / 2;\n\t\t\t\t\t\tsize = m_Image.Size;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar destRect = new Rectangle(location, size);\n\n\t\t\t\tif (m_Art == Art.Items && m_RoomView)\n\t\t\t\t{\n\t\t\t\t\tDrawRoomView(e.Graphics, destRect);\n\t\t\t\t}\n\n\t\t\t\te.Graphics.DrawImage(m_Image, destRect, 0, 0, m_Image.Width, m_Image.Height, GraphicsUnit.Pixel);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (m_Art == Art.Items && m_RoomView)\n\t\t\t\t\tDrawRoomView(e.Graphics, new Rectangle((Width - 44) / 2, (Height - 44) / 2, 44, 44));\n\t\t\t}\n\n\t\t\t// ID\n\t\t\tvar black = new Pen(SystemColors.ControlDark);\n\n\t\t\tif ((m_ShowID || m_ShowHexID) && m_Art != Art.Images)\n\t\t\t{\n\t\t\t\tBrush back = new SolidBrush(SystemColors.Window);\n\t\t\t\tBrush text = new SolidBrush(SystemColors.WindowText);\n\n\t\t\t\tvar font = new Font(\"Verdana\", 8.0f);\n\t\t\t\tvar id = m_ArtIndex.ToString();\n\t\t\t\tvar hex = m_ArtIndex.ToString(\"X\");\n\n\t\t\t\tif (m_ShowID)\n\t\t\t\t{\n\t\t\t\t\tvar siz = e.Graphics.MeasureString(id, font);\n\n\t\t\t\t\tvar s = siz.ToSize();\n\t\t\t\t\ts.Width += 4;\n\t\t\t\t\tsiz.Height += 4;\n\n\t\t\t\t\tvar x = Width - s.Width - 4;\n\t\t\t\t\tvar y = Height - s.Height - 4;\n\n\t\t\t\t\tvar r = new RectangleF(x + 2, y, siz.Width, siz.Height);\n\n\t\t\t\t\te.Graphics.FillRectangle(back, x, y, s.Width, s.Height);\n\t\t\t\t\te.Graphics.DrawRectangle(black, x, y, s.Width, s.Height);\n\t\t\t\t\te.Graphics.DrawString(id, font, text, r);\n\t\t\t\t}\n\n\t\t\t\tif (m_ShowHexID)\n\t\t\t\t{\n\t\t\t\t\tvar siz = e.Graphics.MeasureString(hex, font);\n\n\t\t\t\t\tvar s = siz.ToSize();\n\t\t\t\t\ts.Width += 4;\n\t\t\t\t\tsiz.Height += 4;\n\n\t\t\t\t\tvar y = Height - s.Height - 4;\n\n\t\t\t\t\tvar r = new RectangleF(6, y, siz.Width, siz.Height);\n\n\t\t\t\t\te.Graphics.FillRectangle(back, 4, y, s.Width, s.Height);\n\t\t\t\t\te.Graphics.DrawRectangle(black, 4, y, s.Width, s.Height);\n\t\t\t\t\te.Graphics.DrawString(hex, font, text, r);\n\t\t\t\t}\n\n\t\t\t\ttext.Dispose();\n\t\t\t\tback.Dispose();\n\t\t\t\tfont.Dispose();\n\t\t\t}\n\n\t\t\t// Border\n\n\t\t\te.Graphics.DrawRectangle(black, 0, 0, Width - 1, Height - 1);\n\t\t\tblack.Dispose();\n\t\t}\n\n\t\t#region Room View\n\t\t/// <summary>\n\t\t///     Draws the room view\n\t\t/// </summary>\n\t\t/// <param name=\"g\">The graphics used to draw the room view</param>\n\t\t/// <param name=\"imgRect\">The rectangle the image will occupy on the display</param>\n\t\tprivate void DrawRoomView(Graphics g, Rectangle imgRect)\n\t\t{\n\t\t\tvar bottom = Point.Empty;\n\t\t\tvar top = Point.Empty;\n\t\t\tvar left = Point.Empty;\n\t\t\tvar right = Point.Empty;\n\n\t\t\tbottom.X = imgRect.X + (imgRect.Width / 2);\n\t\t\tbottom.Y = imgRect.Bottom;\n\n\t\t\ttop.X = bottom.X;\n\t\t\ttop.Y = bottom.Y - imgRect.Width;\n\n\t\t\tleft.X = imgRect.X;\n\t\t\tleft.Y = imgRect.Bottom - (imgRect.Width / 2);\n\n\t\t\tright.X = imgRect.Right;\n\t\t\tright.Y = left.Y;\n\n\t\t\t// top points\n\t\t\tvar top1 = Point.Empty;\n\t\t\tvar top2 = Point.Empty;\n\t\t\tvar top3 = Point.Empty;\n\n\t\t\ttop1.Y = top2.Y = top3.Y = 0;\n\t\t\ttop1.X = left.X;\n\t\t\ttop2.X = top.X;\n\t\t\ttop3.X = right.X;\n\n\t\t\tvar blackPen = new Pen(Color.Black);\n\t\t\tBrush whiteBrush = new LinearGradientBrush(top, right, Color.DarkSlateBlue, Color.SkyBlue);\n\n\t\t\t// Draw base block\n\t\t\tvar baseBlock = new[] {top, right, bottom, left, top};\n\t\t\tg.FillPolygon(whiteBrush, baseBlock);\n\n\t\t\t// Fill\n\t\t\tvar leftArea = new[] {left, top1, top2, top, left};\n\t\t\tvar rightArea = new[] {top, top2, top3, right, top};\n\n\t\t\tBrush darkBrush = new LinearGradientBrush(left, top1, Color.MidnightBlue, Color.LightGray);\n\t\t\tBrush lightBrush = new LinearGradientBrush(right, top3, Color.SteelBlue, Color.White);\n\n\t\t\tg.FillPolygon(darkBrush, leftArea);\n\t\t\tg.FillPolygon(lightBrush, rightArea);\n\n\t\t\t// Draw base\n\t\t\tg.DrawLines(blackPen, baseBlock);\n\n\t\t\t// Draw vertical lines\n\t\t\tg.DrawLine(blackPen, left, top1);\n\t\t\tg.DrawLine(blackPen, top, top2);\n\t\t\tg.DrawLine(blackPen, right, top3);\n\n\t\t\t// Draw top line\n\t\t\tg.DrawLine(blackPen, top1, top3);\n\n\t\t\t// Draw axes\n\t\t\tg.DrawLine(blackPen, right, GetIntersection(bottom, right));\n\t\t\tg.DrawLine(blackPen, right, GetIntersection(top, right));\n\t\t\tg.DrawLine(blackPen, left, GetIntersection(bottom, left));\n\t\t\tg.DrawLine(blackPen, left, GetIntersection(top, left));\n\n\t\t\tblackPen.Dispose();\n\t\t\twhiteBrush.Dispose();\n\t\t\tdarkBrush.Dispose();\n\t\t\tlightBrush.Dispose();\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Gets the intersection point with the control bounds following a line from p2\n\t\t/// </summary>\n\t\t/// <param name=\"p1\">the starting point of the line</param>\n\t\t/// <param name=\"p2\">the middle point of the line, used to define it</param>\n\t\t/// <returns>A point on the bounds of the control</returns>\n\t\tprivate Point GetIntersection(Point p1, Point p2)\n\t\t{\n\t\t\tvar a = ((p1.Y - p2.Y) / (double)(p1.X - p2.X));\n\t\t\tvar b = p1.Y - (a * p1.X);\n\n\t\t\tif (p1.X < p2.X)\n\t\t\t{\n\t\t\t\t// Right side\n\t\t\t\tvar pRight = Point.Empty;\n\n\t\t\t\tpRight.X = Width;\n\t\t\t\tpRight.Y = (int)(Width * a + b);\n\n\t\t\t\tif (pRight.Y < 0)\n\t\t\t\t{\n\t\t\t\t\tpRight.Y = 0;\n\t\t\t\t\tpRight.X = (int)-(b / a);\n\t\t\t\t}\n\n\t\t\t\treturn pRight;\n\t\t\t}\n\t\t\tvar pLeft = Point.Empty;\n\n\t\t\tif (b < 0)\n\t\t\t{\n\t\t\t\tpLeft.Y = 0;\n\t\t\t\tpLeft.X = (int)(-b / a);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpLeft.Y = (int)b;\n\t\t\t\tpLeft.X = 0;\n\t\t\t}\n\n\t\t\treturn pLeft;\n\t\t}\n\t\t#endregion\n\n\t\tprotected override void OnResize(EventArgs e)\n\t\t{\n\t\t\tbase.OnResize(e);\n\n\t\t\tRefresh();\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Calculates the image displayed by the control\n\t\t/// </summary>\n\t\tprivate void CreateDisplay()\n\t\t{\n\t\t\tif (m_Image != null)\n\t\t\t{\n\t\t\t\tm_Image.Dispose();\n\t\t\t}\n\n\t\t\tswitch (m_Art)\n\t\t\t{\n\t\t\t\tcase Art.Items:\n\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tm_Image = new Bitmap(Ultima.Art.GetStatic(m_ArtIndex));\n\t\t\t\t\t}\n\t\t\t\t\tcatch\n\t\t\t\t\t{\n\t\t\t\t\t\tm_Image = null;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t/*case Art.Gumps:\n\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tm_Image = new Bitmap(Gumps.GetGump(m_ArtIndex));\n\t\t\t\t\t}\n\t\t\t\t\tcatch\n\t\t\t\t\t{\n\t\t\t\t\t\tm_Image = null;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;*/\n\n\t\t\t\tcase Art.NPCs:\n\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tif (m_Animate)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//m_Image = DoAnimation();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvar hue = m_Hue;\n\n\t\t\t\t\t\t\tvar frames = Animations.GetAnimation(m_ArtIndex, 0, 1, ref hue, true, true);\n\n\t\t\t\t\t\t\tif (frames != null)\n\t\t\t\t\t\t\t\tm_Image = new Bitmap(frames[0].Bitmap);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tm_Image = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch\n\t\t\t\t\t{\n\t\t\t\t\t\tm_Image = null;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Hue\n\t\t\t//\n\t\t\tif (m_Hue > 0 && m_Image != null && m_Art != Art.Images)\n\t\t\t{\n\t\t\t\tif (m_Art != Art.NPCs || (m_Art == Art.NPCs && !m_Animate))\n\t\t\t\t{\n\t\t\t\t\tvar hue = Hues.GetHue(m_Hue - 1);\n\n\t\t\t\t\tif (hue != null)\n\t\t\t\t\t{\n\t\t\t\t\t\tHues.ApplyTo(m_Image, hue.Colors, m_Art == Art.Gumps);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Sets up the animation\n\t\t/// </summary>\n\t\t/// <returns>The current image</returns>\n\t\t/*private Bitmap DoAnimation()\n\t\t{\n\t\t\tif (m_Timer == null)\n\t\t\t{\n\t\t\t\t// Create the animation\n\t\t\t\tvar frames = Animations.GetAnimation(m_ArtIndex, 0, 1, ref m_Hue, true, false);\n\n\t\t\t\tif (frames == null)\n\t\t\t\t\treturn null;\n\n\t\t\t\tvar count = frames.Length;\n\t\t\t\tm_Animation = new Bitmap[count];\n\n\t\t\t\tfor (var i = 0; i < count; i++)\n\t\t\t\t{\n\t\t\t\t\tm_Animation[i] = frames[i].Bitmap;\n\t\t\t\t}\n\n\t\t\t\tm_Timer = new Timer();\n\t\t\t\tm_Timer.Interval = 1000 / count;\n\t\t\t\tm_Timer.Tick += AnimTick;\n\t\t\t\tm_Timer.Start();\n\n\t\t\t\tm_FrameIndex = 0;\n\t\t\t\treturn new Bitmap(m_Animation[0]);\n\t\t\t}\n\t\t\treturn new Bitmap(m_Animation[m_FrameIndex]);\n\t\t}\n\n\t\tprivate void AnimTick(object sender, EventArgs e)\n\t\t{\n\t\t\tm_FrameIndex++;\n\n\t\t\tif (m_FrameIndex == m_Animation.Length)\n\t\t\t\tm_FrameIndex = 0;\n\n\t\t\tm_ImageInvalidated = true;\n\t\t\tRefresh();\n\t\t}\n\n\t\t/// <summary>\n\t\t///     Stops the current animation\n\t\t/// </summary>\n\t\tprivate void StopAnimation()\n\t\t{\n\t\t\tif (m_Timer != null)\n\t\t\t{\n\t\t\t\tif (m_Timer.Enabled)\n\t\t\t\t\tm_Timer.Stop();\n\n\t\t\t\tm_Timer.Dispose();\n\t\t\t\tm_Timer = null;\n\t\t\t}\n\n\t\t\tif (m_Animation != null)\n\t\t\t{\n\t\t\t\tfor (var i = 0; i < m_Animation.Length; i++)\n\t\t\t\t\tif (m_Animation[i] != null)\n\t\t\t\t\t\tm_Animation[i].Dispose();\n\t\t\t}\n\n\t\t\tm_Animation = null;\n\t\t\tm_FrameIndex = 0;\n\t\t}*/\n    }\n}"
  },
  {
    "path": "Razor/UI/BuffDebuffOptions.Designer.cs",
    "content": "﻿namespace Assistant.UI\n{\n    partial class BuffDebuffOptions\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BuffDebuffOptions));\n            this.grpFilter = new System.Windows.Forms.GroupBox();\n            this.removeFilter = new System.Windows.Forms.Button();\n            this.addFilter = new System.Windows.Forms.Button();\n            this.buffDebuffFilters = new System.Windows.Forms.ListBox();\n            this.lblSeconds = new System.Windows.Forms.Label();\n            this.buffDebuffSeconds = new System.Windows.Forms.TextBox();\n            this.displayBuffDebuffEvery = new System.Windows.Forms.CheckBox();\n            this.buffDebuffFormat = new System.Windows.Forms.TextBox();\n            this.setDebuffHue = new System.Windows.Forms.Button();\n            this.lblDebuffHue = new System.Windows.Forms.Label();\n            this.setBuffHue = new System.Windows.Forms.Button();\n            this.lblBuffHue = new System.Windows.Forms.Label();\n            this.buffFormatKey = new System.Windows.Forms.Button();\n            this.okClose = new System.Windows.Forms.Button();\n            this.overrideBuffDebuffFormat = new System.Windows.Forms.CheckBox();\n            this.grpFilter.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // grpFilter\n            // \n            this.grpFilter.Controls.Add(this.removeFilter);\n            this.grpFilter.Controls.Add(this.addFilter);\n            this.grpFilter.Controls.Add(this.buffDebuffFilters);\n            this.grpFilter.Location = new System.Drawing.Point(12, 12);\n            this.grpFilter.Name = \"grpFilter\";\n            this.grpFilter.Size = new System.Drawing.Size(319, 140);\n            this.grpFilter.TabIndex = 65;\n            this.grpFilter.TabStop = false;\n            this.grpFilter.Text = \"Filter:\";\n            // \n            // removeFilter\n            // \n            this.removeFilter.Location = new System.Drawing.Point(230, 57);\n            this.removeFilter.Name = \"removeFilter\";\n            this.removeFilter.Size = new System.Drawing.Size(83, 29);\n            this.removeFilter.TabIndex = 76;\n            this.removeFilter.Text = \"Remove\";\n            this.removeFilter.UseVisualStyleBackColor = true;\n            this.removeFilter.Click += new System.EventHandler(this.RemoveFilter_Click);\n            // \n            // addFilter\n            // \n            this.addFilter.Location = new System.Drawing.Point(230, 22);\n            this.addFilter.Name = \"addFilter\";\n            this.addFilter.Size = new System.Drawing.Size(83, 29);\n            this.addFilter.TabIndex = 75;\n            this.addFilter.Text = \"Add\";\n            this.addFilter.UseVisualStyleBackColor = true;\n            this.addFilter.Click += new System.EventHandler(this.AddFilter_Click);\n            // \n            // buffDebuffFilters\n            // \n            this.buffDebuffFilters.FormattingEnabled = true;\n            this.buffDebuffFilters.ItemHeight = 15;\n            this.buffDebuffFilters.Location = new System.Drawing.Point(6, 22);\n            this.buffDebuffFilters.Name = \"buffDebuffFilters\";\n            this.buffDebuffFilters.Size = new System.Drawing.Size(218, 109);\n            this.buffDebuffFilters.TabIndex = 74;\n            // \n            // lblSeconds\n            // \n            this.lblSeconds.AutoSize = true;\n            this.lblSeconds.Location = new System.Drawing.Point(225, 213);\n            this.lblSeconds.Name = \"lblSeconds\";\n            this.lblSeconds.Size = new System.Drawing.Size(50, 15);\n            this.lblSeconds.TabIndex = 82;\n            this.lblSeconds.Text = \"seconds\";\n            // \n            // buffDebuffSeconds\n            // \n            this.buffDebuffSeconds.Location = new System.Drawing.Point(175, 210);\n            this.buffDebuffSeconds.Name = \"buffDebuffSeconds\";\n            this.buffDebuffSeconds.Size = new System.Drawing.Size(47, 23);\n            this.buffDebuffSeconds.TabIndex = 81;\n            this.buffDebuffSeconds.Text = \"20\";\n            this.buffDebuffSeconds.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.buffDebuffSeconds.TextChanged += new System.EventHandler(this.BuffDebuffSeconds_TextChanged);\n            // \n            // displayBuffDebuffEvery\n            // \n            this.displayBuffDebuffEvery.AutoSize = true;\n            this.displayBuffDebuffEvery.Location = new System.Drawing.Point(18, 212);\n            this.displayBuffDebuffEvery.Name = \"displayBuffDebuffEvery\";\n            this.displayBuffDebuffEvery.Size = new System.Drawing.Size(160, 19);\n            this.displayBuffDebuffEvery.TabIndex = 80;\n            this.displayBuffDebuffEvery.Text = \"Display buff/debuff every\";\n            this.displayBuffDebuffEvery.UseVisualStyleBackColor = true;\n            this.displayBuffDebuffEvery.CheckedChanged += new System.EventHandler(this.DisplayBuffDebuffEvery_CheckedChanged);\n            // \n            // buffDebuffFormat\n            // \n            this.buffDebuffFormat.Location = new System.Drawing.Point(18, 183);\n            this.buffDebuffFormat.Name = \"buffDebuffFormat\";\n            this.buffDebuffFormat.Size = new System.Drawing.Size(224, 23);\n            this.buffDebuffFormat.TabIndex = 79;\n            this.buffDebuffFormat.Text = \"[{action}{name} {duration}]\";\n            this.buffDebuffFormat.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.buffDebuffFormat.TextChanged += new System.EventHandler(this.BuffDebuffFormat_TextChanged);\n            // \n            // setDebuffHue\n            // \n            this.setDebuffHue.Location = new System.Drawing.Point(175, 260);\n            this.setDebuffHue.Name = \"setDebuffHue\";\n            this.setDebuffHue.Size = new System.Drawing.Size(47, 20);\n            this.setDebuffHue.TabIndex = 78;\n            this.setDebuffHue.Text = \"Set\";\n            this.setDebuffHue.Click += new System.EventHandler(this.SetDebuffHue_Click);\n            // \n            // lblDebuffHue\n            // \n            this.lblDebuffHue.Location = new System.Drawing.Point(15, 262);\n            this.lblDebuffHue.Name = \"lblDebuffHue\";\n            this.lblDebuffHue.Size = new System.Drawing.Size(207, 18);\n            this.lblDebuffHue.TabIndex = 77;\n            this.lblDebuffHue.Text = \"Debuff Hue:\";\n            // \n            // setBuffHue\n            // \n            this.setBuffHue.Location = new System.Drawing.Point(175, 237);\n            this.setBuffHue.Name = \"setBuffHue\";\n            this.setBuffHue.Size = new System.Drawing.Size(47, 20);\n            this.setBuffHue.TabIndex = 76;\n            this.setBuffHue.Text = \"Set\";\n            this.setBuffHue.Click += new System.EventHandler(this.SetBuffHue_Click);\n            // \n            // lblBuffHue\n            // \n            this.lblBuffHue.Location = new System.Drawing.Point(15, 239);\n            this.lblBuffHue.Name = \"lblBuffHue\";\n            this.lblBuffHue.Size = new System.Drawing.Size(207, 18);\n            this.lblBuffHue.TabIndex = 75;\n            this.lblBuffHue.Text = \"Buff Hue:\";\n            // \n            // buffFormatKey\n            // \n            this.buffFormatKey.Location = new System.Drawing.Point(248, 183);\n            this.buffFormatKey.Name = \"buffFormatKey\";\n            this.buffFormatKey.Size = new System.Drawing.Size(16, 23);\n            this.buffFormatKey.TabIndex = 84;\n            this.buffFormatKey.Text = \"?\";\n            this.buffFormatKey.UseVisualStyleBackColor = true;\n            this.buffFormatKey.Click += new System.EventHandler(this.BuffFormatKey_Click);\n            // \n            // okClose\n            // \n            this.okClose.Location = new System.Drawing.Point(248, 251);\n            this.okClose.Name = \"okClose\";\n            this.okClose.Size = new System.Drawing.Size(83, 29);\n            this.okClose.TabIndex = 85;\n            this.okClose.Text = \"OK\";\n            this.okClose.UseVisualStyleBackColor = true;\n            this.okClose.Click += new System.EventHandler(this.OkClose_Click);\n            // \n            // overrideBuffDebuffFormat\n            // \n            this.overrideBuffDebuffFormat.AutoSize = true;\n            this.overrideBuffDebuffFormat.Location = new System.Drawing.Point(18, 158);\n            this.overrideBuffDebuffFormat.Name = \"overrideBuffDebuffFormat\";\n            this.overrideBuffDebuffFormat.Size = new System.Drawing.Size(175, 19);\n            this.overrideBuffDebuffFormat.TabIndex = 86;\n            this.overrideBuffDebuffFormat.Text = \"Override buff/debuff format\";\n            this.overrideBuffDebuffFormat.UseVisualStyleBackColor = true;\n            this.overrideBuffDebuffFormat.CheckedChanged += new System.EventHandler(this.overrideBuffDebuffFormat_CheckedChanged);\n            // \n            // BuffDebuff\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(341, 291);\n            this.Controls.Add(this.overrideBuffDebuffFormat);\n            this.Controls.Add(this.okClose);\n            this.Controls.Add(this.buffFormatKey);\n            this.Controls.Add(this.lblSeconds);\n            this.Controls.Add(this.buffDebuffSeconds);\n            this.Controls.Add(this.displayBuffDebuffEvery);\n            this.Controls.Add(this.buffDebuffFormat);\n            this.Controls.Add(this.setDebuffHue);\n            this.Controls.Add(this.lblDebuffHue);\n            this.Controls.Add(this.setBuffHue);\n            this.Controls.Add(this.lblBuffHue);\n            this.Controls.Add(this.grpFilter);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.MaximizeBox = false;\n            this.Name = \"BuffDebuff\";\n            this.ShowIcon = false;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\n            this.Text = \"Buff/Debuff Options\";\n            this.Closing += new System.ComponentModel.CancelEventHandler(this.BuffDebuff_Closing);\n            this.Load += new System.EventHandler(this.BuffDebuff_Load);\n            this.grpFilter.ResumeLayout(false);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.GroupBox grpFilter;\n        private System.Windows.Forms.Button removeFilter;\n        private System.Windows.Forms.Button addFilter;\n        private System.Windows.Forms.ListBox buffDebuffFilters;\n        private System.Windows.Forms.Label lblSeconds;\n        private System.Windows.Forms.TextBox buffDebuffSeconds;\n        private System.Windows.Forms.CheckBox displayBuffDebuffEvery;\n        private System.Windows.Forms.TextBox buffDebuffFormat;\n        private System.Windows.Forms.Button setDebuffHue;\n        private System.Windows.Forms.Label lblDebuffHue;\n        private System.Windows.Forms.Button setBuffHue;\n        private System.Windows.Forms.Label lblBuffHue;\n        private System.Windows.Forms.Button buffFormatKey;\n        private System.Windows.Forms.Button okClose;\n        private System.Windows.Forms.CheckBox overrideBuffDebuffFormat;\n    }\n}"
  },
  {
    "path": "Razor/UI/BuffDebuffOptions.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.ComponentModel;\nusing System.Drawing;\nusing System.Text;\nusing System.Windows.Forms;\nusing Assistant.Core;\n\nnamespace Assistant.UI\n{\n    public partial class BuffDebuffOptions : Form\n    {\n        public BuffDebuffOptions()\n        {\n            InitializeComponent();\n        }\n\n        private void SetBuffHue_Click(object sender, EventArgs e)\n        {\n            lblBuffHue.SafeAction(s => { SetHue(s, \"BuffHue\"); });\n        }\n\n        private void SetDebuffHue_Click(object sender, EventArgs e)\n        {\n            lblDebuffHue.SafeAction(s => { SetHue(s, \"DebuffHue\"); });\n        }\n\n        private void SetHue(Control ctrl, string cfg)\n        {\n            HueEntry h = new HueEntry(Config.GetInt(cfg));\n\n            if (h.ShowDialog(this) == DialogResult.OK)\n            {\n                int hueIdx = h.Hue;\n                Config.SetProperty(cfg, hueIdx);\n                if (hueIdx > 0 && hueIdx < 3000)\n                    ctrl.BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n                else\n                    ctrl.BackColor = Color.White;\n                ctrl.ForeColor = (ctrl.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\n            }\n        }\n\n        private void InitPreviewHue(Control ctrl, string cfg)\n        {\n            int hueIdx = Config.GetInt(cfg);\n            if (hueIdx > 0 && hueIdx < 3000)\n                ctrl.BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n            else\n                ctrl.BackColor = SystemColors.Control;\n            ctrl.ForeColor = (ctrl.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\n        }\n\n        private void BuffDebuffFormat_TextChanged(object sender, EventArgs e)\n        {\n            if (string.IsNullOrEmpty(buffDebuffFormat.Text))\n            {\n                Config.SetProperty(\"BuffDebuffFormat\", \"[{action}{name} {duration}]\");\n            }\n            else\n            {\n                Config.SetProperty(\"BuffDebuffFormat\", buffDebuffFormat.Text);\n            }\n        }\n\n        private void BuffDebuffSeconds_TextChanged(object sender, EventArgs e)\n        {\n            Config.SetProperty(\"BuffDebuffSeconds\", Utility.ToInt32(buffDebuffSeconds.Text.Trim(), 20));\n\n            if (Config.GetInt(\"BuffDebuffSeconds\") < 1)\n                Config.SetProperty(\"BuffDebuffSeconds\", 20);\n        }\n\n        private void DisplayBuffDebuffEvery_CheckedChanged(object sender, EventArgs e)\n        {\n            Config.SetProperty(\"BuffDebuffEveryXSeconds\", displayBuffDebuffEvery.Checked);\n        }\n\n        private void BtnOk_Click(object sender, EventArgs e)\n        {\n            Hide();\n        }\n\n        private void AddFilter_Click(object sender, EventArgs e)\n        {\n            if (InputBox.Show(this, \"Filter Buff/Debuff\",\n                \"Enter part or the whole name of the buff to filter it from showing overhead\"))\n            {\n                string name = InputBox.GetString();\n\n                if (!string.IsNullOrEmpty(name))\n                {\n                    buffDebuffFilters.Items.Add(name.Trim());\n                }\n            }\n\n            SaveFilter();\n        }\n\n        private void BuffDebuff_Load(object sender, EventArgs e)\n        {\n            buffDebuffFilters.Items.Clear();\n\n            foreach (string filter in Config.GetString(\"BuffDebuffFilter\").Split(','))\n            {\n                if (string.IsNullOrEmpty(filter))\n                    continue;\n\n                buffDebuffFilters.Items.Add(filter);\n            }\n\n            buffDebuffFormat.SafeAction(s => s.Text = Config.GetString(\"BuffDebuffFormat\"));\n            buffDebuffSeconds.SafeAction(s => s.Text = Convert.ToString(Config.GetInt(\"BuffDebuffSeconds\")));\n            displayBuffDebuffEvery.SafeAction(s => s.Checked = Config.GetBool(\"BuffDebuffEveryXSeconds\"));\n            overrideBuffDebuffFormat.SafeAction(s => s.Checked = Config.GetBool(\"OverrideBuffDebuffFormat\"));\n\n            lblBuffHue.SafeAction(s => { InitPreviewHue(s, \"BuffHue\"); });\n            lblDebuffHue.SafeAction(s => { InitPreviewHue(s, \"DebuffHue\"); });\n        }\n\n        private void RemoveFilter_Click(object sender, EventArgs e)\n        {\n            if (buffDebuffFilters.SelectedIndex < 0)\n                return;\n\n            buffDebuffFilters.Items.RemoveAt(buffDebuffFilters.SelectedIndex);\n\n            SaveFilter();\n        }\n\n        private void BuffFormatKey_Click(object sender, EventArgs e)\n        {\n            StringBuilder sb = new StringBuilder();\n            sb.AppendLine(\"You can insert these variables into the buff/debuff format box.\");\n            sb.AppendLine(string.Empty);\n            sb.AppendLine(\"{name} - The name of the buff/debuff\");\n            sb.AppendLine(\"{action} - + or - depending if you gain or lose the buff/debuff\");\n            sb.AppendLine(\"{duration} - Time in seconds left for the buff/debuff\");\n\n            MessageBox.Show(this, sb.ToString(), \"Buff/Debuff Format\", MessageBoxButtons.OK,\n                MessageBoxIcon.Information);\n        }\n\n        private void SaveFilter()\n        {\n            StringBuilder sb = new StringBuilder();\n            foreach (var item in buffDebuffFilters.Items)\n            {\n                sb.Append($\"{item},\");\n            }\n\n            Config.SetProperty(\"BuffDebuffFilter\", sb.ToString());\n\n            BuffDebuffManager.ReloadFilter();\n        }\n\n        private void OkClose_Click(object sender, EventArgs e)\n        {\n            this.SafeAction(s => s.Hide());\n        }\n\n        private void BuffDebuff_Closing(object sender, CancelEventArgs e)\n        {\n            this.SafeAction(s =>\n            {\n                e.Cancel = true;\n                s.Hide();\n            });\n        }\n\n        private void overrideBuffDebuffFormat_CheckedChanged(object sender, EventArgs e)\n        {\n            Config.SetProperty(\"OverrideBuffDebuffFormat\", displayBuffDebuffEvery.Checked);\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/BuffDebuffOptions.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAAAAACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAQAAAAAAAAAAAAAAAEAAAAB\n        AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYW\n        FgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAA\n        MwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm\n        /wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/\n        zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNm\n        ZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM\n        /wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYz\n        mQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbM\n        MwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkz\n        MwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnM\n        AACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwA\n        mQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZ\n        MwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/\n        zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9m\n        zADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/\n        ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKy\n        sgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//\n        AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK\n        CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCrcKCgoKCgoKCgoKCgoK\n        CgoKCgoKCgoKCgoKCgoKCgoK+QoKCgoKCgoKCgrSCgoKCgoKCgoKCgoKCgoKCgoKCgr5+QoKCgoKCgr5\n        sQoKCgoKCgoKCgoKCgoKCgoKCgoKCvn5CgoKCgoKsbEKCgoKCgoKCgoKCgoKCgoKCgoKCgoK+ZQKCgoK\n        CuPjCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr5sQoKCgpHsQoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgpq\n        Cgr5QbEKCgqxtwoKCgoKCgr5CgoK+QoKCgoKCgoKCuP5lPmUCgoKCrGxt7f5+fkKCvkK+fkKCgoKCgoK\n        CgoKFkH5lAoK+QoK+bcKCgr5t7cK+fn5CgoKCgoKCgoKCrdB+fkKCgoK0rext7EKCvn5Crf5+QoKCgoK\n        CgoKCgqx+UdBCgoKCgq3+fkKt5QK+fkK0vn5CgoKCgoKCgoKCgq3+UGUCgoKCvmxtwoKsbcK+QqUCvn5\n        +QoKCgoKCgoKCgr5F0f5CgoKCmqxCgoKavn5+eP5arexagoKCgoKCgoKCgqU+Wrj+QoKt7cKRmlq+Qq3\n        lJQXF+MWCgoKCgoKCgoKCvn5+flq4/kKCuvs7O0KCgoKCgoKCgoKCgoKCgoKCgoKCkfjCgoWRxaSku3s\n        7OwKCgoKCgoKCgoKCgoKCgoKCgoK+fkKCgr5bpKS7e3t7eztCgoKCgoKCgoKCgoKCgoKCgr5+ZQKCgqS\n        kpLt7e3t7e3tCgoKCgoKCgoKCgoKCgoKCgr54woK7++SkpLt7e3t7Ozs7fcKCgoKCgoKCgoKCrHjFkEX\n        FhZpku/3kpLt7e3s7Ozs7JIKCgoKCgoKCgoKR/n5+fn5+fkg7e+SkpLt7Ozs7Ozs7ZIKCgoKCgoKCgpH\n        QUFBQUcXahbt95KS7e3s7Ozs7Oztkvf3CgoKCgoKCgoKCgrs6+wKCpKS7e3t7Ozs7Ozt7ZL39+/vCgoK\n        CgoKCgoKCuzr6uzs7ZLt7ezs7Ozs7ZKS9+/v7+/vCgoKCgoKCgrr7JLrbeyS7ezs7Ozs7ZKS9/fv7wcH\n        BwcKCgoKCgoK7BLs7/fs7Ozs7Ozs7O2S9+/v7+8HBwcHBwoKCgoKCgoSbe8H7+zt7Ovs7O2Skvfv7+8H\n        BwcHBwcHCgoKCgoK7ezv7++S7O3v9+zs9/fv7+8HBwcHBwcH8fAKCgoKCuwS6+ztkvfv7+8HB/f3B7y8\n        vPDw8PDwvPP/8/////////////////f////3/v//8/n///Pz///z5///88////sc/u/4PAaf+GziP/Dw\n        ZH/h8SR/8PGVH/h5wA/8GQgP/AYf//5gD//+cAP//jgB//8wAD/4AAAf+AAAD/gAAAP/jAAB/4AAAP8A\n        AAD+AAAA/gAAAPwAAAD4AAAA\n</value>\n  </data>\n</root>"
  },
  {
    "path": "Razor/UI/Config.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Xml;\r\nusing System.IO;\r\nusing System.Reflection;\r\nusing System.Text;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing System.Configuration;\r\nusing System.Windows.Forms;\r\nusing Assistant.Agents;\r\nusing Assistant.Core;\r\nusing Assistant.Filters;\r\nusing Assistant.Macros;\r\nusing Assistant.Scripts;\r\nusing Assistant.UI;\r\nusing ContainerLabels = Assistant.Core.ContainerLabels;\r\n\r\nnamespace Assistant\r\n{\r\n    public class Profile\r\n    {\r\n        private string m_Name;\r\n        private Dictionary<string, object> m_Props;\r\n        private System.Threading.Mutex m_Mutex;\r\n\r\n        public Profile(string name)\r\n        {\r\n            Name = name;\r\n            m_Props = new Dictionary<string, object>(16, StringComparer.OrdinalIgnoreCase);\r\n\r\n            MakeDefault();\r\n        }\r\n\r\n        public void MakeDefault()\r\n        {\r\n            m_Props.Clear();\r\n\r\n            AddProperty(\"ShowMobNames\", false);\r\n            AddProperty(\"ShowCorpseNames\", false);\r\n            AddProperty(\"DisplaySkillChanges\", false);\r\n\r\n            if (Client.IsOSI)\r\n                AddProperty(\"TitleBarText\", @\"UO - {char} {crimtime}- {mediumstatbar} {bp} {bm} {gl} {gs} {mr} {ns} {ss} {sa} {aids}\");\r\n            else\r\n                AddProperty(\"TitleBarText\", @\"UO - {char}\");\r\n\r\n            AddProperty(\"TitleBarDisplay\", true);\r\n            AddProperty(\"AutoSearch\", true);\r\n            AddProperty(\"NoSearchPouches\", true);\r\n            AddProperty(\"CounterWarnAmount\", (int) 5);\r\n            AddProperty(\"CounterWarn\", true);\r\n            AddProperty(\"ObjectDelay\", (int) 600);\r\n            AddProperty(\"ObjectDelayEnabled\", true);\r\n            AddProperty(\"AlwaysOnTop\", false);\r\n            AddProperty(\"SortCounters\", true);\r\n            AddProperty(\"QueueActions\", false);\r\n            AddProperty(\"QueueTargets\", false);\r\n            AddProperty(\"WindowX\", (int) 400);\r\n            AddProperty(\"WindowY\", (int) 400);\r\n            AddProperty(\"CountStealthSteps\", true);\r\n\r\n            AddProperty(\"SysColor\", (int) 0x0044);\r\n            AddProperty(\"WarningColor\", (int) 0x0025);\r\n            AddProperty(\"ExemptColor\", (int) 0x0480);\r\n            AddProperty(\"SpeechHue\", (int) 0x03B1);\r\n            AddProperty(\"BeneficialSpellHue\", (int) 0x0005);\r\n            AddProperty(\"HarmfulSpellHue\", (int) 0x0058);\r\n            AddProperty(\"NeutralSpellHue\", (int) 0x03B1);\r\n            AddProperty(\"ForceSpeechHue\", false);\r\n            AddProperty(\"ForceSpellHue\", true);\r\n            AddProperty(\"SpellFormat\", @\"{power} [{spell}]\");\r\n\r\n            AddProperty(\"ShowNotoHue\", true);\r\n            AddProperty(\"Opacity\", (int) 100);\r\n\r\n            AddProperty(\"AutoOpenCorpses\", false);\r\n            AddProperty(\"CorpseRange\", (int) 2);\r\n\r\n            AddProperty(\"BlockDismount\", false);\r\n\r\n            AddProperty(\"CapFullScreen\", false);\r\n            AddProperty(\"CapPath\",\r\n                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), \"RazorScreenShots\"));\r\n            AddProperty(\"CapTimeStamp\", true);\r\n            AddProperty(\"ImageFormat\", \"jpg\");\r\n\r\n            AddProperty(\"UndressConflicts\", true);\r\n            AddProperty(\"HighlightReagents\", true);\r\n            AddProperty(\"Systray\", false);\r\n            AddProperty(\"TitlebarImages\", true);\r\n\r\n            AddProperty(\"SellAgentMax\", (int) 99);\r\n            AddProperty(\"SkillListCol\", (int) -1);\r\n            AddProperty(\"SkillListAsc\", false);\r\n\r\n            AddProperty(\"AutoStack\", false);\r\n            AddProperty(\"ActionStatusMsg\", true);\r\n            AddProperty(\"RememberPwds\", false);\r\n\r\n            AddProperty(\"SpellUnequip\", true);\r\n            AddProperty(\"RangeCheckLT\", true);\r\n            AddProperty(\"LTRange\", (int) 12);\r\n\r\n            AddProperty(\"FilterSnoopMsg\", true);\r\n            AddProperty(\"OldStatBar\", false);\r\n\r\n            AddProperty(\"SmartLastTarget\", false);\r\n            AddProperty(\"LastTargTextFlags\", true);\r\n            //AddProperty(\"SmartCPU\", false);\r\n            AddProperty(\"LTHilight\", (int) 0);\r\n\r\n            AddProperty(\"AutoFriend\", false);\r\n\r\n            AddProperty(\"AutoOpenDoors\", true);\r\n\r\n            AddProperty(\"MessageLevel\", 0);\r\n\r\n            AddProperty(\"ForceIP\", \"\");\r\n            AddProperty(\"ForcePort\", 0);\r\n\r\n            AddProperty(\"ForceSizeEnabled\", false);\r\n            AddProperty(\"ForceSizeX\", 1000);\r\n            AddProperty(\"ForceSizeY\", 800);\r\n\r\n            AddProperty(\"PotionEquip\", false);\r\n            AddProperty(\"BlockHealPoison\", true);\r\n\r\n            AddProperty(\"SmoothWalk\", false);\r\n\r\n            AddProperty(\"Negotiate\", true);\r\n\r\n            AddProperty(\"MapX\", 200);\r\n            AddProperty(\"MapY\", 200);\r\n            AddProperty(\"MapW\", 200);\r\n            AddProperty(\"MapH\", 200);\r\n\r\n            AddProperty(\"LogPacketsByDefault\", false);\r\n\r\n            AddProperty(\"ShowHealth\", true);\r\n            AddProperty(\"HealthFmt\", \"[{0}%]\");\r\n            AddProperty(\"ShowPartyStats\", true);\r\n            AddProperty(\"PartyStatFmt\", \"[{0}% / {1}%]\");\r\n\r\n            AddProperty(\"HotKeyStop\", false);\r\n            AddProperty(\"DiffTargetByType\", false);\r\n            AddProperty(\"StepThroughMacro\", false);\r\n\r\n            AddProperty(\"ShowTargetSelfLastClearOverhead\", true);\r\n            AddProperty(\"ShowOverheadMessages\", false);\r\n            AddProperty(\"CaptureMibs\", false);\r\n\r\n            //OverheadFormat\r\n            AddProperty(\"OverheadFormat\", \"[{msg}]\");\r\n            AddProperty(\"OverheadStyle\", 1);\r\n\r\n            AddProperty(\"GoldPerDisplay\", false);\r\n\r\n            AddProperty(\"LightLevel\", 31);\r\n            AddProperty(\"LogSkillChanges\", false);\r\n            AddProperty(\"StealthOverhead\", false);\r\n\r\n            AddProperty(\"ShowBuffDebuffOverhead\", true);\r\n            AddProperty(\"BuffDebuffFormat\", \"[{action}{name} {duration}]\");\r\n\r\n            AddProperty(\"BlockOpenCorpsesTwice\", false);\r\n\r\n            AddProperty(\"ShowAttackTargetOverhead\", true);\r\n\r\n            AddProperty(\"RangeCheckTargetByType\", false);\r\n            AddProperty(\"RangeCheckDoubleClick\", false);\r\n\r\n            AddProperty(\"ShowContainerLabels\", false);\r\n            AddProperty(\"ContainerLabelFormat\", \"[{label}] ({type})\");\r\n            AddProperty(\"ContainerLabelColor\", 88);\r\n            AddProperty(\"ContainerLabelStyle\", 1);\r\n\r\n            AddProperty(\"Season\", 5);\r\n\r\n            AddProperty(\"BlockTradeRequests\", false);\r\n            AddProperty(\"BlockPartyInvites\", false);\r\n            AddProperty(\"AutoAcceptParty\", false);\r\n\r\n            AddProperty(\"MaxLightLevel\", 31);\r\n            AddProperty(\"MinLightLevel\", 0);\r\n            AddProperty(\"MinMaxLightLevelEnabled\", false);\r\n            AddProperty(\"ShowStaticWalls\", false);\r\n            AddProperty(\"ShowStaticWallLabels\", false);\r\n\r\n            AddProperty(\"ShowTextTargetIndicator\", false);\r\n            AddProperty(\"ShowAttackTargetNewOnly\", true);\r\n\r\n            AddProperty(\"FilterDragonGraphics\", false);\r\n            AddProperty(\"FilterDrakeGraphics\", false);\r\n            AddProperty(\"DragonGraphic\", 0);\r\n            AddProperty(\"DrakeGraphic\", 0);\r\n\r\n            AddProperty(\"ShowDamageDealt\", false);\r\n            AddProperty(\"ShowDamageDealtOverhead\", false);\r\n            AddProperty(\"ShowDamageTaken\", false);\r\n            AddProperty(\"ShowDamageTakenOverhead\", false);\r\n\r\n            AddProperty(\"ShowInRazorTitleBar\", false);\r\n            AddProperty(\"RazorTitleBarText\", \"{name} on {account} ({profile} - {shard}) - Razor v{version}\");\r\n\r\n            AddProperty(\"EnableUOAAPI\", true);\r\n\r\n            AddProperty(\"TargetIndicatorFormat\", \"* Target *\");\r\n\r\n            AddProperty(\"NextPrevTargetIgnoresFriends\", false);\r\n\r\n            AddProperty(\"StealthStepsFormat\", \"Steps: {step}\");\r\n\r\n            AddProperty(\"ShowFriendOverhead\", false);\r\n\r\n            AddProperty(\"DisplaySkillChangesOverhead\", false);\r\n\r\n            AddProperty(\"GrabHotBag\", \"0\");\r\n\r\n            // Enable it for OSI client by default, CUO turn it off\r\n            AddProperty(\"MacroActionDelay\", Client.IsOSI);\r\n\r\n            AddProperty(\"AutoOpenDoorWhenHidden\", false);\r\n\r\n            AddProperty(\"DisableMacroPlayFinish\", false);\r\n\r\n            AddProperty(\"ShowBandageTimer\", false);\r\n            AddProperty(\"ShowBandageTimerFormat\", \"Bandage: {count}s\");\r\n            AddProperty(\"ShowBandageTimerLocation\", 0);\r\n            AddProperty(\"OnlyShowBandageTimerEvery\", false);\r\n            AddProperty(\"OnlyShowBandageTimerSeconds\", 1);\r\n            AddProperty(\"ShowBandageTimerHue\", 88);\r\n\r\n            AddProperty(\"TargetIndicatorHue\", 10);\r\n\r\n            AddProperty(\"FilterSystemMessages\", false);\r\n            AddProperty(\"FilterRazorMessages\", false);\r\n            AddProperty(\"FilterDelay\", 3.5);\r\n            AddProperty(\"FilterOverheadMessages\", false);\r\n\r\n            AddProperty(\"OnlyNextPrevBeneficial\", false);\r\n            AddProperty(\"FriendlyBeneficialOnly\", false);\r\n            AddProperty(\"NonFriendlyHarmfulOnly\", false);\r\n\r\n            AddProperty(\"ShowBandageStart\", false);\r\n            AddProperty(\"BandageStartMessage\", \"Bandage: Starting\");\r\n            AddProperty(\"ShowBandageEnd\", false);\r\n            AddProperty(\"BandageEndMessage\", \"Bandage: Ending\");\r\n\r\n            AddProperty(\"BuffDebuffSeconds\", 20);\r\n            AddProperty(\"BuffHue\", 88);\r\n            AddProperty(\"DebuffHue\", 338);\r\n            AddProperty(\"DisplayBuffDebuffEvery\", false);\r\n            AddProperty(\"BuffDebuffFilter\", string.Empty);\r\n            AddProperty(\"BuffDebuffEveryXSeconds\", false);\r\n\r\n            AddProperty(\"CaptureOthersDeathDelay\", 0.5);\r\n            AddProperty(\"CaptureOwnDeathDelay\", 0.5);\r\n            AddProperty(\"CaptureOthersDeath\", false);\r\n            AddProperty(\"CaptureOwnDeath\", false);\r\n\r\n            AddProperty(\"TargetFilterEnabled\", false);\r\n\r\n            AddProperty(\"FilterDaemonGraphics\", false);\r\n            AddProperty(\"DaemonGraphic\", 0);\r\n\r\n            AddProperty(\"SoundFilterEnabled\", false);\r\n            AddProperty(\"ShowFilteredSound\", false);\r\n            AddProperty(\"ShowPlayingSoundInfo\", false);\r\n            AddProperty(\"ShowMusicInfo\", false);\r\n\r\n            AddProperty(\"AutoSaveScript\", false);\r\n            AddProperty(\"AutoSaveScriptPlay\", false);\r\n\r\n            AddProperty(\"HighlightFriend\", false);\r\n            \r\n            AddProperty(\"ScriptDisablePlayFinish\", false);\r\n\r\n            AddProperty(\"ShowWaypointOverhead\", true);\r\n            AddProperty(\"ShowWaypointDistance\", true);\r\n            AddProperty(\"ShowWaypointSeconds\", 10);\r\n\r\n            AddProperty(\"ClearWaypoint\", false);\r\n            AddProperty(\"HideWaypointDistance\", 4);\r\n\r\n            AddProperty(\"CreateWaypointOnDeath\", false);\r\n\r\n            AddProperty(\"ShowPartyFriendOverhead\", false);\r\n\r\n            AddProperty(\"OverrideSpellFormat\", true);\r\n\r\n            AddProperty(\"PotionReequip\", true);\r\n\r\n            AddProperty(\"EnableTextFilter\", false);\r\n\r\n            AddProperty(\"DisableScriptTooltips\", false);\r\n\r\n            AddProperty(\"BuyAgentsIgnoreGold\", false);\r\n            \r\n            AddProperty(\"OverrideBuffDebuffFormat\", false);\r\n\r\n            AddProperty(\"NextPrevAlphabetical\", false);\r\n\r\n            AddProperty(\"FilterWyrmGraphics\", false);\r\n            AddProperty(\"WyrmGraphic\", 0);\r\n\r\n            AddProperty(\"WindowSizeX\", 546);\r\n            AddProperty(\"WindowSizeY\", 411);\r\n\r\n            AddProperty(\"PlayEmoteSound\", false);\r\n\r\n            AddProperty(\"ShowBuffDebuffGump\", false);\r\n            AddProperty(\"ShowBuffDebuffIcons\", true);\r\n            AddProperty(\"ShowBuffDebuffWidth\", 100);\r\n            AddProperty(\"ShowBuffDebuffHeight\", 18);\r\n            AddProperty(\"ShowBuffDebuffSort\", 2);\r\n            AddProperty(\"UseBlackBuffDebuffBg\", false);\r\n            AddProperty(\"ShowBuffDebuffTimeType\", 0);\r\n            \r\n            AddProperty(\"DefaultScriptDelay\", true);\r\n            AddProperty(\"EnableHighlight\", false);\r\n            AddProperty(\"DisableScriptStopwatch\", false);\r\n\r\n            AddProperty(\"CooldownHeight\", 28);\r\n            AddProperty(\"CooldownWidth\", 110);\r\n\r\n            Counter.Default();\r\n            Filter.DisableAll();\r\n            DressList.ClearAll();\r\n            HotKey.ClearAll();\r\n            Agent.ClearAll();\r\n            PasswordMemory.ClearAll();\r\n            FriendsManager.ClearAll();\r\n            WaypointManager.ClearAll();\r\n            TextFilterManager.ClearAll();\r\n            DressList.ClearAll();\r\n            OverheadManager.ClearAll();\r\n            ContainerLabels.ClearAll();\r\n            MacroVariables.ClearAll();\r\n            ScriptVariables.ClearAll();\r\n        }\r\n\r\n        public string Name\r\n        {\r\n            get { return m_Name; }\r\n            set\r\n            {\r\n                if (value != null && value.Trim() != \"\")\r\n                {\r\n                    StringBuilder sb = new StringBuilder(value);\r\n                    sb.Replace('\\\\', '_');\r\n                    sb.Replace('/', '_');\r\n                    sb.Replace('\\\"', '\\'');\r\n                    sb.Replace(':', '_');\r\n                    sb.Replace('?', '_');\r\n                    sb.Replace('*', '_');\r\n                    sb.Replace('<', '(');\r\n                    sb.Replace('>', ')');\r\n                    sb.Replace('|', '_');\r\n                    m_Name = sb.ToString();\r\n                }\r\n                else\r\n                {\r\n                    m_Name = \"[No Name]\";\r\n                }\r\n            }\r\n        }\r\n\r\n        private static bool m_Warned = false;\r\n\r\n        public bool Load()\r\n        {\r\n            if (m_Name == null || m_Name.Trim() == \"\")\r\n                return false;\r\n\r\n            string path = Config.GetUserDirectory(\"Profiles\");\r\n            string file = Path.Combine(path, $\"{m_Name}.xml\");\r\n            if (!File.Exists(file))\r\n                return false;\r\n\r\n            XmlDocument doc = new XmlDocument();\r\n            try\r\n            {\r\n                doc.Load(file);\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(Engine.ActiveWindow, Language.Format(LocString.ProfileCorrupt, file),\r\n                    \"Profile Load Error\", MessageBoxButtons.OK, MessageBoxIcon.Stop);\r\n                return false;\r\n            }\r\n\r\n            XmlElement root = doc[\"profile\"];\r\n            if (root == null)\r\n                return false;\r\n\r\n            Assembly exe = Assembly.GetCallingAssembly();\r\n            if (exe == null)\r\n                return false;\r\n\r\n            foreach (XmlElement el in root.GetElementsByTagName(\"property\"))\r\n            {\r\n                try\r\n                {\r\n                    string name = el.GetAttribute(\"name\");\r\n                    string typeStr = el.GetAttribute(\"type\");\r\n                    string val = el.InnerText;\r\n\r\n                    if (typeStr == \"-null-\" || name == \"LimitSize\" || name == \"VisRange\")\r\n                    {\r\n                        //m_Props[name] = null;\r\n                        if (m_Props.ContainsKey(name))\r\n                            m_Props.Remove(name);\r\n                    }\r\n                    else\r\n                    {\r\n                        Type type = Type.GetType(typeStr);\r\n                        if (type == null)\r\n                            type = exe.GetType(typeStr);\r\n\r\n                        if (m_Props.ContainsKey(name) || name == \"ForceSize\")\r\n                        {\r\n                            if (type == null)\r\n                                m_Props.Remove(name);\r\n                            else\r\n                                m_Props[name] = GetObjectFromString(val, type);\r\n                        }\r\n                    }\r\n                }\r\n                catch (Exception e)\r\n                {\r\n                    MessageBox.Show(Engine.ActiveWindow, Language.Format(LocString.ProfileLoadEx, e.ToString()),\r\n                        \"Profile Load Exception\", MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                }\r\n            }\r\n\r\n            Filter.Load(root[\"filters\"]);\r\n            Counter.LoadProfile(root[\"counters\"]);\r\n            Agent.LoadProfile(root[\"agents\"]);\r\n            DressList.Load(root[\"dresslists\"]);\r\n            TargetFilterManager.Load(root[\"targetfilters\"]);\r\n            SoundMusicManager.Load(root[\"soundfilters\"]);\r\n            WaypointManager.Load(root[\"waypoints\"]);\r\n            TextFilterManager.Load(root[\"textfilters\"]);\r\n            FriendsManager.Load(root[\"friends\"]);\r\n            HotKey.Load(root[\"hotkeys\"]);\r\n            PasswordMemory.Load(root[\"passwords\"]);\r\n            OverheadManager.Load(root[\"overheadmessages\"]);\r\n            ContainerLabels.Load(root[\"containerlabels\"]);\r\n            MacroVariables.Load(root[\"macrovariables\"]);\r\n            //imports previous absolutetargets and doubleclickvariables if present in profile\r\n            if ((root.SelectSingleNode(\"absolutetargets\") != null) ||\r\n                (root.SelectSingleNode(\"doubleclickvariables\") != null))\r\n            {\r\n                MacroVariables.Import(root);\r\n            }\r\n\r\n            ScriptVariables.Load(root[\"scriptvariables\"]);\r\n\r\n            GoldPerHourTimer.Stop();\r\n            DamageTracker.Stop();\r\n\r\n            if (m_Props.ContainsKey(\"ForceSize\"))\r\n            {\r\n                try\r\n                {\r\n                    int x, y;\r\n                    switch ((int) m_Props[\"ForceSize\"])\r\n                    {\r\n                        case 1:\r\n                            x = 960;\r\n                            y = 600;\r\n                            break;\r\n                        case 2:\r\n                            x = 1024;\r\n                            y = 768;\r\n                            break;\r\n                        case 3:\r\n                            x = 1152;\r\n                            y = 864;\r\n                            break;\r\n                        case 4:\r\n                            x = 1280;\r\n                            y = 720;\r\n                            break;\r\n                        case 5:\r\n                            x = 1280;\r\n                            y = 768;\r\n                            break;\r\n                        case 6:\r\n                            x = 1280;\r\n                            y = 800;\r\n                            break;\r\n                        case 7:\r\n                            x = 1280;\r\n                            y = 960;\r\n                            break;\r\n                        case 8:\r\n                            x = 1280;\r\n                            y = 1024;\r\n                            break;\r\n\r\n                        case 0:\r\n                        default:\r\n                            x = 800;\r\n                            y = 600;\r\n                            break;\r\n                    }\r\n\r\n                    SetProperty(\"ForceSizeX\", x);\r\n                    SetProperty(\"ForceSizeY\", y);\r\n\r\n                    if (x != 800 || y != 600)\r\n                        SetProperty(\"ForceSizeEnabled\", true);\r\n\r\n                    m_Props.Remove(\"ForceSize\");\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n\r\n            //if ( !Language.Load( GetString( \"Language\" ) ) )\r\n            //\tMessageBox.Show( Engine.ActiveWindow, \"Warning: Could not load language from profile, using current language instead.\", \"Language Error\", MessageBoxButtons.OK, MessageBoxIcon.Warning );\r\n\r\n            return true;\r\n        }\r\n\r\n        public void Unload()\r\n        {\r\n            try\r\n            {\r\n                if (m_Mutex != null)\r\n                {\r\n                    m_Mutex.ReleaseMutex();\r\n                    m_Mutex.Close();\r\n                    m_Mutex = null;\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public void Save()\r\n        {\r\n            string profileDir = Config.GetUserDirectory(\"Profiles\");\r\n            string file = Path.Combine(profileDir, $\"{m_Name}.xml\");\r\n\r\n            if (m_Name != \"default\" && !m_Warned)\r\n            {\r\n                try\r\n                {\r\n                    m_Mutex = new System.Threading.Mutex(true, $\"Razor_Profile_{m_Name}\");\r\n\r\n                    if (!m_Mutex.WaitOne(10, false))\r\n                        throw new Exception(\"Can't grab profile mutex, must be in use!\");\r\n                }\r\n                catch\r\n                {\r\n                    //MessageBox.Show( Engine.ActiveWindow, Language.Format( LocString.ProfileInUse, m_Name ), \"Profile In Use\", MessageBoxButtons.OK, MessageBoxIcon.Warning );\r\n                    //m_Warned = true;\r\n                    return; // refuse to overwrite profiles that we don't own.\r\n                }\r\n            }\r\n\r\n            XmlTextWriter xml;\r\n            try\r\n            {\r\n                xml = new XmlTextWriter(file, Encoding.UTF8);\r\n            }\r\n            catch\r\n            {\r\n                return;\r\n            }\r\n\r\n            xml.Formatting = Formatting.Indented;\r\n            xml.IndentChar = '\\t';\r\n            xml.Indentation = 1;\r\n\r\n            xml.WriteStartDocument(true);\r\n            xml.WriteStartElement(\"profile\");\r\n\r\n            foreach (KeyValuePair<string, object> de in m_Props)\r\n            {\r\n                xml.WriteStartElement(\"property\");\r\n                xml.WriteAttributeString(\"name\", de.Key);\r\n                if (de.Value == null)\r\n                {\r\n                    xml.WriteAttributeString(\"type\", \"-null-\");\r\n                }\r\n                else\r\n                {\r\n                    xml.WriteAttributeString(\"type\", de.Value.GetType().FullName);\r\n                    xml.WriteString(de.Value.ToString());\r\n                }\r\n\r\n                xml.WriteEndElement();\r\n            }\r\n\r\n            xml.WriteStartElement(\"filters\");\r\n            Filter.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"counters\");\r\n            Counter.SaveProfile(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"agents\");\r\n            Agent.SaveProfile(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"dresslists\");\r\n            DressList.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"hotkeys\");\r\n            HotKey.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"passwords\");\r\n            PasswordMemory.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"overheadmessages\");\r\n            OverheadManager.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"containerlabels\");\r\n            ContainerLabels.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"macrovariables\");\r\n            MacroVariables.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"scriptvariables\");\r\n            ScriptVariables.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"friends\");\r\n            FriendsManager.Save(xml);\r\n            xml.WriteEndElement();\r\n            \r\n            xml.WriteStartElement(\"textfilters\");\r\n            TextFilterManager.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"targetfilters\");\r\n            TargetFilterManager.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"soundfilters\");\r\n            SoundMusicManager.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteStartElement(\"waypoints\");\r\n            WaypointManager.Save(xml);\r\n            xml.WriteEndElement();\r\n\r\n            xml.WriteEndElement(); // end profile section\r\n\r\n            xml.Close();\r\n        }\r\n\r\n        private static Type[] ctorTypes = new Type[] {typeof(string)};\r\n\r\n        private object GetObjectFromString(string val, Type type)\r\n        {\r\n            if (type == typeof(string))\r\n            {\r\n                return val;\r\n            }\r\n            else\r\n            {\r\n                try\r\n                {\r\n                    ConstructorInfo ctor = type.GetConstructor(ctorTypes);\r\n                    if (ctor != null)\r\n                        return ctor.Invoke(new object[] {val});\r\n                }\r\n                catch\r\n                {\r\n                }\r\n\r\n                return Convert.ChangeType(val, type);\r\n            }\r\n        }\r\n\r\n        public object GetProperty(string name)\r\n        {\r\n            if (!m_Props.ContainsKey(name))\r\n                throw new Exception(Language.Format(LocString.NoProp, name));\r\n            return m_Props[name];\r\n        }\r\n\r\n        public void SetProperty(string name, object val)\r\n        {\r\n            if (!m_Props.ContainsKey(name))\r\n                throw new Exception(Language.Format(LocString.NoProp, name));\r\n            m_Props[name] = val;\r\n        }\r\n\r\n        public void AddProperty(string name, object val)\r\n        {\r\n            m_Props[name] = val;\r\n        }\r\n    }\r\n\r\n    public class Config\r\n    {\r\n        private static Profile m_Current;\r\n        private static Dictionary<Serial, string> m_Chars;\r\n\r\n        private static Dictionary<string, string> m_AppSettings = new Dictionary<string, string>();\r\n\r\n        static Config()\r\n        {\r\n            var path = Path.Combine(Engine.RootPath, \"settings.csv\");\r\n\r\n            // Set defaults\r\n            m_AppSettings[\"UODataDir\"] = @\"D:\\Games\\UO\";\r\n            m_AppSettings[\"UOClient\"] = @\"D:\\Games\\UO\\client.exe\";\r\n            m_AppSettings[\"LastPort\"] = \"2593\";\r\n            m_AppSettings[\"LastProfile\"] = \"default\";\r\n            m_AppSettings[\"LastServer\"] = \"127.0.0.1\";\r\n            m_AppSettings[\"LastServerId\"] = \"0\";\r\n            m_AppSettings[\"ClientEncrypted\"] = \"1\";\r\n            m_AppSettings[\"ServerEncrypted\"] = \"0\";\r\n            m_AppSettings[\"ShowWelcome\"] = \"1\";\r\n            m_AppSettings[\"UId\"] = \"\";\r\n            m_AppSettings[\"MaxOrganizerAgents\"] = \"20\";\r\n            m_AppSettings[\"MaxBuyAgents\"] = \"20\";\r\n            m_AppSettings[\"MaxRestockAgents\"] = \"20\";\r\n            m_AppSettings[\"ImportProfilesAndMacros\"] = \"true\";\r\n            m_AppSettings[\"BackupPath\"] = @\".\\Backup\";\r\n\r\n            try\r\n            {\r\n                if (!File.Exists(path))\r\n                {\r\n                    File.Create(path);\r\n                }\r\n                else\r\n                {\r\n                    foreach (var line in File.ReadLines(path))\r\n                    {\r\n                        var strs = line.Split(',');\r\n\r\n                        m_AppSettings[strs[0].Trim()] = strs[1].Trim();\r\n                    }\r\n                }\r\n            }\r\n            catch (Exception)\r\n            { }\r\n            finally\r\n            {\r\n            }\r\n        }\r\n\r\n        public static Profile CurrentProfile\r\n        {\r\n            get\r\n            {\r\n                if (m_Current == null)\r\n                    LoadLastProfile();\r\n                return m_Current;\r\n            }\r\n        }\r\n\r\n        public static void Save()\r\n        {\r\n            if (m_Current != null)\r\n                m_Current.Save();\r\n            SaveCharList();\r\n            SaveAppSettings();\r\n        }\r\n\r\n        public static bool LoadProfile(string name)\r\n        {\r\n            Profile p = new Profile(name);\r\n            if (p.Load())\r\n            {\r\n                LastProfileName = p.Name;\r\n                if (m_Current != null)\r\n                    m_Current.Unload();\r\n                m_Current = p;\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static void NewProfile(string name)\r\n        {\r\n            if (m_Current != null)\r\n                m_Current.Unload();\r\n            m_Current = new Profile(name);\r\n        }\r\n\r\n        public static void LoadCharList()\r\n        {\r\n            if (m_Chars == null)\r\n                m_Chars = new Dictionary<Serial, string>();\r\n            else\r\n                m_Chars.Clear();\r\n\r\n            string file = Path.Combine(Config.GetUserDirectory(\"Profiles\"), \"chars.lst\");\r\n            if (!File.Exists(file))\r\n                return;\r\n\r\n            using (StreamReader reader = new StreamReader(file))\r\n            {\r\n                string line;\r\n                while ((line = reader.ReadLine()) != null)\r\n                {\r\n                    if (line.Length <= 0 || line[0] == ';' || line[0] == '#')\r\n                        continue;\r\n                    string[] split = line.Split('=');\r\n                    try\r\n                    {\r\n                        m_Chars.Add(Serial.Parse(split[0]), split[1]);\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        public static void SaveCharList()\r\n        {\r\n            if (m_Chars == null)\r\n                m_Chars = new Dictionary<Serial, string>();\r\n\r\n            try\r\n            {\r\n                using (StreamWriter writer =\r\n                    new StreamWriter(Path.Combine(Config.GetUserDirectory(\"Profiles\"), \"chars.lst\")))\r\n                {\r\n                    foreach (KeyValuePair<Serial, string> de in m_Chars)\r\n                    {\r\n                        writer.WriteLine(\"{0}={1}\", de.Key, de.Value);\r\n                    }\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        public static void LoadProfileFor(PlayerData player)\r\n        {\r\n            if (m_Chars == null)\r\n                m_Chars = new Dictionary<Serial, string>();\r\n\r\n            string prof;\r\n\r\n            if (m_Chars.TryGetValue(player.Serial, out prof) && prof != null)\r\n            {\r\n                if (m_Current != null && (m_Current.Name == prof || m_Current.Name.Trim() == prof.Trim()))\r\n                    return;\r\n\r\n                Save();\r\n\r\n                if (!LoadProfile(prof))\r\n                {\r\n                    if (prof != \"default\")\r\n                    {\r\n                        if (!LoadProfile(\"default\"))\r\n                            m_Current.MakeDefault();\r\n                    }\r\n                    else\r\n                    {\r\n                        m_Current.MakeDefault();\r\n                    }\r\n                }\r\n\r\n                Engine.MainWindow.InitConfig();\r\n            }\r\n            else\r\n            {\r\n                m_Chars[player.Serial] = (m_Current != null ? m_Current.Name : \"default\");\r\n            }\r\n\r\n            Engine.MainWindow.SafeAction(s => s.SelectProfile(m_Current != null ? m_Current.Name : \"default\"));\r\n        }\r\n\r\n        public static void SetProfileFor(PlayerData player)\r\n        {\r\n            if (m_Current != null)\r\n                m_Chars[player.Serial] = m_Current.Name;\r\n        }\r\n\r\n        public static bool LoadLastProfile()\r\n        {\r\n            string name = LastProfileName;\r\n            Profile p;\r\n\r\n            if (!string.IsNullOrWhiteSpace(name))\r\n            {\r\n                p = new Profile(name);\r\n                if (p.Load())\r\n                {\r\n                    if (m_Current != null)\r\n                        m_Current.Unload();\r\n                    m_Current = p;\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            LastProfileName = \"default\";\r\n            p = new Profile(\"default\");\r\n            if (!p.Load())\r\n            {\r\n                p.MakeDefault();\r\n                p.Save();\r\n            }\r\n\r\n            if (m_Current != null)\r\n                m_Current.Unload();\r\n            m_Current = p;\r\n\r\n            return true;\r\n        }\r\n\r\n        public static void SetupProfilesList(ComboBox list, string selectName)\r\n        {\r\n            if (list == null || list.Items == null)\r\n                return;\r\n\r\n            string[] files = Directory.GetFiles(Config.GetUserDirectory(\"Profiles\"), \"*.xml\");\r\n            string compare = String.Empty;\r\n            if (selectName != null)\r\n                compare = selectName.ToLower();\r\n\r\n            for (int i = 0; i < files.Length; i++)\r\n            {\r\n                string name = Path.GetFileNameWithoutExtension(files[i]);\r\n                if (name == null || name.Length <= 0)\r\n                    name = files[i];\r\n                if (name == null)\r\n                    continue;\r\n\r\n                list.Items.Add(name);\r\n                if (name.ToLower() == compare)\r\n                    list.SelectedIndex = i;\r\n            }\r\n        }\r\n\r\n        public static List<string> GetProfileList()\r\n        {\r\n            List<string> list = new List<string>();\r\n\r\n            string[] files = Directory.GetFiles(GetUserDirectory(\"Profiles\"), \"*.xml\");\r\n\r\n            foreach (var file in files)\r\n            {\r\n                list.Add(Path.GetFileNameWithoutExtension(file));\r\n            }\r\n\r\n            return list;\r\n        }\r\n\r\n        private static void SaveAppSettings()\r\n        {\r\n            var path = Path.Combine(Engine.RootPath, \"settings.csv\");\r\n\r\n            Engine.EnsureDirectory(Engine.RootPath);\r\n\r\n            if (!File.Exists(path))\r\n            {\r\n                File.Create(path);\r\n            }\r\n\r\n            var data = \"\";\r\n            foreach (var setting in m_AppSettings)\r\n            {\r\n                data += $\"{setting.Key}, {setting.Value}\\n\";\r\n            }\r\n\r\n            File.WriteAllText(path, data);\r\n        }\r\n\r\n        public static T GetAppSetting<T>(string key)\r\n        {\r\n            try\r\n            {\r\n                var appSetting = m_AppSettings[key];\r\n\r\n                if (!string.IsNullOrWhiteSpace(appSetting))\r\n                {\r\n                    var converter = TypeDescriptor.GetConverter(typeof(T));\r\n                    return (T) (converter.ConvertFromInvariantString(appSetting));\r\n                }\r\n\r\n                return default(T);\r\n            }\r\n            catch\r\n            {\r\n                return default(T);\r\n            }\r\n        }\r\n\r\n        public static object GetProperty(string name)\r\n        {\r\n            return CurrentProfile.GetProperty(name);\r\n        }\r\n\r\n        public static void SetProperty(string name, object val)\r\n        {\r\n            CurrentProfile.SetProperty(name, val);\r\n        }\r\n\r\n        public static void AddProperty(string name, object val)\r\n        {\r\n            CurrentProfile.AddProperty(name, val);\r\n        }\r\n\r\n        public static bool GetBool(string name)\r\n        {\r\n            return (bool) CurrentProfile.GetProperty(name);\r\n        }\r\n\r\n        public static string GetString(string name)\r\n        {\r\n            return (string) CurrentProfile.GetProperty(name);\r\n        }\r\n\r\n        public static int GetInt(string name)\r\n        {\r\n            return (int) CurrentProfile.GetProperty(name);\r\n        }\r\n\r\n        public static double GetDouble(string name)\r\n        {\r\n            return (double) CurrentProfile.GetProperty(name);\r\n        }\r\n\r\n        public static bool SetAppSetting(string key, string value)\r\n        {\r\n            try\r\n            {\r\n                m_AppSettings[key] = value;\r\n                SaveAppSettings();\r\n\r\n                return true;\r\n            }\r\n            catch\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        public static void RecursiveCopy(string oldDir, string newDir, bool overWrite = false)\r\n        {\r\n            Engine.EnsureDirectory(newDir);\r\n\r\n            if (!Directory.Exists(oldDir))\r\n                return;\r\n\r\n            string[] files = Directory.GetFiles(oldDir);\r\n            foreach (string f in files)\r\n                File.Copy(Path.Combine(oldDir, Path.GetFileName(f)), Path.Combine(newDir, Path.GetFileName(f)),\r\n                    overWrite);\r\n\r\n            string[] dirs = Directory.GetDirectories(oldDir);\r\n            foreach (string d in dirs)\r\n                RecursiveCopy(Path.Combine(oldDir, Path.GetDirectoryName(d)),\r\n                    Path.Combine(newDir, Path.GetDirectoryName(d)), overWrite);\r\n        }\r\n\r\n        public static void CopyUserFiles(string appDir, string name)\r\n        {\r\n            RecursiveCopy(Path.Combine(GetInstallDirectory(), name), Path.Combine(appDir, name));\r\n        }\r\n\r\n        public static void ImportProfilesMacros(string appDataSource)\r\n        {\r\n            RecursiveCopy(Path.Combine(appDataSource, \"Profiles\"), Path.Combine(GetInstallDirectory(), \"Profiles\"),\r\n                true);\r\n\r\n            RecursiveCopy(Path.Combine(appDataSource, \"Macros\"), Path.Combine(GetInstallDirectory(), \"Macros\"), true);\r\n\r\n            File.Copy(Path.Combine(appDataSource, \"counters.xml\"), Path.Combine(GetInstallDirectory(), \"counters.xml\"),\r\n                true);\r\n        }\r\n\r\n        public static string GetUserDirectory(string name)\r\n        {\r\n            string appDir = GetInstallDirectory();\r\n\r\n            if (!Directory.Exists(Path.Combine(appDir, \"Macros\")))\r\n            {\r\n                Directory.CreateDirectory(Path.Combine(appDir, \"Macros\"));\r\n            }\r\n\r\n            if (!Directory.Exists(Path.Combine(appDir, \"Profiles\")))\r\n            {\r\n                Directory.CreateDirectory(Path.Combine(appDir, \"Profiles\"));\r\n            }\r\n\r\n            if (!Directory.Exists(Path.Combine(appDir, \"Scripts\")))\r\n            {\r\n                Directory.CreateDirectory(Path.Combine(appDir, \"Scripts\"));\r\n            }\r\n\r\n            name = name.Length > 0 ? Path.Combine(appDir, name) : appDir;\r\n\r\n            Engine.EnsureDirectory(name);\r\n\r\n            return name;\r\n        }\r\n\r\n        public static string GetUserDirectory()\r\n        {\r\n            return GetUserDirectory(\"\");\r\n        }\r\n\r\n        public static string GetInstallDirectory(string name)\r\n        {\r\n            string dir = Engine.RootPath;\r\n\r\n            if (name.Length > 0)\r\n            {\r\n                dir = Path.Combine(dir, name);\r\n            }\r\n\r\n            Engine.EnsureDirectory(dir);\r\n\r\n            return dir;\r\n        }\r\n\r\n        public static string GetInstallDirectory()\r\n        {\r\n            return GetInstallDirectory(\"\");\r\n        }\r\n\r\n        public static string LastProfileName\r\n        {\r\n            get => GetAppSetting<string>(\"LastProfile\");\r\n            set => SetAppSetting(\"LastProfile\", value);\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/ContainerLabels.Designer.cs",
    "content": "﻿namespace Assistant.UI\n{\n    partial class ContainerLabels\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.cancelContainerLabels = new System.Windows.Forms.Button();\n            this.saveContainerLabels = new System.Windows.Forms.Button();\n            this.lblFormat = new System.Windows.Forms.Label();\n            this.containerLabelFormat = new System.Windows.Forms.TextBox();\n            this.removeContainerLabel = new System.Windows.Forms.Button();\n            this.addContainLabel = new System.Windows.Forms.Button();\n            this.containerView = new System.Windows.Forms.ListView();\n            this.containerId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.containerType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.containerLabel = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.containerAlias = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.setExHue = new System.Windows.Forms.Button();\n            this.lblContainerHue = new System.Windows.Forms.Label();\n            this.setColorHue = new System.Windows.Forms.Button();\n            this.asciiStyle = new System.Windows.Forms.RadioButton();\n            this.unicodeStyle = new System.Windows.Forms.RadioButton();\n            this.lblStyle = new System.Windows.Forms.Label();\n            this.setAlias = new System.Windows.Forms.Button();\n            this.SuspendLayout();\n            // \n            // cancelContainerLabels\n            // \n            this.cancelContainerLabels.Location = new System.Drawing.Point(449, 240);\n            this.cancelContainerLabels.Name = \"cancelContainerLabels\";\n            this.cancelContainerLabels.Size = new System.Drawing.Size(54, 28);\n            this.cancelContainerLabels.TabIndex = 20;\n            this.cancelContainerLabels.Text = \"Cancel\";\n            this.cancelContainerLabels.UseVisualStyleBackColor = true;\n            this.cancelContainerLabels.Click += new System.EventHandler(this.cancelOverheadMessages_Click);\n            // \n            // saveContainerLabels\n            // \n            this.saveContainerLabels.Location = new System.Drawing.Point(507, 240);\n            this.saveContainerLabels.Name = \"saveContainerLabels\";\n            this.saveContainerLabels.Size = new System.Drawing.Size(50, 28);\n            this.saveContainerLabels.TabIndex = 19;\n            this.saveContainerLabels.Text = \"OK\";\n            this.saveContainerLabels.UseVisualStyleBackColor = true;\n            this.saveContainerLabels.Click += new System.EventHandler(this.saveContainerLabels_Click);\n            // \n            // lblFormat\n            // \n            this.lblFormat.AutoSize = true;\n            this.lblFormat.Location = new System.Drawing.Point(12, 240);\n            this.lblFormat.Name = \"lblFormat\";\n            this.lblFormat.Size = new System.Drawing.Size(79, 15);\n            this.lblFormat.TabIndex = 30;\n            this.lblFormat.Text = \"Label Format:\";\n            // \n            // containerLabelFormat\n            // \n            this.containerLabelFormat.Location = new System.Drawing.Point(97, 237);\n            this.containerLabelFormat.Name = \"containerLabelFormat\";\n            this.containerLabelFormat.Size = new System.Drawing.Size(132, 23);\n            this.containerLabelFormat.TabIndex = 29;\n            this.containerLabelFormat.Text = \"[{label}] ({name})\";\n            this.containerLabelFormat.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            // \n            // removeContainerLabel\n            // \n            this.removeContainerLabel.Location = new System.Drawing.Point(449, 150);\n            this.removeContainerLabel.Name = \"removeContainerLabel\";\n            this.removeContainerLabel.Size = new System.Drawing.Size(108, 40);\n            this.removeContainerLabel.TabIndex = 28;\n            this.removeContainerLabel.Text = \"Remove Selected\";\n            this.removeContainerLabel.UseVisualStyleBackColor = true;\n            this.removeContainerLabel.Click += new System.EventHandler(this.removeContainerLabel_Click);\n            // \n            // addContainLabel\n            // \n            this.addContainLabel.Location = new System.Drawing.Point(449, 12);\n            this.addContainLabel.Name = \"addContainLabel\";\n            this.addContainLabel.Size = new System.Drawing.Size(108, 40);\n            this.addContainLabel.TabIndex = 27;\n            this.addContainLabel.Text = \"Add Container Label\";\n            this.addContainLabel.UseVisualStyleBackColor = true;\n            this.addContainLabel.Click += new System.EventHandler(this.addContainLabel_Click);\n            // \n            // containerView\n            // \n            this.containerView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {\n            this.containerId,\n            this.containerType,\n            this.containerLabel,\n            this.containerAlias});\n            this.containerView.FullRowSelect = true;\n            this.containerView.Location = new System.Drawing.Point(12, 12);\n            this.containerView.MultiSelect = false;\n            this.containerView.Name = \"containerView\";\n            this.containerView.Size = new System.Drawing.Size(431, 215);\n            this.containerView.TabIndex = 22;\n            this.containerView.UseCompatibleStateImageBehavior = false;\n            this.containerView.View = System.Windows.Forms.View.Details;\n            this.containerView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnMouseDownContainerView);\n            // \n            // containerId\n            // \n            this.containerId.Text = \"ID\";\n            this.containerId.Width = 88;\n            // \n            // containerType\n            // \n            this.containerType.Text = \"Type\";\n            this.containerType.Width = 100;\n            // \n            // containerLabel\n            // \n            this.containerLabel.Text = \"Label\";\n            this.containerLabel.Width = 132;\n            // \n            // containerAlias\n            // \n            this.containerAlias.Text = \"Alias\";\n            this.containerAlias.Width = 106;\n            // \n            // setExHue\n            // \n            this.setExHue.Location = new System.Drawing.Point(182, 263);\n            this.setExHue.Name = \"setExHue\";\n            this.setExHue.Size = new System.Drawing.Size(47, 21);\n            this.setExHue.TabIndex = 39;\n            this.setExHue.Text = \"Set\";\n            this.setExHue.Click += new System.EventHandler(this.setExHue_Click);\n            // \n            // lblContainerHue\n            // \n            this.lblContainerHue.Location = new System.Drawing.Point(12, 263);\n            this.lblContainerHue.Name = \"lblContainerHue\";\n            this.lblContainerHue.Size = new System.Drawing.Size(217, 21);\n            this.lblContainerHue.TabIndex = 38;\n            this.lblContainerHue.Text = \"Default Label Hue:\";\n            this.lblContainerHue.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // setColorHue\n            // \n            this.setColorHue.Location = new System.Drawing.Point(449, 58);\n            this.setColorHue.Name = \"setColorHue\";\n            this.setColorHue.Size = new System.Drawing.Size(108, 40);\n            this.setColorHue.TabIndex = 40;\n            this.setColorHue.Text = \"Set Color/Hue\";\n            this.setColorHue.UseVisualStyleBackColor = true;\n            this.setColorHue.Click += new System.EventHandler(this.setColorHue_Click);\n            // \n            // asciiStyle\n            // \n            this.asciiStyle.AutoSize = true;\n            this.asciiStyle.Location = new System.Drawing.Point(309, 238);\n            this.asciiStyle.Name = \"asciiStyle\";\n            this.asciiStyle.Size = new System.Drawing.Size(53, 19);\n            this.asciiStyle.TabIndex = 41;\n            this.asciiStyle.TabStop = true;\n            this.asciiStyle.Text = \"ASCII\";\n            this.asciiStyle.UseVisualStyleBackColor = true;\n            // \n            // unicodeStyle\n            // \n            this.unicodeStyle.AutoSize = true;\n            this.unicodeStyle.Location = new System.Drawing.Point(309, 263);\n            this.unicodeStyle.Name = \"unicodeStyle\";\n            this.unicodeStyle.Size = new System.Drawing.Size(69, 19);\n            this.unicodeStyle.TabIndex = 42;\n            this.unicodeStyle.TabStop = true;\n            this.unicodeStyle.Text = \"Unicode\";\n            this.unicodeStyle.UseVisualStyleBackColor = true;\n            // \n            // lblStyle\n            // \n            this.lblStyle.AutoSize = true;\n            this.lblStyle.Location = new System.Drawing.Point(237, 240);\n            this.lblStyle.Name = \"lblStyle\";\n            this.lblStyle.Size = new System.Drawing.Size(66, 15);\n            this.lblStyle.TabIndex = 43;\n            this.lblStyle.Text = \"Label Style:\";\n            // \n            // setAlias\n            // \n            this.setAlias.Location = new System.Drawing.Point(449, 104);\n            this.setAlias.Name = \"setAlias\";\n            this.setAlias.Size = new System.Drawing.Size(108, 40);\n            this.setAlias.TabIndex = 44;\n            this.setAlias.Text = \"Set Container Alias\";\n            this.setAlias.UseVisualStyleBackColor = true;\n            this.setAlias.Click += new System.EventHandler(this.setAlias_Click);\n            // \n            // ContainerLabels\n            // \n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;\n            this.ClientSize = new System.Drawing.Size(569, 291);\n            this.Controls.Add(this.setAlias);\n            this.Controls.Add(this.lblStyle);\n            this.Controls.Add(this.unicodeStyle);\n            this.Controls.Add(this.asciiStyle);\n            this.Controls.Add(this.setColorHue);\n            this.Controls.Add(this.setExHue);\n            this.Controls.Add(this.lblContainerHue);\n            this.Controls.Add(this.lblFormat);\n            this.Controls.Add(this.containerLabelFormat);\n            this.Controls.Add(this.removeContainerLabel);\n            this.Controls.Add(this.addContainLabel);\n            this.Controls.Add(this.containerView);\n            this.Controls.Add(this.cancelContainerLabels);\n            this.Controls.Add(this.saveContainerLabels);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\n            this.MaximizeBox = false;\n            this.Name = \"ContainerLabels\";\n            this.Text = \"Container Labels\";\n            this.Load += new System.EventHandler(this.ContainerLabels_Load);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n            this.Closing += new System.ComponentModel.CancelEventHandler(this.ContainerLabels_Closing);\n\n        }\n\n        #endregion\n        private System.Windows.Forms.Button cancelContainerLabels;\n        private System.Windows.Forms.Button saveContainerLabels;\n        private System.Windows.Forms.Label lblFormat;\n        private System.Windows.Forms.TextBox containerLabelFormat;\n        private System.Windows.Forms.Button removeContainerLabel;\n        private System.Windows.Forms.Button addContainLabel;\n        private System.Windows.Forms.ListView containerView;\n        private System.Windows.Forms.ColumnHeader containerId;\n        private System.Windows.Forms.ColumnHeader containerType;\n        private System.Windows.Forms.ColumnHeader containerLabel;\n        private System.Windows.Forms.Button setExHue;\n        private System.Windows.Forms.Label lblContainerHue;\n        private System.Windows.Forms.Button setColorHue;\n        private System.Windows.Forms.RadioButton asciiStyle;\n        private System.Windows.Forms.RadioButton unicodeStyle;\n        private System.Windows.Forms.Label lblStyle;\n        private System.Windows.Forms.ColumnHeader containerAlias;\n        private System.Windows.Forms.Button setAlias;\n    }\n}"
  },
  {
    "path": "Razor/UI/ContainerLabels.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing Assistant.Macros;\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Drawing;\nusing System.Windows.Forms;\nusing Ultima;\n\nnamespace Assistant.UI\n{\n    public partial class ContainerLabels : Form\n    {\n        // Used to track new entries in the form's life\n        private List<Core.ContainerLabels.ContainerLabel> NewContainerEntries =\n            new List<Core.ContainerLabels.ContainerLabel>();\n\n        public ContainerLabels()\n        {\n            InitializeComponent();\n        }\n\n        private void ContainerLabels_Load(object sender, EventArgs e)\n        {\n            foreach (Core.ContainerLabels.ContainerLabel list in Core.ContainerLabels.ContainerLabelList)\n            {\n                ListViewItem item = new ListViewItem($\"{list.Id}\");\n                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, list.Type));\n                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, list.Label));\n                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, list.Alias));\n\n                int hueIdx = list.Hue;\n\n                if (hueIdx > 0 && hueIdx < 3000)\n                    item.SubItems[2].BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n                else\n                    item.SubItems[2].BackColor = SystemColors.Control;\n\n                item.SubItems[2].ForeColor =\n                    (item.SubItems[2].BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\n\n                item.UseItemStyleForSubItems = false;\n\n                containerView.SafeAction(s => s.Items.Add(item));\n            }\n\n            containerLabelFormat.SafeAction(s => s.Text = Config.GetString(\"ContainerLabelFormat\"));\n            InitPreviewHue(lblContainerHue, \"ContainerLabelColor\");\n\n            if (Config.GetInt(\"ContainerLabelStyle\") == 0)\n            {\n                asciiStyle.SafeAction(s => s.Checked = true);\n            }\n            else\n            {\n                unicodeStyle.SafeAction(s => s.Checked = true);\n            }\n        }\n\n        private void InitPreviewHue(Control ctrl, string cfg)\n        {\n            int hueIdx = Config.GetInt(cfg);\n\n            if (hueIdx > 0 && hueIdx < 3000)\n                ctrl.BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n            else\n                ctrl.BackColor = SystemColors.Control;\n\n            ctrl.ForeColor = (ctrl.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\n        }\n\n        private void saveContainerLabels_Click(object sender, EventArgs e)\n        {\n            List<Core.ContainerLabels.ContainerLabel> newContainerLabelList =\n                new List<Core.ContainerLabels.ContainerLabel>();\n\n            // Keep it simple, reset to default if it isn't what we like\n            if (string.IsNullOrEmpty(containerLabelFormat.Text) || !containerLabelFormat.Text.Contains(\"{label}\"))\n            {\n                containerLabelFormat.Text = @\"[{label}] ({type})\";\n            }\n\n            Config.SetProperty(\"ContainerLabelFormat\", containerLabelFormat.Text);\n\n            if (asciiStyle.Checked)\n            {\n                Config.SetProperty(\"ContainerLabelStyle\", 0);\n            }\n            else\n            {\n                Config.SetProperty(\"ContainerLabelStyle\", 1);\n            }\n\n            foreach (ListViewItem item in containerView.Items)\n            {\n                Core.ContainerLabels.ContainerLabel label = new Core.ContainerLabels.ContainerLabel\n                {\n                    Id = item.SubItems[0].Text,\n                    Type = item.SubItems[1].Text,\n                    Label = item.SubItems[2].Text,\n                    Hue = GetHueFromListView(item.SubItems[0].Text),\n                    Alias = item.SubItems[3].Text\n                };\n\n                newContainerLabelList.Add(label);\n            }\n\n            Core.ContainerLabels.ContainerLabelList =\n                new List<Core.ContainerLabels.ContainerLabel>(newContainerLabelList);\n\n            Config.Save();\n\n            this.SafeAction(s => s.Hide());\n        }\n\n        private void removeContainerLabel_Click(object sender, EventArgs e)\n        {\n            if (containerView.SelectedItems.Count > 0)\n            {\n                containerView.SafeAction(s => s.Items.Remove(containerView.SelectedItems[0]));\n            }\n        }\n\n        private void cancelOverheadMessages_Click(object sender, EventArgs e)\n        {\n            this.SafeAction(s => s.Hide());\n        }\n\n        private void addContainLabel_Click(object sender, EventArgs e)\n        {\n            if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\n                return;\n\n            Targeting.OneTimeTarget(OnContainerLabelAddTarget);\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\n        }\n\n        private void OnContainerLabelAddTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\n        {\n            TargetInfo t = new TargetInfo\n            {\n                Gfx = gfx,\n                Serial = serial,\n                Type = (byte) (ground ? 1 : 0),\n                X = pt.X,\n                Y = pt.Y,\n                Z = pt.Z\n            };\n\n            if (t != null && t.Serial.IsItem)\n            {\n                Item item = World.FindItem(t.Serial);\n\n                if (!item.IsContainer)\n                {\n                    // must be a container\n                    World.Player.SendMessage(MsgLevel.Force, \"You must select a container\");\n                }\n                else\n                {\n                    // add it\n                    World.Player.SendMessage(MsgLevel.Force, \"Container selected, add label text in Razor\");\n\n                    if (InputBox.Show(this, Language.GetString(LocString.SetContainerLabel),\n                        Language.GetString(LocString.EnterAName)))\n                    {\n                        string name = InputBox.GetString();\n\n                        ListViewItem lvItem = new ListViewItem($\"{t.Serial.Value}\");\n                        lvItem.SubItems.Add(new ListViewItem.ListViewSubItem(lvItem, item.Name));\n                        lvItem.SubItems.Add(new ListViewItem.ListViewSubItem(lvItem, name));\n                        lvItem.SubItems.Add(new ListViewItem.ListViewSubItem(lvItem, string.Empty));\n\n                        int hueIdx = Config.GetInt(\"ContainerLabelColor\");\n\n                        if (hueIdx > 0 && hueIdx < 3000)\n                            lvItem.SubItems[2].BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n                        else\n                            lvItem.SubItems[2].BackColor = SystemColors.Control;\n\n                        lvItem.SubItems[2].ForeColor = (lvItem.SubItems[2].BackColor.GetBrightness() < 0.35\n                            ? Color.White\n                            : Color.Black);\n\n                        lvItem.UseItemStyleForSubItems = false;\n\n                        containerView.SafeAction(s => s.Items.Add(lvItem));\n\n                        NewContainerEntries.Add(new Core.ContainerLabels.ContainerLabel\n                        {\n                            Hue = hueIdx,\n                            Id = $\"{t.Serial.Value}\",\n                            Label = name,\n                            Type = item.Name\n                        });\n\n                        World.Player.SendMessage(MsgLevel.Force, $\"Container {item} labeled as '{name}'\");\n\n                        Show();\n                    }\n                }\n            }\n            else if (t != null && t.Serial.IsMobile)\n            {\n                World.Player.SendMessage(MsgLevel.Force, \"You shouldn't label other people\");\n            }\n        }\n\n        private void setExHue_Click(object sender, EventArgs e)\n        {\n            SetHue(lblContainerHue, \"ContainerLabelColor\");\n        }\n\n        private bool SetHue(Control ctrl, string cfg)\n        {\n            HueEntry h = new HueEntry(Config.GetInt(cfg));\n\n            if (h.ShowDialog(this) == DialogResult.OK)\n            {\n                int hueIdx = h.Hue;\n                Config.SetProperty(cfg, hueIdx);\n                if (hueIdx > 0 && hueIdx < 3000)\n                    ctrl.BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n                else\n                    ctrl.BackColor = Color.White;\n                ctrl.ForeColor = (ctrl.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\n\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        private void setColorHue_Click(object sender, EventArgs e)\n        {\n            if (containerView.SelectedItems.Count > 0)\n            {\n                SetContainerLabelHue();\n            }\n        }\n\n        private bool SetContainerLabelHue()\n        {\n            ListViewItem selectedItem = containerView.Items[containerView.SelectedIndices[0]];\n\n            HueEntry h = new HueEntry(GetHueFromListView(selectedItem.SubItems[0].Text));\n\n            // TODO: BREAKING DRY!\n            if (h.ShowDialog(this) == DialogResult.OK)\n            {\n                int hueIdx = h.Hue;\n\n                if (hueIdx > 0 && hueIdx < 3000)\n                    selectedItem.SubItems[2].BackColor = Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\n                else\n                    selectedItem.SubItems[2].BackColor = Color.White;\n\n                selectedItem.SubItems[2].ForeColor = (selectedItem.SubItems[2].BackColor.GetBrightness() < 0.35\n                    ? Color.White\n                    : Color.Black);\n\n                foreach (Core.ContainerLabels.ContainerLabel list in Core.ContainerLabels.ContainerLabelList)\n                {\n                    if (list.Id.Equals(selectedItem.Text))\n                    {\n                        list.Hue = hueIdx;\n                        break;\n                    }\n                }\n\n                foreach (Core.ContainerLabels.ContainerLabel list in NewContainerEntries)\n                {\n                    if (list.Id.Equals(selectedItem.Text))\n                    {\n                        list.Hue = hueIdx;\n                        break;\n                    }\n                }\n\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        public int GetHueFromListView(string id)\n        {\n            int hue = 0;\n\n            foreach (Core.ContainerLabels.ContainerLabel list in Core.ContainerLabels.ContainerLabelList)\n            {\n                if (list.Id.Equals(id))\n                {\n                    return list.Hue;\n                }\n            }\n\n            foreach (Core.ContainerLabels.ContainerLabel list in NewContainerEntries)\n            {\n                if (list.Id.Equals(id))\n                {\n                    return list.Hue;\n                }\n            }\n\n            return hue;\n        }\n\n        private void OnMouseDownContainerView(object sender, MouseEventArgs e)\n        {\n            if (containerView.SelectedItems.Count == 0)\n                return;\n\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\n            {\n                ContextMenuStrip menu = new ContextMenuStrip();\n                menu.Items.Add(\"Open Container (if in range)\", null, new EventHandler(OnContainerDoubleClick));\n\n                menu.Show(containerView, new Point(e.X, e.Y));\n            }\n        }\n\n        private void OnContainerDoubleClick(object sender, System.EventArgs e)\n        {\n            ListViewItem selectedItem = containerView.Items[containerView.SelectedIndices[0]];\n\n            Item container = World.FindItem(Serial.Parse(selectedItem.SubItems[0].Text));\n\n            if (!container.IsContainer)\n                return;\n\n            World.Player.SendMessage(MsgLevel.Force, \"Opening container\");\n\n            Client.Instance.SendToServer(new DoubleClick(container.Serial));\n        }\n\n        private void setAlias_Click(object sender, EventArgs e)\n        {\n            if (containerView.SelectedItems.Count > 0)\n            {\n                ListViewItem selectedItem = containerView.Items[containerView.SelectedIndices[0]];\n\n                if (InputBox.Show(this, Language.GetString(LocString.SetContainerLabel),\n                    Language.GetString(LocString.EnterAName)))\n                {\n                    string name = InputBox.GetString();\n\n                    selectedItem.SubItems[3].Text = name;\n\n                    foreach (Core.ContainerLabels.ContainerLabel list in Core.ContainerLabels.ContainerLabelList)\n                    {\n                        if (list.Id.Equals(selectedItem.Text))\n                        {\n                            list.Alias = name;\n                            break;\n                        }\n                    }\n\n                    foreach (Core.ContainerLabels.ContainerLabel list in NewContainerEntries)\n                    {\n                        if (list.Id.Equals(selectedItem.Text))\n                        {\n                            list.Alias = name;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        private void ContainerLabels_Closing(object sender, CancelEventArgs e)\n        {\n            this.SafeAction(s =>\n            {\n                e.Cancel = true;\n                s.Hide();\n            });\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/ContainerLabels.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "Razor/UI/Ext.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Windows.Forms;\n\nnamespace Assistant.UI\n{\n    static class Ext\n    {\n        public static void SafeAction<TControl>(this TControl control, Action<TControl> action) where TControl : Control\n        {\n            if (control.InvokeRequired)\n            {\n                control.Invoke(action, control);\n            }\n            else\n                action(control);\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/HueEntry.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System.Drawing;\r\nusing System.Windows.Forms;\r\n\r\nnamespace Assistant\r\n{\r\n    /// <summary>\r\n    /// Summary description for HueEntry.\r\n    /// </summary>\r\n    public class HueEntry : System.Windows.Forms.Form\r\n    {\r\n        private System.Windows.Forms.Label label1;\r\n        private System.Windows.Forms.TextBox hueNum;\r\n        private System.Windows.Forms.Button inGame;\r\n        private System.Windows.Forms.Label preview;\r\n        private System.Windows.Forms.Button okay;\r\n        private System.Windows.Forms.Button cancel;\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        private int m_Hue;\r\n\r\n        public delegate void HueEntryCallback(int hue);\r\n\r\n        public static HueEntryCallback Callback = null;\r\n\r\n        public int Hue\r\n        {\r\n            get { return m_Hue; }\r\n        }\r\n\r\n        public HueEntry() : this(0)\r\n        {\r\n        }\r\n\r\n        public HueEntry(int hue)\r\n        {\r\n            m_Hue = hue;\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n\r\n            //\r\n            // TODO: Add any constructor code after InitializeComponent call\r\n            //\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            this.label1 = new System.Windows.Forms.Label();\r\n            this.hueNum = new System.Windows.Forms.TextBox();\r\n            this.inGame = new System.Windows.Forms.Button();\r\n            this.preview = new System.Windows.Forms.Label();\r\n            this.okay = new System.Windows.Forms.Button();\r\n            this.cancel = new System.Windows.Forms.Button();\r\n            this.SuspendLayout();\r\n            // \r\n            // label1\r\n            // \r\n            this.label1.Location = new System.Drawing.Point(12, 9);\r\n            this.label1.Name = \"label1\";\r\n            this.label1.Size = new System.Drawing.Size(83, 18);\r\n            this.label1.TabIndex = 0;\r\n            this.label1.Text = \"Hue Number:\";\r\n            // \r\n            // hueNum\r\n            // \r\n            this.hueNum.Location = new System.Drawing.Point(101, 6);\r\n            this.hueNum.Name = \"hueNum\";\r\n            this.hueNum.Size = new System.Drawing.Size(61, 23);\r\n            this.hueNum.TabIndex = 1;\r\n            this.hueNum.TextChanged += new System.EventHandler(this.hueNum_TextChanged);\r\n            // \r\n            // inGame\r\n            // \r\n            this.inGame.Location = new System.Drawing.Point(15, 35);\r\n            this.inGame.Name = \"inGame\";\r\n            this.inGame.Size = new System.Drawing.Size(147, 35);\r\n            this.inGame.TabIndex = 2;\r\n            this.inGame.Text = \"Select in Game\";\r\n            this.inGame.Click += new System.EventHandler(this.inGame_Click);\r\n            // \r\n            // preview\r\n            // \r\n            this.preview.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;\r\n            this.preview.Location = new System.Drawing.Point(15, 73);\r\n            this.preview.Name = \"preview\";\r\n            this.preview.Size = new System.Drawing.Size(147, 35);\r\n            this.preview.TabIndex = 3;\r\n            this.preview.Text = \"Preview\";\r\n            this.preview.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\r\n            // \r\n            // okay\r\n            // \r\n            this.okay.Location = new System.Drawing.Point(110, 111);\r\n            this.okay.Name = \"okay\";\r\n            this.okay.Size = new System.Drawing.Size(52, 35);\r\n            this.okay.TabIndex = 4;\r\n            this.okay.Text = \"&OK\";\r\n            this.okay.Click += new System.EventHandler(this.okay_Click);\r\n            // \r\n            // cancel\r\n            // \r\n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\r\n            this.cancel.Location = new System.Drawing.Point(15, 111);\r\n            this.cancel.Name = \"cancel\";\r\n            this.cancel.Size = new System.Drawing.Size(52, 35);\r\n            this.cancel.TabIndex = 5;\r\n            this.cancel.Text = \"Cancel\";\r\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\r\n            // \r\n            // HueEntry\r\n            // \r\n            this.AcceptButton = this.okay;\r\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\r\n            this.CancelButton = this.cancel;\r\n            this.ClientSize = new System.Drawing.Size(177, 154);\r\n            this.ControlBox = false;\r\n            this.Controls.Add(this.hueNum);\r\n            this.Controls.Add(this.cancel);\r\n            this.Controls.Add(this.okay);\r\n            this.Controls.Add(this.preview);\r\n            this.Controls.Add(this.inGame);\r\n            this.Controls.Add(this.label1);\r\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\r\n            this.MaximizeBox = false;\r\n            this.MinimizeBox = false;\r\n            this.Name = \"HueEntry\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\r\n            this.Text = \"Select a Hue\";\r\n            this.Load += new System.EventHandler(this.HueEntry_Load);\r\n            this.ResumeLayout(false);\r\n            this.PerformLayout();\r\n        }\r\n\r\n        #endregion\r\n\r\n        private void hueNum_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            SetPreview(Utility.ToInt32(hueNum.Text, 0) & 0x3FFF);\r\n        }\r\n\r\n        public const int TextHueIDX = 30;\r\n\r\n        private void SetPreview(int hue)\r\n        {\r\n            if (hue > 0 && hue < 3000)\r\n                preview.BackColor = Ultima.Hues.GetHue(hue - 1).GetColor(TextHueIDX);\r\n            else\r\n                preview.BackColor = Color.Black;\r\n            preview.ForeColor = (preview.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\r\n        }\r\n\r\n        private void HueResp(int hue)\r\n        {\r\n            hue &= 0x3FFF;\r\n            SetPreview(hue);\r\n            hueNum.Text = hue.ToString();\r\n            Callback = null;\r\n\r\n            //Engine.MainWindow.SafeAction(s => s.ShowMe());\r\n            if (Client.IsOSI) // With CUO, this cancels the window not saving the result\r\n                this.Hide();\r\n\r\n            this.SendToBack();\r\n            this.WindowState = FormWindowState.Normal;\r\n            this.BringToFront();\r\n            this.Show();\r\n        }\r\n\r\n        private void inGame_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            Callback = new HueEntryCallback(HueResp);\r\n            Client.Instance.SendToClient(new HuePicker());\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelHue);\r\n        }\r\n\r\n        private void okay_Click(object sender, System.EventArgs e)\r\n        {\r\n            m_Hue = Utility.ToInt32(hueNum.Text, 0);\r\n            this.DialogResult = DialogResult.OK;\r\n            this.Close();\r\n            Callback = null;\r\n        }\r\n\r\n        private void cancel_Click(object sender, System.EventArgs e)\r\n        {\r\n            this.DialogResult = DialogResult.Cancel;\r\n            this.Close();\r\n            Callback = null;\r\n        }\r\n\r\n        private void HueEntry_Load(object sender, System.EventArgs e)\r\n        {\r\n            Language.LoadControlNames(this);\r\n\r\n            SetPreview(m_Hue);\r\n            hueNum.Text = m_Hue.ToString();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/HueEntry.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n</root>"
  },
  {
    "path": "Razor/UI/InputBox.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Windows.Forms;\r\n\r\nnamespace Assistant\r\n{\r\n    /// <summary>\r\n    /// Summary description for NewProfile.\r\n    /// </summary>\r\n    public class InputBox : System.Windows.Forms.Form\r\n    {\r\n        private static InputBox m_Instance;\r\n\r\n        public static bool Show(string prompt)\r\n        {\r\n            return Show(null, prompt, Language.GetString(LocString.InputReq), \"\");\r\n        }\r\n\r\n        public static bool Show(string prompt, string title)\r\n        {\r\n            return Show(null, prompt, title, \"\");\r\n        }\r\n\r\n        public static bool Show(string prompt, string title, string def)\r\n        {\r\n            return Show(null, prompt, title, def);\r\n        }\r\n\r\n        public static bool Show(Form parent, string prompt)\r\n        {\r\n            return Show(parent, prompt, Language.GetString(LocString.InputReq), \"\");\r\n        }\r\n\r\n        public static bool Show(Form parent, string prompt, string title)\r\n        {\r\n            return Show(parent, prompt, title, \"\");\r\n        }\r\n\r\n        public static bool Show(Form parent, string prompt, string title, string def)\r\n        {\r\n            if (m_Instance == null)\r\n                m_Instance = new InputBox();\r\n            m_Instance.Prompt.Text = prompt;\r\n            m_Instance.Text = title;\r\n            m_Instance.m_String = \"\";\r\n            m_Instance.EntryBox.Text = def;\r\n\r\n            if (parent != null)\r\n                return m_Instance.ShowDialog() == DialogResult.OK;\r\n            else\r\n                return m_Instance.ShowDialog(parent) == DialogResult.OK;\r\n        }\r\n\r\n        public static string GetString()\r\n        {\r\n            return m_Instance != null ? m_Instance.m_String : null;\r\n        }\r\n\r\n        public static int GetInt(int def)\r\n        {\r\n            try\r\n            {\r\n                string conv = m_Instance.m_String;\r\n                int b = 10;\r\n                if (conv[0] == '0' && conv[1] == 'x')\r\n                {\r\n                    b = 16;\r\n                    conv = conv.Substring(2);\r\n                }\r\n                else if (conv[0] == 'x' || conv[0] == 'X')\r\n                {\r\n                    b = 16;\r\n                    conv = conv.Substring(1);\r\n                }\r\n\r\n                return Convert.ToInt32(conv, b);\r\n            }\r\n            catch\r\n            {\r\n                return def;\r\n            }\r\n        }\r\n\r\n        public static int GetInt()\r\n        {\r\n            return GetInt(0);\r\n        }\r\n\r\n        private string m_String;\r\n        private System.Windows.Forms.Button ok;\r\n        private System.Windows.Forms.Button cancel;\r\n        private System.Windows.Forms.Label Prompt;\r\n        private System.Windows.Forms.TextBox EntryBox;\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        private InputBox()\r\n        {\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n\r\n            //\r\n            // TODO: Add any constructor code after InitializeComponent call\r\n            //\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            this.Prompt = new System.Windows.Forms.Label();\r\n            this.EntryBox = new System.Windows.Forms.TextBox();\r\n            this.ok = new System.Windows.Forms.Button();\r\n            this.cancel = new System.Windows.Forms.Button();\r\n            this.SuspendLayout();\r\n            // \r\n            // Prompt\r\n            // \r\n            this.Prompt.Location = new System.Drawing.Point(12, 9);\r\n            this.Prompt.Name = \"Prompt\";\r\n            this.Prompt.Size = new System.Drawing.Size(210, 16);\r\n            this.Prompt.TabIndex = 0;\r\n            this.Prompt.Text = \":\";\r\n            // \r\n            // EntryBox\r\n            // \r\n            this.EntryBox.Location = new System.Drawing.Point(12, 28);\r\n            this.EntryBox.Name = \"EntryBox\";\r\n            this.EntryBox.Size = new System.Drawing.Size(243, 23);\r\n            this.EntryBox.TabIndex = 1;\r\n            // \r\n            // ok\r\n            // \r\n            this.ok.Location = new System.Drawing.Point(186, 57);\r\n            this.ok.Name = \"ok\";\r\n            this.ok.Size = new System.Drawing.Size(69, 30);\r\n            this.ok.TabIndex = 2;\r\n            this.ok.Text = \"Okay\";\r\n            this.ok.Click += new System.EventHandler(this.ok_Click);\r\n            // \r\n            // cancel\r\n            // \r\n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\r\n            this.cancel.Location = new System.Drawing.Point(15, 57);\r\n            this.cancel.Name = \"cancel\";\r\n            this.cancel.Size = new System.Drawing.Size(69, 30);\r\n            this.cancel.TabIndex = 3;\r\n            this.cancel.Text = \"Cancel\";\r\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\r\n            // \r\n            // InputBox\r\n            // \r\n            this.AcceptButton = this.ok;\r\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\r\n            this.CancelButton = this.cancel;\r\n            this.ClientSize = new System.Drawing.Size(266, 94);\r\n            this.ControlBox = false;\r\n            this.Controls.Add(this.cancel);\r\n            this.Controls.Add(this.ok);\r\n            this.Controls.Add(this.EntryBox);\r\n            this.Controls.Add(this.Prompt);\r\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\r\n            this.Name = \"InputBox\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\r\n            this.Text = \"Input\";\r\n            this.Load += new System.EventHandler(this.InputBox_Load);\r\n            this.ResumeLayout(false);\r\n            this.PerformLayout();\r\n        }\r\n\r\n        #endregion\r\n\r\n        private void ok_Click(object sender, System.EventArgs e)\r\n        {\r\n            m_String = EntryBox.Text.Trim();\r\n            this.DialogResult = DialogResult.OK;\r\n            this.Close();\r\n        }\r\n\r\n        private void cancel_Click(object sender, System.EventArgs e)\r\n        {\r\n            this.DialogResult = DialogResult.Cancel;\r\n            this.Close();\r\n        }\r\n\r\n        private void InputBox_Load(object sender, System.EventArgs e)\r\n        {\r\n            Language.LoadControlNames(this);\r\n\r\n            if (this.Location.X <= 0 || this.Location.Y <= 0)\r\n                this.Location = new System.Drawing.Point(Config.GetInt(\"WindowX\"), Config.GetInt(\"WindowY\"));\r\n\r\n            this.WindowState = FormWindowState.Normal;\r\n            this.BringToFront();\r\n            this.TopMost = true;\r\n\r\n            _ShowTimer = new System.Windows.Forms.Timer();\r\n            _ShowTimer.Interval = 250;\r\n            _ShowTimer.Enabled = true;\r\n            _ShowTimer.Tick += new EventHandler(timer_Tick);\r\n        }\r\n\r\n        private System.Windows.Forms.Timer _ShowTimer;\r\n\r\n        private void timer_Tick(object sender, EventArgs e)\r\n        {\r\n            this.TopMost = false;\r\n            this.BringToFront();\r\n            this.Activate();\r\n\r\n            EntryBox.Focus();\r\n\r\n            if (_ShowTimer != null)\r\n                _ShowTimer.Stop();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/InputBox.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n</root>"
  },
  {
    "path": "Razor/UI/InputDropdown.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.ComponentModel;\nusing System.Windows.Forms;\n\nnamespace Assistant\n{\n    /// <summary>\n    /// Summary description for NewProfile.\n    /// </summary>\n    public class InputDropdown : System.Windows.Forms.Form\n    {\n        private static InputDropdown m_Instance;\n\n\n        public static bool Show(Form parent, string prompt, string[] dropDownItems)\n        {\n            return Show(parent, prompt, dropDownItems, Language.GetString(LocString.InputReq));\n        }\n\n        public static bool Show(Form parent, string prompt, string title)\n        {\n            return Show(parent, prompt, new string[] { }, title);\n        }\n\n        public static bool Show(Form parent, string prompt, string[] dropDownItems, string title)\n        {\n            if (m_Instance == null)\n                m_Instance = new InputDropdown();\n            m_Instance.Prompt.Text = prompt;\n            m_Instance.Text = title;\n            m_Instance.m_String = \"\";\n\n            m_Instance.EntryCombo.Items.Clear();\n            m_Instance.EntryCombo.Items.AddRange(dropDownItems);\n            m_Instance.EntryCombo.SelectedIndex = 0;\n\n            if (parent != null)\n                return m_Instance.ShowDialog() == DialogResult.OK;\n            else\n                return m_Instance.ShowDialog(parent) == DialogResult.OK;\n        }\n\n        public static string GetString()\n        {\n            return m_Instance != null ? m_Instance.m_String : null;\n        }\n\n        public static int GetInt(int def)\n        {\n            try\n            {\n                string conv = m_Instance.m_String;\n                int b = 10;\n                if (conv[0] == '0' && conv[1] == 'x')\n                {\n                    b = 16;\n                    conv = conv.Substring(2);\n                }\n                else if (conv[0] == 'x' || conv[0] == 'X')\n                {\n                    b = 16;\n                    conv = conv.Substring(1);\n                }\n\n                return Convert.ToInt32(conv, b);\n            }\n            catch\n            {\n                return def;\n            }\n        }\n\n        public static int GetInt()\n        {\n            return GetInt(0);\n        }\n\n        private string m_String;\n        private System.Windows.Forms.Button ok;\n        private System.Windows.Forms.Button cancel;\n        private System.Windows.Forms.Label Prompt;\n        private ComboBox EntryCombo;\n\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private Container components = null;\n\n        private InputDropdown()\n        {\n            //\n            // Required for Windows Form Designer support\n            //\n            InitializeComponent();\n\n            //\n            // TODO: Add any constructor code after InitializeComponent call\n            //\n        }\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                if (components != null)\n                {\n                    components.Dispose();\n                }\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.Prompt = new System.Windows.Forms.Label();\n            this.ok = new System.Windows.Forms.Button();\n            this.cancel = new System.Windows.Forms.Button();\n            this.EntryCombo = new System.Windows.Forms.ComboBox();\n            this.SuspendLayout();\n            // \n            // Prompt\n            // \n            this.Prompt.Location = new System.Drawing.Point(12, 9);\n            this.Prompt.Name = \"Prompt\";\n            this.Prompt.Size = new System.Drawing.Size(210, 16);\n            this.Prompt.TabIndex = 0;\n            this.Prompt.Text = \":\";\n            // \n            // ok\n            // \n            this.ok.Location = new System.Drawing.Point(150, 57);\n            this.ok.Name = \"ok\";\n            this.ok.Size = new System.Drawing.Size(69, 30);\n            this.ok.TabIndex = 2;\n            this.ok.Text = \"Okay\";\n            this.ok.Click += new System.EventHandler(this.ok_Click);\n            // \n            // cancel\n            // \n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\n            this.cancel.Location = new System.Drawing.Point(12, 57);\n            this.cancel.Name = \"cancel\";\n            this.cancel.Size = new System.Drawing.Size(69, 30);\n            this.cancel.TabIndex = 3;\n            this.cancel.Text = \"Cancel\";\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\n            // \n            // EntryCombo\n            // \n            this.EntryCombo.FormattingEnabled = true;\n            this.EntryCombo.Location = new System.Drawing.Point(12, 28);\n            this.EntryCombo.Name = \"EntryCombo\";\n            this.EntryCombo.Size = new System.Drawing.Size(207, 23);\n            this.EntryCombo.TabIndex = 4;\n            // \n            // InputDropdown\n            // \n            this.AcceptButton = this.ok;\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\n            this.CancelButton = this.cancel;\n            this.ClientSize = new System.Drawing.Size(232, 94);\n            this.ControlBox = false;\n            this.Controls.Add(this.EntryCombo);\n            this.Controls.Add(this.cancel);\n            this.Controls.Add(this.ok);\n            this.Controls.Add(this.Prompt);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\n            this.Name = \"InputDropdown\";\n            this.ShowInTaskbar = false;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\n            this.Text = \"Input\";\n            this.Load += new System.EventHandler(this.InputDropdown_Load);\n            this.ResumeLayout(false);\n        }\n\n        #endregion\n\n        private void ok_Click(object sender, System.EventArgs e)\n        {\n            m_String = EntryCombo.Text.Trim();\n            this.DialogResult = DialogResult.OK;\n            this.Close();\n        }\n\n        private void cancel_Click(object sender, System.EventArgs e)\n        {\n            this.DialogResult = DialogResult.Cancel;\n            this.Close();\n        }\n\n        private void InputDropdown_Load(object sender, System.EventArgs e)\n        {\n            Language.LoadControlNames(this);\n\n            if (this.Location.X <= 0 || this.Location.Y <= 0)\n                this.Location = new System.Drawing.Point(Config.GetInt(\"WindowX\"), Config.GetInt(\"WindowY\"));\n\n            this.WindowState = FormWindowState.Normal;\n            this.BringToFront();\n            this.TopMost = true;\n\n            _ShowTimer = new System.Windows.Forms.Timer();\n            _ShowTimer.Interval = 250;\n            _ShowTimer.Enabled = true;\n            _ShowTimer.Tick += new EventHandler(timer_Tick);\n        }\n\n        private System.Windows.Forms.Timer _ShowTimer;\n\n        private void timer_Tick(object sender, EventArgs e)\n        {\n            this.TopMost = false;\n            this.BringToFront();\n            this.Activate();\n\n            EntryCombo.Focus();\n\n            if (_ShowTimer != null)\n                _ShowTimer.Stop();\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/InputDropdown.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "Razor/UI/Languages.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\n//#define LOG_CONTROL_TEXT\n\nusing System;\nusing System.Text;\nusing System.IO;\nusing System.Collections;\nusing System.Windows.Forms;\nusing Ultima;\n\nnamespace Assistant\n{\n    #region Localization enum\n\n    //1044060 = Alchemy in UO cliloc\n    public enum LocString : int\n    {\n        Null = 0,\n\n        __Start = 1000,\n        DeathStatus,\n        BardMusic,\n        DogSounds,\n        CatSounds,\n        HorseSounds,\n        SheepSounds,\n        SS_Sound,\n        FizzleSound,\n        Weather,\n        DispCounters,\n        RecountCounters,\n        ClearAbility,\n        SetPrimAb,\n        SetSecAb,\n        ToggleStun,\n        ToggleDisarm,\n        SettingAOSAb,\n        AOSAbCleared,\n        UndressAll,\n        UndressHands,\n        UndressLeft,\n        UndressRight,\n        UndressHat,\n        UndressJewels,\n        BandageSelf,\n        BandageLT,\n        UseBandage,\n        DrinkHeal,\n        DrinkCure,\n        DrinkRef,\n        DrinkNS,\n        DrinkExp,\n        DrinkStr,\n        DrinkAg,\n        NoBandages,\n        NoItemOfType,\n        DClickA1,\n        ReTarget,\n        Conv2DCT,\n        SelTargAct,\n        ProfileLoadEx,\n        MacroItemOutRange,\n        LiftA10,\n        ConvLiftByType,\n        MacroNoHold,\n        EquipTo,\n        DropA2,\n        ConvRelLoc,\n        DropRelA3,\n        GumpRespB, //1050\n        CloseGump,\n        MenuRespA1,\n        MacroNoTarg,\n        AbsTarg,\n        ConvLT,\n        ConvTargType,\n        TargRelLocA3,\n        LastTarget,\n        TargetSelf,\n        SetLT,\n        TargRandRed,\n        TargRandGrey,\n        TargRandBlue,\n        TargRandEnemy,\n        TargRandFriend,\n        TargRandNFriend,\n        SayQA1,\n        UseSkillA1,\n        CastSpellA1,\n        SetAbilityA1,\n        DressA1,\n        UndressA1,\n        UndressLayerA1,\n        WaitAnyMenu,\n        WaitMenuA1,\n        Edit,\n        WaitAnyGump,\n        WaitGumpA1,\n        WaitTarg,\n        PauseA1,\n        WaitA3,\n        LoadingA1,\n        StopCurrent,\n        PlayA1,\n        PlayingA1,\n        MacroFinished,\n        InitError,\n        IE_1,\n        IE_2,\n        IE_3,\n        IE_4,\n        IE_5,\n        IE_6, // InitError.NO_PATCH\n        IE_7,\n        NoMemCpy,\n        SkillChanged,\n        InvalidAbrev,\n        InvalidIID,\n        InvalidHue,\n        SelItem2Count, // 1100\n        ProfileCorrupt,\n        NoProp,\n        CounterFux,\n        NoAutoCount,\n        CountLow,\n        SelHue,\n        TakeSS,\n        TitleBarTip,\n        RazorStatus1,\n        SetSLUp,\n        SetSLDown,\n        SetSLLocked,\n        ConfirmDelCounter,\n        ProfLoadQ,\n        ProfLoadE,\n        NoDelete,\n        EnterProfileName,\n        ProfExists,\n        DressName,\n        DelDressQ,\n        OutOfRangeA1,\n        DelDressItemQ,\n        TargUndressBag,\n        UB_Set,\n        ItemNotFound,\n        KeyUsed,\n        SaveOK,\n        PacketLogWarn,\n        Conv2Type,\n        NewMacro,\n        InvalidChars,\n        MacroExists,\n        MacroConfRec,\n        DelConf,\n        InsWait,\n        InsLT,\n        MoveUp,\n        MoveDown,\n        RemAct,\n        BeginRec,\n        FileNotFoundA1,\n        Confirm,\n        FileDelError,\n        NextRestart,\n        PWWarn,\n        NeedPort,\n        QueueIgnore,\n        ActQueued,\n        QueueFinished,\n        UseOnceAgent, // 1150\n        AddTarg,\n        AddContTarg,\n        RemoveTarg,\n        ClearList,\n        TargItemAdd,\n        TargCont,\n        TargItemRem,\n        ItemAdded,\n        ItemRemoved,\n        ItemsAdded,\n        UseOnceEmpty,\n        UseOnceStatus,\n        UseOnceError,\n        SellTotals,\n        Remove,\n        ContSet,\n        Clear,\n        PushDisable,\n        PushEnable,\n        SetHB,\n        ClearHB,\n        OrganizerAgent,\n        Organizer,\n        OrganizeNow,\n        ContNotSet,\n        NoBackpack,\n        OrgQueued,\n        OrgNoItems,\n        ItemExists,\n        AutoSearchEx,\n        BuyTotals,\n        BuyLowGold,\n        EnterAmount,\n        PrioSet,\n        CurTime,\n        CurLoc,\n        UndressBagRange,\n        UndressQueued,\n        DressQueued,\n        AlreadyDressed,\n        ItemsNotFound,\n        NoSpells,\n        StealthSteps,\n        StealthStart,\n        ClearTargQueue,\n        AttackLastComb,\n        TQCleared,\n        TargSetLT,\n        LTSet,\n        NewTargSet, // 1200\n        TargNoOne,\n        QueuedTS,\n        QueuedLT,\n        OTTCancel,\n        TargByType,\n        Scavenger,\n        DeleteConfirm,\n        SelSSFolder,\n        HotKeys,\n\n        // 1210 - 1248 reserved for hotkey categories\n        HKSubOffset = 1249,\n        // 1252 - 1300 reserved for hotkey sub-categories\n\n        Sell = 1301,\n        Buy,\n        InputReq,\n        CommandList,\n        UseHand,\n        MustDisarm,\n        ArmDisarmRight,\n        ArmDisarmLeft,\n        DropCur,\n        SpellWeaving,\n        ToggleHKEnable,\n        HKEnabledPress,\n        HKDisabledPress,\n        HKEnabled,\n        HKDisabled,\n        WalkA1,\n        AddTargType,\n        LTOutOfRange,\n        SellAmount,\n        SnoopFilter,\n        PackSound,\n        InsIF,\n        InsELSE,\n        InsENDIF,\n        SetAmt,\n        Restock,\n        RestockNow,\n        RestockAgent,\n        RestockTarget,\n        InvalidCont,\n        RestockDone,\n        CancelTarget,\n        NewerVersion,\n        Reload,\n        Save,\n        LTGround,\n        Resync,\n        DismountBlocked,\n        RecStart,\n        VidStop,\n        RecError,\n        WrongVer,\n        VideoCorrupt,\n        ReadError,\n        CatName,\n        CantDelDir,\n        CanCreateDir,\n        CantMoveMacro,\n        Friends,\n\n        // 1350 to 1359 reserved for PacketPlayer stop messages\n        Reserved0 = 1350,\n        Reserved1 = 1359,\n\n        TargFriendAdd,\n        TargFriendRem,\n        FriendAdded,\n        FriendRemoved,\n        Constructs,\n        InsFOR,\n        InsENDFOR,\n        NumIter,\n        ClearScavCache,\n        LastSpell,\n        LastSkill,\n        LastObj,\n        AllNames,\n        UseOnce,\n        TargRandEnemyHuman,\n        TargRandGreyHuman,\n        TargRandInnocentHuman,\n        TargRandCriminalHuman,\n        TargRandCriminal,\n        ForceEndHolding,\n        RestartClient,\n        ApplyOptionsRequired,\n        LiftQueued,\n        RestockQueued,\n        StrChanged,\n        DexChanged,\n        IntChanged,\n        LightFilter,\n        HealPoisonBlocked,\n        ClearDragDropQueue,\n        StopNow,\n        HealOrCureSelf,\n        NextTarget,\n        SetRestockHB,\n        AddUseOnce,\n        AttackLastTarg,\n        EditTimeout,\n        NoHold,\n        NotAllowed,\n        Allowed,\n\n        // 1400 to 1465 reserved for negotiation features\n        NegotiateTitle = 1400,\n        AllFeaturesEnabled,\n        FeatureDescBase,\n\n        NextCliloc = 1466,\n        FeatureDisabled = NextCliloc,\n        FeatureDisabledText,\n        InsComment,\n        AddFriend,\n        RemoveFriend,\n        MiniHealOrCureSelf,\n        NoPatchWarning,\n        Dismount,\n        ToggleMap,\n        TooFar,\n        DragDropQueueFull,\n        ToggleWarPeace,\n        VetRewardGump,\n        ForceSizeBad,\n        ScavengerHB,\n        RestockHBA1,\n        UseOnceHBA1,\n        SellHB,\n        OrganizerHBA1,\n        BadServerAddr,\n        PartyAccept,\n        PartyDecline,\n        HarmfulTarget,\n        BeneficialTarget,\n        RazorFriend,\n        PlayFromHere,\n        Initializing,\n        LoadingLastProfile,\n        LoadingClient,\n        WaitingForClient,\n        RememberDonate,\n        Welcome,\n        Auto2D,\n        Auto3D,\n        AutoDetect, // 1500\n        OpacityA1,\n        NewTimeout,\n        NotAssigned,\n        ChangeTimeout,\n        EnterAName,\n        Invalid,\n        StaffOnlyItems,\n        sStatsA1,\n        DrinkApple,\n\n        TargCloseRed,\n        TargCloseGrey,\n        TargCloseBlue,\n        TargCloseEnemy,\n        TargCloseFriend,\n        TargCloseNFriend,\n        TargCloseEnemyHuman,\n        TargCloseGreyHuman,\n        TargCloseInnocentHuman,\n        TargCloseCriminalHuman,\n        TargCloseCriminal,\n\n        ProfileInUse,\n        WaitingTimeout,\n        NoCliLocMsg,\n        NoCliLoc,\n        BOD,\n        LaunchBODAgent,\n\n        NextTargetHumanoid,\n        NewClipboardMacro = 1950,\n        CopyClipboardMacro = 1951,\n        DeerSounds,\n        MacroRename,\n        NewMacroVariable,\n\n        TargCloseGreyMonster,\n        TargCloseEnemyMonster,\n        TargRandGreyMonster,\n        TargRandEnemyMonster,\n        CyclopTitanSounds,\n        NextTargetEnemyHumanoid,\n        UnableToOpenMacro,\n        PauseCurrent,\n        MacroPaused,\n        MacroResuming,\n        StunReady,\n        StunSuccessful,\n        StunDisabled,\n        StunFailed,\n        AllCorpses,\n        AllMobiles,\n        BullSounds,\n        DragonSounds,\n        SetSellAgentHotBag,\n        AddUseOnceContainer,\n        ChickenSounds,\n        Reserved3,\n        ScavengerEnableDisable,\n        ScavengerSetHotBag,\n        ScavengerAddTarget,\n        GoldPerHotkey,\n        EnterNewText,\n        ImportFromPrevious,\n        SetOrganizerHB,\n        SetContainerLabel,\n        AddToIgnore,\n        RemoveFromIgnore,\n        RazorIgnored,\n        IgnoreAgent,\n        PrevTarget,\n        PrevTargetEnemyHumanoid,\n        PrevTargetHumanoid,\n        UseLastGumpResponse,\n        SetContainerAlias,\n        Interrupt,\n        CaptureBod,\n        DamageTracker,\n        EnableHotkeys,\n        DisableHotkeys,\n        ClientDataMismatch,\n        TargetRandom,\n        TargCloseRedMonster,\n        TargCloseRedHumanoid,\n        TargClosest,\n        TargRandomRedHuman,\n        TargRandomRedMonster,\n        TargRandomNFriendlyHuman,\n        TargRandomNFriendlyMonster,\n        TargRandomFriendlyHuman,\n        TargRandomFriendlyMonster,\n        TargRandomInnocentMonster,\n        TargRandomCriminalMonster,\n        TargClosestNFriendlyHuman,\n        TargClosestNFriendlyMonster,\n        TargClosestFriendlyHuman,\n        TargClosestFriendlyMonster,\n        TargClosestInnocentMonster,\n        TargClosestCriminalMonster,\n        NextTargetMonster,\n        PrevTargetMonster,\n        AddAllMobileFriends,\n        AllCome,\n        AllFollowMe,\n        AllFollow,\n        AllGuardMe,\n        AllGuard,\n        AllKill,\n        AllStay,\n        AllStop,\n        PetCommands,\n        Friend,\n        StrChangeOverhead,\n        DexChangeOverhead,\n        IntChangeOverhead,\n        SkillChangeOverhead,\n        GrabItem,\n        SetGrabItemHotBag,\n        GrabItemTarget,\n        GrabHB,\n        NextTargetCriminalHumanoid,\n        NextTargetMurdererHumanoid,\n        NextTargetInnocentHumanoid,\n        PrevTargetCriminalHumanoid,\n        PrevTargetMurdererHumanoid,\n        PrevTargetInnocentHumanoid,\n        CriminalTargets,\n        EnemyTargets,\n        FriendlyTargets,\n        GreyTargets,\n        InnocentTargets,\n        MurdererTargets,\n        NonFriendlyTargets,\n        NextTargetFriendlyHumanoid,\n        NextTargetGreyHumanoid,\n        NextTargetNonFriendlyHumanoid,\n        PrevTargetFriendlyHumanoid,\n        PrevTargetGreyHumanoid,\n        PrevTargetNonFriendlyHumanoid,\n        ToggleWar,\n        TogglePeace,\n        GHealOrCureSelf,\n        SetLastBeneficial,\n        SetLastHarmful,\n        SetLTBene,\n        SetLTHarm,\n        TargClosestFriend,\n        TargRandomFriend,\n        NextTargetFriend,\n        PrevTargetFriend,\n        UseRightHand,\n        UseLeftHand,\n        InsertOverheadMessage,\n        InsertWaitForTarget,\n        AddAllHumanoidsAsFriends,\n        NextTargetEnemyMonster,\n        NextTargetCriminalMonster,\n        NextTargetMurdererMonster,\n        NextTargetInnocentMonster,\n        PrevTargetCriminalMonster,\n        PrevTargetMurdererMonster,\n        PrevTargetInnocentMonster,\n        NextTargetFriendlyMonster,\n        NextTargetGreyMonster,\n        NextTargetNonFriendlyMonster,\n        PrevTargetEnemyMonster,\n        PrevTargetFriendlyMonster,\n        PrevTargetGreyMonster,\n        PrevTargetNonFriendlyMonster,\n        NewBeneficialTarget,\n        NewHarmfulTarget,\n        BirdSounds,\n        AddAllMobilesTargetFilter,\n        AddAllMobilesHumanoidTargetFilter,\n        InsertWhile,\n        InsertEndWhile,\n        InsertDo,\n        InsertDoWhile,\n        PlayScript,\n        NewScriptVariable,\n        ScriptPlaying,\n        ScriptFinished,\n        StopScript,\n        PartyAdd,\n        Mysticism,\n        Masteries,\n        NextWaypoint,\n        PrevWaypoint,\n        HideWaypoint,\n        InsertClearSysMsg,\n        ClearSysMsg,\n        NextTargetNonFriendly,\n        PrevTargetNonFriendly,\n        SetHue,\n        ScriptDClickType,\n        ScriptTargetType,\n        ScriptCopied,\n        GumpInfo,\n        GumpSysMsg,\n        GumpHotKeys,\n        GumpBoatControl,\n        BuyAgentAttempt,\n        NextTargetFriendly,\n        PrevTargetFriendly,\n        PauseScript,\n        ResumeScriptMessage,\n        PauseScriptMessage,\n        ScriptFinishedStopwatch,\n        __End\n    }\n\n    #endregion\n\n    public class Language\n    {\n        private static Hashtable m_Controls;\n        private static Hashtable m_Strings;\n        private static Ultima.StringList m_CliLoc = null;\n        private static bool m_Loaded = false;\n        private static string m_Current;\n        private static string m_CliLocName = \"ENU\";\n\n        public static bool Loaded\n        {\n            get { return m_Loaded; }\n        }\n\n        public static string Current\n        {\n            get { return m_Current; }\n        }\n\n        public static string CliLocName\n        {\n            get { return m_CliLocName; }\n        }\n\n        public static Ultima.StringList CliLoc\n        {\n            get { return m_CliLoc; }\n        }\n\n\n        public static string GetControlText(string name)\n        {\n            name = $\"{name}::Text\";\n            if (m_Controls.ContainsKey(name))\n                return m_Controls[name] as string;\n            else\n                return null;\n        }\n\n        static Language()\n        {\n            m_Controls = new Hashtable(32, 1.0f, StringComparer.OrdinalIgnoreCase);\n            m_Strings = new Hashtable((int) (LocString.__End - LocString.__Start) + 1, 1.0f);\n        }\n\n        public static string GetString(LocString key)\n        {\n            string value = m_Strings[key] as string;\n            if (value == null)\n                value = $\"LanguageString \\\"{key}\\\" not found!\"; //throw new MissingFieldException( String.Format( \"Razor requested Language Pack string '{0}', but it does not exist in the current language pack.\", key ) );\n            return value;\n        }\n\n        public static string GetString(int key)\n        {\n            string value = null;\n            if (key > (uint) LocString.__Start && key < (uint) LocString.__End)\n                value = m_Strings[(LocString) key] as string;\n            else if (m_CliLoc != null)\n                value = m_CliLoc.GetString(key);\n\n            if (value == null)\n                value = $\"LanguageString \\\"{key}\\\" not found!\";\n            return value;\n        }\n\n        public static string Format(int key, params object[] args)\n        {\n            return string.Format(GetString(key), args);\n        }\n\n        public static string Format(LocString key, params object[] args)\n        {\n            return string.Format(GetString(key), args);\n        }\n        \n        public static string GetSkillCliloc(int skill)\n        {\n            string value = null;\n            \n            if (m_CliLoc != null)\n            {\n                value = m_CliLoc.GetString(1044060 + skill);\n            }\n\n            if (value == null)\n            {\n                value = $\"LanguageString \\\"{1044060 + skill}\\\" not found!\";\n            }\n\n            return value;\n        }\n\n        public static string[] GetPackNames()\n        {\n            string path = Config.GetInstallDirectory(\"Language\");\n            string[] names = Directory.GetFiles(path, \"Razor_lang.*\");\n            for (int i = 0; i < names.Length; i++)\n                names[i] = Path.GetExtension(names[i]).ToUpper().Substring(1);\n            return names;\n        }\n\n        public static bool Load(string lang)\n        {\n            lang = lang.ToUpper();\n            if (m_Current != null && m_Current == lang)\n                return true;\n\n            m_CliLocName = \"enu\";\n            string filename = Path.Combine(Config.GetInstallDirectory(\"Language\"),\n                $\"Razor_lang.{lang.ToLower()}\");\n            if (!File.Exists(filename))\n                return false;\n            m_Current = lang;\n            ArrayList errors = new ArrayList();\n            Encoding encoding = Encoding.ASCII;\n\n            using (StreamReader reader = new StreamReader(filename))\n            {\n                string line;\n                while ((line = reader.ReadLine()) != null)\n                {\n                    line = line.Trim();\n                    string lower = line.ToLower();\n\n                    if (line == \"\" || line[0] == '#' || line[0] == ';' ||\n                        (line.Length >= 2 && line[0] == '/' && line[1] == '/'))\n                        continue;\n                    else if (lower == \"[controls]\" || lower == \"[strings]\")\n                        break;\n\n                    if (lower.StartsWith(\"::encoding\"))\n                    {\n                        try\n                        {\n                            int idx = lower.IndexOf('=') + 1;\n                            if (idx > 0 && idx < lower.Length)\n                                encoding = Encoding.GetEncoding(line.Substring(idx).Trim());\n                        }\n                        catch\n                        {\n                            encoding = null;\n                        }\n\n                        if (encoding == null)\n                        {\n                            MessageBox.Show(\n                                \"Error: The encoding specified in the language file was not valid.  Using ASCII.\",\n                                \"Invalid Encoding\", MessageBoxButtons.OK, MessageBoxIcon.Error);\n                            encoding = Encoding.ASCII;\n                        }\n\n                        break;\n                    }\n                }\n            }\n\n            using (StreamReader reader = new StreamReader(filename, encoding))\n            {\n                //m_Dict.Clear(); // just overwrite the old lang, rather than erasing it (this way if this lang is missing something, it'll appear in the old one\n                int lineNum = 0;\n                string line;\n                bool controls = true;\n                int idx = 0;\n\n                while ((line = reader.ReadLine()) != null)\n                {\n                    try\n                    {\n                        line = line.Trim();\n                        lineNum++;\n                        if (line == \"\" || line[0] == '#' || line[0] == ';' ||\n                            (line.Length >= 2 && line[0] == '/' && line[1] == '/'))\n                            continue;\n                        string lower = line.ToLower();\n                        if (lower == \"[controls]\")\n                        {\n                            controls = true;\n                            continue;\n                        }\n                        else if (lower == \"[strings]\")\n                        {\n                            controls = false;\n                            continue;\n                        }\n                        else if (lower.StartsWith(\"::cliloc\"))\n                        {\n                            idx = lower.IndexOf('=') + 1;\n                            if (idx > 0 && idx < lower.Length)\n                                m_CliLocName = lower.Substring(idx).Trim().ToUpper();\n                            continue;\n                        }\n                        else if (lower.StartsWith(\"::encoding\"))\n                        {\n                            continue;\n                        }\n\n                        idx = line.IndexOf('=');\n                        if (idx < 0)\n                        {\n                            errors.Add(lineNum);\n                            continue;\n                        }\n\n                        string key = line.Substring(0, idx).Trim();\n                        string value = line.Substring(idx + 1).Trim().Replace(\"\\\\n\", \"\\n\");\n\n                        if (controls)\n                            m_Controls[key] = value;\n                        else\n                            m_Strings[(LocString) Convert.ToInt32(key)] = value;\n                    }\n                    catch\n                    {\n                        errors.Add(lineNum);\n                    }\n                } //while\n            } //using\n\n            if (errors.Count > 0)\n            {\n                StringBuilder sb = new StringBuilder();\n\n                sb.AppendFormat(\"Razor enountered errors on the following lines while loading the file '{0}'\\r\\n\",\n                    filename);\n                for (int i = 0; i < errors.Count; i++)\n                    sb.AppendFormat(\"Line {0}\\r\\n\", errors[i]);\n\n                new MessageDialog(\"Language Pack Load Errors\", true, sb.ToString()).Show();\n            }\n\n            LoadCliLoc();\n\n            m_Loaded = true;\n            return true;\n        }\n\n        public static void LoadCliLoc()\n        {\n            if (m_CliLocName == null || m_CliLocName.Length <= 0)\n                m_CliLocName = \"enu\";\n\n            try\n            {\n                m_CliLoc = new Ultima.StringList(m_CliLocName.ToLower());\n            }\n            catch (Exception e)\n            {\n                string fileName = \"[CliLoc]\";\n                try\n                {\n                    fileName = Ultima.Files.GetFilePath($\"cliloc.{m_CliLocName}\");\n                }\n                catch\n                {\n                }\n\n                new MessageDialog(\"Error loading CliLoc\", true,\n                        \"There was an exception while attempting to load '{0}':\\n{1}\", fileName, e)\n                    .ShowDialog(Engine.ActiveWindow);\n            }\n\n            if (m_CliLoc == null || m_CliLoc.Entries == null || m_CliLoc.Entries.Count < 10)\n            {\n                m_CliLoc = null;\n                if (m_CliLocName != \"enu\")\n                {\n                    m_CliLocName = \"enu\";\n                    LoadCliLoc();\n                    return;\n                }\n                else\n                {\n                    MessageBox.Show(Engine.ActiveWindow, Language.GetString(LocString.NoCliLocMsg),\n                        Language.GetString(LocString.NoCliLoc), MessageBoxButtons.OK, MessageBoxIcon.Warning);\n                }\n            }\n        }\n\n        public static string GetCliloc(int num)\n        {\n            if (m_CliLoc == null)\n                return String.Empty;\n\n            StringEntry se = m_CliLoc.GetEntry(num);\n\n            if (se != null)\n                return se.Format();\n            else\n                return string.Empty;\n        }\n\n        public static string ClilocFormat(int num, string argstr)\n        {\n            if (m_CliLoc == null)\n                return String.Empty;\n\n            StringEntry se = m_CliLoc.GetEntry(num);\n\n            if (se != null)\n                return se.SplitFormat(argstr);\n            else\n                return string.Empty;\n        }\n\n        public static string ClilocFormat(int num, params object[] args)\n        {\n            if (m_CliLoc == null)\n                return String.Empty;\n\n            StringEntry se = m_CliLoc.GetEntry(num);\n\n            if (se != null)\n                return se.Format(args);\n            else\n                return string.Empty;\n        }\n\n        private static void LoadControls(string name, System.Windows.Forms.Control.ControlCollection controls)\n        {\n            if (controls == null)\n                return;\n\n            for (int i = 0; i < controls.Count; i++)\n            {\n                string find = $\"{name}::{controls[i].Name}\";\n                string str = m_Controls[find] as string;\n                if (str != null)\n                    controls[i].Text = str;\n\n                if (controls[i] is ListView)\n                {\n                    foreach (ColumnHeader ch in ((ListView) controls[i]).Columns)\n                    {\n                        find = $\"{name}::{controls[i].Name}::{ch.Index}\";\n                        str = m_Controls[find] as string;\n                        if (str != null)\n                            ch.Text = str;\n                    }\n                }\n\n                LoadControls(name, controls[i].Controls);\n            }\n        }\n\n        public static void LoadControlNames(System.Windows.Forms.Form form)\n        {\n#if LOG_CONTROL_TEXT\n\t\t\tDumpControls( form );\n#endif\n\n            LoadControls(form.Name, form.Controls);\n            string text = m_Controls[$\"{form.Name}::Text\"] as string;\n            if (text != null)\n                form.Text = text;\n\n            if (form is MainForm)\n                ((MainForm) form).UpdateTitle();\n        }\n\n#if LOG_CONTROL_TEXT\n\t\tpublic static void DumpControls( System.Windows.Forms.Form form )\n\t\t{\n\t\t\tusing ( StreamWriter w = new StreamWriter( form.Name+\".controls.txt\" ) )\n\t\t\t{\n\t\t\t\tw.WriteLine( \"{0}::Text={1}\", form.Name, form.Text );\n\t\t\t\tDump( form.Name, form.Controls, w );\n\t\t\t}\n\t\t}\n\n\t\tprivate static void Dump( string name, System.Windows.Forms.Control.ControlCollection ctrls, StreamWriter w )\n\t\t{\n\t\t\tfor(int i = 0;ctrls != null && i<ctrls.Count;i++)\n\t\t\t{\n\t\t\t\tif ( !(ctrls[i] is System.Windows.Forms.TextBox) && !(ctrls[i] is System.Windows.Forms.ComboBox) )\n\t\t\t\t{\n\t\t\t\t\tif ( ctrls[i].Text.Length > 0 )\n\t\t\t\t\t\tw.WriteLine( \"{0}::{1}={2}\", name, ctrls[i].Name, ctrls[i].Text );\n\t\t\t\t\tif ( ctrls[i] is ListView )\n\t\t\t\t\t{\n\t\t\t\t\t\tforeach ( ColumnHeader ch in ((ListView)ctrls[i]).Columns )\n\t\t\t\t\t\t\tw.WriteLine( \"{0}::{1}::{2}={3}\", name, ctrls[i].Name, ch.Index, ch.Text );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tDump( name, ctrls[i].Controls, w );\n\t\t\t}\n\t\t}\n#endif\n    }\n}"
  },
  {
    "path": "Razor/UI/MacroInsertDoWhile.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Windows.Forms;\nusing Assistant.Macros;\nusing Ultima;\n\nnamespace Assistant\n{\n    /// <summary>\n    /// Summary description for MacroInsertIf.\n    /// </summary>\n    public class MacroInsertDoWhile : System.Windows.Forms.Form\n    {\n        private Macro m_Macro;\n        private int m_Idx;\n        private MacroAction m_Action;\n\n        private int m_SkillStart = -1;\n\n        private System.Windows.Forms.Button insert;\n        private System.Windows.Forms.TextBox txtAmount;\n        private System.Windows.Forms.Button cancel;\n        private System.Windows.Forms.ComboBox varList;\n        private System.Windows.Forms.ComboBox opList;\n        private System.Windows.Forms.Label label1;\n        private ComboBox whileVariables;\n\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.Container components = null;\n\n        public MacroInsertDoWhile(Macro m, int idx)\n        {\n            m_Macro = m;\n            m_Idx = idx;\n            //\n            // Required for Windows Form Designer support\n            //\n            InitializeComponent();\n\n            foreach (Counter c in Counter.List)\n                varList.Items.Add(c.Name);\n\n            m_SkillStart = varList.Items.Count;\n\n            if (World.Player != null && World.Player.SkillsSent)\n            {\n                foreach (Skill skill in World.Player.Skills)\n                {\n                    varList.Items.Add(Skills.GetSkillDisplayName(skill.Index));\n                }\n            }\n        }\n\n        public MacroInsertDoWhile(MacroAction a)\n        {\n            m_Action = a;\n            //\n            // Required for Windows Form Designer support\n            //\n            InitializeComponent();\n\n            foreach (Counter c in Counter.List)\n                varList.Items.Add(c.Name);\n\n            m_SkillStart = varList.Items.Count;\n\n            if (World.Player != null && World.Player.SkillsSent)\n            {\n                foreach (Skill skill in World.Player.Skills)\n                {\n                    varList.Items.Add(Skills.GetSkillDisplayName(skill.Index));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                if (components != null)\n                {\n                    components.Dispose();\n                }\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.insert = new System.Windows.Forms.Button();\n            this.txtAmount = new System.Windows.Forms.TextBox();\n            this.varList = new System.Windows.Forms.ComboBox();\n            this.cancel = new System.Windows.Forms.Button();\n            this.opList = new System.Windows.Forms.ComboBox();\n            this.label1 = new System.Windows.Forms.Label();\n            this.whileVariables = new System.Windows.Forms.ComboBox();\n            this.SuspendLayout();\n            // \n            // insert\n            // \n            this.insert.Location = new System.Drawing.Point(117, 38);\n            this.insert.Name = \"insert\";\n            this.insert.Size = new System.Drawing.Size(76, 33);\n            this.insert.TabIndex = 0;\n            this.insert.Text = \"&Insert\";\n            this.insert.Click += new System.EventHandler(this.insert_Click);\n            // \n            // txtAmount\n            // \n            this.txtAmount.Location = new System.Drawing.Point(266, 9);\n            this.txtAmount.Name = \"txtAmount\";\n            this.txtAmount.Size = new System.Drawing.Size(126, 23);\n            this.txtAmount.TabIndex = 7;\n            // \n            // varList\n            // \n            this.varList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.varList.Items.AddRange(new object[]\n            {\n                \"Hits\",\n                \"Mana\",\n                \"Stamina\",\n                \"Poisoned\",\n                \"SysMessage\",\n                \"Weight\",\n                \"Mounted\",\n                \"R Hand Empty\",\n                \"L Hand Empty\"\n            });\n            this.varList.Location = new System.Drawing.Point(72, 9);\n            this.varList.Name = \"varList\";\n            this.varList.Size = new System.Drawing.Size(129, 23);\n            this.varList.TabIndex = 8;\n            this.varList.SelectedIndexChanged += new System.EventHandler(this.varList_SelectedIndexChanged);\n            // \n            // cancel\n            // \n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\n            this.cancel.Location = new System.Drawing.Point(199, 38);\n            this.cancel.Name = \"cancel\";\n            this.cancel.Size = new System.Drawing.Size(76, 33);\n            this.cancel.TabIndex = 10;\n            this.cancel.Text = \"&Cancel\";\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\n            // \n            // opList\n            // \n            this.opList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.opList.Items.AddRange(new object[]\n            {\n                \"<=\",\n                \">=\",\n                \"<\",\n                \">\"\n            });\n            this.opList.Location = new System.Drawing.Point(207, 9);\n            this.opList.Name = \"opList\";\n            this.opList.Size = new System.Drawing.Size(53, 23);\n            this.opList.TabIndex = 11;\n            // \n            // label1\n            // \n            this.label1.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Bold,\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\n            this.label1.Location = new System.Drawing.Point(8, 12);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(64, 20);\n            this.label1.TabIndex = 12;\n            this.label1.Text = \"Do While:\";\n            // \n            // whileVariables\n            // \n            this.whileVariables.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.whileVariables.FormattingEnabled = true;\n            this.whileVariables.Items.AddRange(new object[]\n            {\n                \"{maxhp}\",\n                \"{maxstam}\",\n                \"{maxmana}\"\n            });\n            this.whileVariables.Location = new System.Drawing.Point(281, 44);\n            this.whileVariables.Name = \"whileVariables\";\n            this.whileVariables.Size = new System.Drawing.Size(104, 23);\n            this.whileVariables.TabIndex = 14;\n            this.whileVariables.SelectedIndexChanged += new System.EventHandler(this.ifVariables_SelectedIndexChanged);\n            // \n            // MacroInsertDoWhile\n            // \n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\n            this.ClientSize = new System.Drawing.Size(404, 79);\n            this.ControlBox = false;\n            this.Controls.Add(this.whileVariables);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.opList);\n            this.Controls.Add(this.cancel);\n            this.Controls.Add(this.varList);\n            this.Controls.Add(this.txtAmount);\n            this.Controls.Add(this.insert);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\n            this.Name = \"MacroInsertDoWhile\";\n            this.ShowInTaskbar = false;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\n            this.Text = \"Insert Do While...\";\n            this.Load += new System.EventHandler(this.MacroInsertWhile_Load);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n        }\n\n        #endregion\n\n        private void cancel_Click(object sender, System.EventArgs e)\n        {\n            this.DialogResult = DialogResult.Cancel;\n            this.Close();\n        }\n\n        private void insert_Click(object sender, System.EventArgs e)\n        {\n            MacroAction a = null;\n\n            try\n            {\n                if (varList.SelectedIndex == (int) DoWhileAction.DoWhileVarType.SysMessage)\n                {\n                    a = new DoWhileAction((DoWhileAction.DoWhileVarType) varList.SelectedIndex, txtAmount.Text);\n                }\n                else if (varList.SelectedIndex >= m_SkillStart)\n                {\n                    int skillId = -1;\n\n                    foreach (Skill skill in World.Player.Skills)\n                    {\n                        if (Skills.GetSkillDisplayName(skill.Index).Equals(varList.SelectedItem as string))\n                        {\n                            skillId = skill.Index;\n                            break;\n                        }\n                    }\n\n                    if (skillId != -1)\n                        a = new DoWhileAction(DoWhileAction.DoWhileVarType.Skill, (sbyte) opList.SelectedIndex,\n                            Utility.ToDouble(txtAmount.Text, 0.0), skillId);\n                }\n                else if (varList.SelectedIndex >= (int) DoWhileAction.DoWhileVarType.BeginCountersMarker)\n                {\n                    a = new DoWhileAction(DoWhileAction.DoWhileVarType.Counter, (sbyte) opList.SelectedIndex,\n                        Utility.ToInt32(txtAmount.Text, 0), varList.SelectedItem as string);\n                }\n                else\n                {\n                    a = txtAmount.Text.Contains(\"{\") // using an if variable\n                        ? new DoWhileAction((DoWhileAction.DoWhileVarType) varList.SelectedIndex,\n                            (sbyte) opList.SelectedIndex,\n                            txtAmount.Text)\n                        : new DoWhileAction((DoWhileAction.DoWhileVarType) varList.SelectedIndex,\n                            (sbyte) opList.SelectedIndex,\n                            Utility.ToInt32(txtAmount.Text, 0));\n                }\n            }\n            catch\n            {\n                return;\n            }\n\n            if (m_Action == null)\n                m_Macro.Insert(m_Idx + 1, a);\n            else\n                m_Action.Parent.Convert(m_Action, a);\n            this.DialogResult = DialogResult.OK;\n            this.Close();\n        }\n\n        private void MacroInsertWhile_Load(object sender, System.EventArgs e)\n        {\n            Language.LoadControlNames(this);\n\n            if (m_Action is DoWhileAction)\n            {\n                try\n                {\n                    varList.SelectedIndex = (int) ((DoWhileAction) m_Action).Variable;\n                }\n                catch\n                {\n                }\n\n                try\n                {\n                    opList.SelectedIndex = (int) ((DoWhileAction) m_Action).Op;\n                }\n                catch\n                {\n                }\n\n                try\n                {\n                    if (varList.SelectedIndex != 3 && (varList.SelectedIndex <= 5 ||\n                                                       varList.SelectedIndex >=\n                                                       (int) DoWhileAction.DoWhileVarType.BeginCountersMarker))\n                        txtAmount.Text = ((DoWhileAction) m_Action).Value.ToString();\n                }\n                catch\n                {\n                }\n\n                if (((DoWhileAction) m_Action).Counter != null &&\n                    ((DoWhileAction) m_Action).Variable == DoWhileAction.DoWhileVarType.Counter)\n                    try\n                    {\n                        varList.SelectedItem = ((DoWhileAction) m_Action).Counter;\n                    }\n                    catch\n                    {\n                    }\n\n                if (((DoWhileAction) m_Action).SkillId != -1 &&\n                    ((DoWhileAction) m_Action).Variable == DoWhileAction.DoWhileVarType.Skill)\n                    try\n                    {\n                        varList.SelectedItem = Skills.GetSkillDisplayName(((DoWhileAction) m_Action).SkillId);\n                    }\n                    catch\n                    {\n                    }\n            }\n        }\n\n        private void varList_SelectedIndexChanged(object sender, System.EventArgs e)\n        {\n            try\n            {\n                opList.Visible = varList.SelectedIndex < 3 || varList.SelectedIndex == 5 ||\n                                 varList.SelectedIndex >= (int) DoWhileAction.DoWhileVarType.BeginCountersMarker;\n                txtAmount.Visible = varList.SelectedIndex != 3 &&\n                                    (varList.SelectedIndex <= 5 || varList.SelectedIndex >=\n                                     (int) DoWhileAction.DoWhileVarType.BeginCountersMarker);\n            }\n            catch\n            {\n            }\n\n            /*if ( !opList.Visible )\n            {\n                if ( txtAmount.Visible )\n                {\n                    //varList.Size = new System.Drawing.Size(80, 21);\n\n                    //txtAmount.Location = new System.Drawing.Point(104, 9);\n                    //txtAmount.Size = new System.Drawing.Size(120, 20);\n                }\n                else\n                {\n                    //varList.Size = new System.Drawing.Size(200, 21);\n                }\n            }\n            else\n            {\n                varList.Size = new System.Drawing.Size(80, 21);\n\n                txtAmount.Location = new System.Drawing.Point(144, 9);\n                txtAmount.Size = new System.Drawing.Size(80, 20);\n            }*/\n        }\n\n        private void ifVariables_SelectedIndexChanged(object sender, EventArgs e)\n        {\n            if (whileVariables.SelectedItem.ToString().Substring(0, 1).Equals(\"{\") && whileVariables.Focused)\n            {\n                txtAmount.Text = $\"{whileVariables.SelectedItem}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/MacroInsertDoWhile.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "Razor/UI/MacroInsertIf.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Windows.Forms;\r\nusing Assistant.Macros;\r\nusing Ultima;\r\n\r\nnamespace Assistant\r\n{\r\n    /// <summary>\r\n    /// Summary description for MacroInsertIf.\r\n    /// </summary>\r\n    public class MacroInsertIf : System.Windows.Forms.Form\r\n    {\r\n        private Macro m_Macro;\r\n        private int m_Idx;\r\n        private MacroAction m_Action;\r\n\r\n        private int m_SkillStart = -1;\r\n\r\n        private System.Windows.Forms.Button insert;\r\n        private System.Windows.Forms.TextBox txtAmount;\r\n        private System.Windows.Forms.Button cancel;\r\n        private System.Windows.Forms.ComboBox varList;\r\n        private System.Windows.Forms.ComboBox opList;\r\n        private System.Windows.Forms.Label label1;\r\n        private ComboBox ifVariables;\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        public MacroInsertIf(Macro m, int idx)\r\n        {\r\n            m_Macro = m;\r\n            m_Idx = idx;\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n\r\n            foreach (Counter c in Counter.List)\r\n                varList.Items.Add(c.Name);\r\n\r\n            m_SkillStart = varList.Items.Count;\r\n\r\n            if (World.Player != null && World.Player.SkillsSent)\r\n            {\r\n                foreach (Skill skill in World.Player.Skills)\r\n                {\r\n                    varList.Items.Add(Skills.GetSkillDisplayName(skill.Index));\r\n                }\r\n            }\r\n        }\r\n\r\n        public MacroInsertIf(MacroAction a)\r\n        {\r\n            m_Action = a;\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n\r\n            foreach (Counter c in Counter.List)\r\n                varList.Items.Add(c.Name);\r\n\r\n            m_SkillStart = varList.Items.Count;\r\n\r\n            if (World.Player != null && World.Player.SkillsSent)\r\n            {\r\n                foreach (Skill skill in World.Player.Skills)\r\n                {\r\n                    varList.Items.Add(Skills.GetSkillDisplayName(skill.Index));\r\n                }\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            this.insert = new System.Windows.Forms.Button();\r\n            this.txtAmount = new System.Windows.Forms.TextBox();\r\n            this.varList = new System.Windows.Forms.ComboBox();\r\n            this.cancel = new System.Windows.Forms.Button();\r\n            this.opList = new System.Windows.Forms.ComboBox();\r\n            this.label1 = new System.Windows.Forms.Label();\r\n            this.ifVariables = new System.Windows.Forms.ComboBox();\r\n            this.SuspendLayout();\r\n            // \r\n            // insert\r\n            // \r\n            this.insert.Location = new System.Drawing.Point(124, 38);\r\n            this.insert.Name = \"insert\";\r\n            this.insert.Size = new System.Drawing.Size(76, 33);\r\n            this.insert.TabIndex = 0;\r\n            this.insert.Text = \"&Insert\";\r\n            this.insert.Click += new System.EventHandler(this.insert_Click);\r\n            // \r\n            // txtAmount\r\n            // \r\n            this.txtAmount.Location = new System.Drawing.Point(238, 9);\r\n            this.txtAmount.Name = \"txtAmount\";\r\n            this.txtAmount.Size = new System.Drawing.Size(156, 23);\r\n            this.txtAmount.TabIndex = 7;\r\n            // \r\n            // varList\r\n            // \r\n            this.varList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\r\n            this.varList.Items.AddRange(new object[]\r\n            {\r\n                \"Hits\",\r\n                \"Mana\",\r\n                \"Stamina\",\r\n                \"Poisoned\",\r\n                \"SysMessage\",\r\n                \"Weight\",\r\n                \"Mounted\",\r\n                \"R Hand Empty\",\r\n                \"L Hand Empty\"\r\n            });\r\n            this.varList.Location = new System.Drawing.Point(30, 9);\r\n            this.varList.Name = \"varList\";\r\n            this.varList.Size = new System.Drawing.Size(143, 23);\r\n            this.varList.TabIndex = 8;\r\n            this.varList.SelectedIndexChanged += new System.EventHandler(this.varList_SelectedIndexChanged);\r\n            // \r\n            // cancel\r\n            // \r\n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\r\n            this.cancel.Location = new System.Drawing.Point(206, 38);\r\n            this.cancel.Name = \"cancel\";\r\n            this.cancel.Size = new System.Drawing.Size(76, 33);\r\n            this.cancel.TabIndex = 10;\r\n            this.cancel.Text = \"&Cancel\";\r\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\r\n            // \r\n            // opList\r\n            // \r\n            this.opList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\r\n            this.opList.Items.AddRange(new object[]\r\n            {\r\n                \"<=\",\r\n                \">=\",\r\n                \"<\",\r\n                \">\"\r\n            });\r\n            this.opList.Location = new System.Drawing.Point(179, 9);\r\n            this.opList.Name = \"opList\";\r\n            this.opList.Size = new System.Drawing.Size(53, 23);\r\n            this.opList.TabIndex = 11;\r\n            // \r\n            // label1\r\n            // \r\n            this.label1.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Bold,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.label1.Location = new System.Drawing.Point(8, 12);\r\n            this.label1.Name = \"label1\";\r\n            this.label1.Size = new System.Drawing.Size(16, 20);\r\n            this.label1.TabIndex = 12;\r\n            this.label1.Text = \"If:\";\r\n            // \r\n            // ifVariables\r\n            // \r\n            this.ifVariables.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\r\n            this.ifVariables.FormattingEnabled = true;\r\n            this.ifVariables.Items.AddRange(new object[]\r\n            {\r\n                \"{maxhp}\",\r\n                \"{maxstam}\",\r\n                \"{maxmana}\"\r\n            });\r\n            this.ifVariables.Location = new System.Drawing.Point(288, 44);\r\n            this.ifVariables.Name = \"ifVariables\";\r\n            this.ifVariables.Size = new System.Drawing.Size(104, 23);\r\n            this.ifVariables.TabIndex = 14;\r\n            this.ifVariables.SelectedIndexChanged += new System.EventHandler(this.ifVariables_SelectedIndexChanged);\r\n            // \r\n            // MacroInsertIf\r\n            // \r\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\r\n            this.ClientSize = new System.Drawing.Size(404, 77);\r\n            this.ControlBox = false;\r\n            this.Controls.Add(this.ifVariables);\r\n            this.Controls.Add(this.label1);\r\n            this.Controls.Add(this.opList);\r\n            this.Controls.Add(this.cancel);\r\n            this.Controls.Add(this.varList);\r\n            this.Controls.Add(this.txtAmount);\r\n            this.Controls.Add(this.insert);\r\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\r\n            this.Name = \"MacroInsertIf\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\r\n            this.Text = \"Insert If...\";\r\n            this.Load += new System.EventHandler(this.MacroInsertIf_Load);\r\n            this.ResumeLayout(false);\r\n            this.PerformLayout();\r\n        }\r\n\r\n        #endregion\r\n\r\n        private void cancel_Click(object sender, System.EventArgs e)\r\n        {\r\n            this.DialogResult = DialogResult.Cancel;\r\n            this.Close();\r\n        }\r\n\r\n        private void insert_Click(object sender, System.EventArgs e)\r\n        {\r\n            MacroAction a = null;\r\n\r\n            try\r\n            {\r\n                if (varList.SelectedIndex == (int) IfAction.IfVarType.SysMessage)\r\n                {\r\n                    a = new IfAction((IfAction.IfVarType) varList.SelectedIndex, txtAmount.Text);\r\n                }\r\n                else if (varList.SelectedIndex >= m_SkillStart)\r\n                {\r\n                    int skillId = -1;\r\n\r\n                    foreach (Skill skill in World.Player.Skills)\r\n                    {\r\n                        if (Skills.GetSkillDisplayName(skill.Index).Equals(varList.SelectedItem as string))\r\n                        {\r\n                            skillId = skill.Index;\r\n                            break;\r\n                        }\r\n                    }\r\n\r\n                    if (skillId != -1)\r\n                        a = new IfAction(IfAction.IfVarType.Skill, (sbyte) opList.SelectedIndex,\r\n                            Utility.ToDouble(txtAmount.Text, 0.0), skillId);\r\n                }\r\n                else if (varList.SelectedIndex >= (int) IfAction.IfVarType.BeginCountersMarker)\r\n                {\r\n                    a = new IfAction(IfAction.IfVarType.Counter, (sbyte) opList.SelectedIndex,\r\n                        Utility.ToInt32(txtAmount.Text, 0), varList.SelectedItem as string);\r\n                }\r\n                else\r\n                {\r\n                    a = txtAmount.Text.Contains(\"{\") // using an if variable\r\n                        ? new IfAction((IfAction.IfVarType) varList.SelectedIndex, (sbyte) opList.SelectedIndex,\r\n                            txtAmount.Text)\r\n                        : new IfAction((IfAction.IfVarType) varList.SelectedIndex, (sbyte) opList.SelectedIndex,\r\n                            Utility.ToInt32(txtAmount.Text, 0));\r\n                }\r\n            }\r\n            catch\r\n            {\r\n                return;\r\n            }\r\n\r\n            if (m_Action == null)\r\n                m_Macro.Insert(m_Idx + 1, a);\r\n            else\r\n                m_Action.Parent.Convert(m_Action, a);\r\n            this.DialogResult = DialogResult.OK;\r\n            this.Close();\r\n        }\r\n\r\n        private void MacroInsertIf_Load(object sender, System.EventArgs e)\r\n        {\r\n            Language.LoadControlNames(this);\r\n\r\n            if (m_Action is IfAction)\r\n            {\r\n                try\r\n                {\r\n                    varList.SelectedIndex = (int) ((IfAction) m_Action).Variable;\r\n                }\r\n                catch\r\n                {\r\n                }\r\n\r\n                try\r\n                {\r\n                    opList.SelectedIndex = (int) ((IfAction) m_Action).Op;\r\n                }\r\n                catch\r\n                {\r\n                }\r\n\r\n                try\r\n                {\r\n                    if (varList.SelectedIndex != 3 && (varList.SelectedIndex <= 5 ||\r\n                                                       varList.SelectedIndex >=\r\n                                                       (int) IfAction.IfVarType.BeginCountersMarker))\r\n                        txtAmount.Text = ((IfAction) m_Action).Value.ToString();\r\n                }\r\n                catch\r\n                {\r\n                }\r\n\r\n                if (((IfAction) m_Action).Counter != null &&\r\n                    ((IfAction) m_Action).Variable == IfAction.IfVarType.Counter)\r\n                    try\r\n                    {\r\n                        varList.SelectedItem = ((IfAction) m_Action).Counter;\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n\r\n                if (((IfAction) m_Action).SkillId != -1 &&\r\n                    ((IfAction) m_Action).Variable == IfAction.IfVarType.Skill)\r\n                    try\r\n                    {\r\n                        varList.SelectedItem = Skills.GetSkillDisplayName(((IfAction) m_Action).SkillId);\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n            }\r\n        }\r\n\r\n        private void varList_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                opList.Visible = varList.SelectedIndex < 3 || varList.SelectedIndex == 5 ||\r\n                                 varList.SelectedIndex >= (int) IfAction.IfVarType.BeginCountersMarker;\r\n                txtAmount.Visible = varList.SelectedIndex != 3 &&\r\n                                    (varList.SelectedIndex <= 5 || varList.SelectedIndex >=\r\n                                     (int) IfAction.IfVarType.BeginCountersMarker);\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            /*if ( !opList.Visible )\r\n            {\r\n                if ( txtAmount.Visible )\r\n                {\r\n                    //varList.Size = new System.Drawing.Size(80, 21);\r\n\r\n                    //txtAmount.Location = new System.Drawing.Point(104, 9);\r\n                    //txtAmount.Size = new System.Drawing.Size(120, 20);\r\n                }\r\n                else\r\n                {\r\n                    //varList.Size = new System.Drawing.Size(200, 21);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                varList.Size = new System.Drawing.Size(80, 21);\r\n\r\n                txtAmount.Location = new System.Drawing.Point(144, 9);\r\n                txtAmount.Size = new System.Drawing.Size(80, 20);\r\n            }*/\r\n        }\r\n\r\n        private void ifVariables_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (ifVariables.SelectedItem.ToString().Substring(0, 1).Equals(\"{\") && ifVariables.Focused)\r\n            {\r\n                txtAmount.Text = $\"{ifVariables.SelectedItem}\";\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/MacroInsertIf.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n</root>"
  },
  {
    "path": "Razor/UI/MacroInsertWait.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Windows.Forms;\r\nusing Assistant.Macros;\r\n\r\nnamespace Assistant\r\n{\r\n    /// <summary>\r\n    /// Summary description for MacroInsertWait.\r\n    /// </summary>\r\n    public class MacroInsertWait : System.Windows.Forms.Form\r\n    {\r\n        private Macro m_Macro;\r\n        private int m_Idx;\r\n        private MacroAction m_Action;\r\n\r\n        private System.Windows.Forms.Button insert;\r\n        private System.Windows.Forms.RadioButton radioPause;\r\n        private System.Windows.Forms.TextBox pause;\r\n        private System.Windows.Forms.Label label1;\r\n        private System.Windows.Forms.RadioButton radioGump;\r\n        private System.Windows.Forms.RadioButton radioStat;\r\n        private System.Windows.Forms.TextBox statAmount;\r\n        private System.Windows.Forms.Button cancel;\r\n        private System.Windows.Forms.RadioButton radioTarg;\r\n        private System.Windows.Forms.ComboBox statList;\r\n        private System.Windows.Forms.ComboBox statOpList;\r\n        private System.Windows.Forms.RadioButton radioMenu;\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        public MacroInsertWait(Macro m, int idx)\r\n        {\r\n            m_Macro = m;\r\n            m_Idx = idx;\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n\r\n            //\r\n            // TODO: Add any constructor code after InitializeComponent call\r\n            //\r\n        }\r\n\r\n        public MacroInsertWait(MacroAction a)\r\n        {\r\n            m_Action = a;\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n\r\n            //\r\n            // TODO: Add any constructor code after InitializeComponent call\r\n            //\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            this.insert = new System.Windows.Forms.Button();\r\n            this.radioPause = new System.Windows.Forms.RadioButton();\r\n            this.pause = new System.Windows.Forms.TextBox();\r\n            this.label1 = new System.Windows.Forms.Label();\r\n            this.radioGump = new System.Windows.Forms.RadioButton();\r\n            this.radioTarg = new System.Windows.Forms.RadioButton();\r\n            this.radioStat = new System.Windows.Forms.RadioButton();\r\n            this.statAmount = new System.Windows.Forms.TextBox();\r\n            this.statList = new System.Windows.Forms.ComboBox();\r\n            this.cancel = new System.Windows.Forms.Button();\r\n            this.statOpList = new System.Windows.Forms.ComboBox();\r\n            this.radioMenu = new System.Windows.Forms.RadioButton();\r\n            this.SuspendLayout();\r\n            // \r\n            // insert\r\n            // \r\n            this.insert.Location = new System.Drawing.Point(67, 148);\r\n            this.insert.Name = \"insert\";\r\n            this.insert.Size = new System.Drawing.Size(64, 38);\r\n            this.insert.TabIndex = 0;\r\n            this.insert.Text = \"&Insert\";\r\n            this.insert.Click += new System.EventHandler(this.insert_Click);\r\n            // \r\n            // radioPause\r\n            // \r\n            this.radioPause.Location = new System.Drawing.Point(12, 12);\r\n            this.radioPause.Name = \"radioPause\";\r\n            this.radioPause.Size = new System.Drawing.Size(101, 20);\r\n            this.radioPause.TabIndex = 1;\r\n            this.radioPause.Text = \"Pause for:\";\r\n            this.radioPause.CheckedChanged += new System.EventHandler(this.radioPause_CheckedChanged);\r\n            // \r\n            // pause\r\n            // \r\n            this.pause.Enabled = false;\r\n            this.pause.Location = new System.Drawing.Point(89, 12);\r\n            this.pause.Name = \"pause\";\r\n            this.pause.Size = new System.Drawing.Size(40, 23);\r\n            this.pause.TabIndex = 2;\r\n            // \r\n            // label1\r\n            // \r\n            this.label1.Location = new System.Drawing.Point(135, 15);\r\n            this.label1.Name = \"label1\";\r\n            this.label1.Size = new System.Drawing.Size(91, 20);\r\n            this.label1.TabIndex = 3;\r\n            this.label1.Text = \"milliseconds\";\r\n            // \r\n            // radioGump\r\n            // \r\n            this.radioGump.Location = new System.Drawing.Point(12, 41);\r\n            this.radioGump.Name = \"radioGump\";\r\n            this.radioGump.Size = new System.Drawing.Size(176, 20);\r\n            this.radioGump.TabIndex = 4;\r\n            this.radioGump.Text = \"Wait for Gump\";\r\n            // \r\n            // radioTarg\r\n            // \r\n            this.radioTarg.Location = new System.Drawing.Point(12, 93);\r\n            this.radioTarg.Name = \"radioTarg\";\r\n            this.radioTarg.Size = new System.Drawing.Size(128, 20);\r\n            this.radioTarg.TabIndex = 5;\r\n            this.radioTarg.Text = \"Wait for Target\";\r\n            // \r\n            // radioStat\r\n            // \r\n            this.radioStat.Location = new System.Drawing.Point(12, 119);\r\n            this.radioStat.Name = \"radioStat\";\r\n            this.radioStat.Size = new System.Drawing.Size(67, 20);\r\n            this.radioStat.TabIndex = 6;\r\n            this.radioStat.Text = \"Wait for \";\r\n            this.radioStat.CheckedChanged += new System.EventHandler(this.radioStat_CheckedChanged);\r\n            // \r\n            // statAmount\r\n            // \r\n            this.statAmount.Enabled = false;\r\n            this.statAmount.Location = new System.Drawing.Point(205, 119);\r\n            this.statAmount.Name = \"statAmount\";\r\n            this.statAmount.Size = new System.Drawing.Size(50, 23);\r\n            this.statAmount.TabIndex = 7;\r\n            // \r\n            // statList\r\n            // \r\n            this.statList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\r\n            this.statList.Enabled = false;\r\n            this.statList.Items.AddRange(new object[]\r\n            {\r\n                \"Hits\",\r\n                \"Mana\",\r\n                \"Stamina\"\r\n            });\r\n            this.statList.Location = new System.Drawing.Point(85, 119);\r\n            this.statList.Name = \"statList\";\r\n            this.statList.Size = new System.Drawing.Size(64, 23);\r\n            this.statList.TabIndex = 8;\r\n            // \r\n            // cancel\r\n            // \r\n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\r\n            this.cancel.Location = new System.Drawing.Point(137, 148);\r\n            this.cancel.Name = \"cancel\";\r\n            this.cancel.Size = new System.Drawing.Size(64, 38);\r\n            this.cancel.TabIndex = 10;\r\n            this.cancel.Text = \"&Cancel\";\r\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\r\n            // \r\n            // statOpList\r\n            // \r\n            this.statOpList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\r\n            this.statOpList.Enabled = false;\r\n            this.statOpList.Items.AddRange(new object[]\r\n            {\r\n                \"<=\",\r\n                \">=\"\r\n            });\r\n            this.statOpList.Location = new System.Drawing.Point(155, 119);\r\n            this.statOpList.Name = \"statOpList\";\r\n            this.statOpList.Size = new System.Drawing.Size(44, 23);\r\n            this.statOpList.TabIndex = 11;\r\n            // \r\n            // radioMenu\r\n            // \r\n            this.radioMenu.Location = new System.Drawing.Point(12, 67);\r\n            this.radioMenu.Name = \"radioMenu\";\r\n            this.radioMenu.Size = new System.Drawing.Size(176, 20);\r\n            this.radioMenu.TabIndex = 12;\r\n            this.radioMenu.Text = \"Wait for old-style Menu/Dialog\";\r\n            // \r\n            // MacroInsertWait\r\n            // \r\n            this.AcceptButton = this.insert;\r\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\r\n            this.CancelButton = this.cancel;\r\n            this.ClientSize = new System.Drawing.Size(267, 192);\r\n            this.ControlBox = false;\r\n            this.Controls.Add(this.radioMenu);\r\n            this.Controls.Add(this.statOpList);\r\n            this.Controls.Add(this.cancel);\r\n            this.Controls.Add(this.statList);\r\n            this.Controls.Add(this.statAmount);\r\n            this.Controls.Add(this.radioStat);\r\n            this.Controls.Add(this.radioTarg);\r\n            this.Controls.Add(this.label1);\r\n            this.Controls.Add(this.pause);\r\n            this.Controls.Add(this.radioPause);\r\n            this.Controls.Add(this.insert);\r\n            this.Controls.Add(this.radioGump);\r\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\r\n            this.Name = \"MacroInsertWait\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\r\n            this.Text = \"Insert Wait/Pause...\";\r\n            this.Load += new System.EventHandler(this.MacroInsertWait_Load);\r\n            this.ResumeLayout(false);\r\n            this.PerformLayout();\r\n        }\r\n\r\n        #endregion\r\n\r\n        private void cancel_Click(object sender, System.EventArgs e)\r\n        {\r\n            this.DialogResult = DialogResult.Cancel;\r\n            this.Close();\r\n        }\r\n\r\n        private void insert_Click(object sender, System.EventArgs e)\r\n        {\r\n            MacroAction a = null;\r\n\r\n            if (radioPause.Checked)\r\n                a = new PauseAction(TimeSpan.FromMilliseconds(Utility.ToInt32(pause.Text, 1000)));\r\n            else if (radioGump.Checked)\r\n                a = new WaitForGumpAction(0);\r\n            else if (radioMenu.Checked)\r\n                a = new WaitForMenuAction(0);\r\n            else if (radioTarg.Checked)\r\n                a = new WaitForTargetAction();\r\n            else if (radioStat.Checked && statList.SelectedIndex >= 0 && statList.SelectedIndex < 3 &&\r\n                     statOpList.SelectedIndex >= 0 && statOpList.SelectedIndex < statOpList.Items.Count)\r\n                a = new WaitForStatAction((IfAction.IfVarType) statList.SelectedIndex, (byte) statOpList.SelectedIndex,\r\n                    Utility.ToInt32(statAmount.Text, 0));\r\n\r\n            if (a != null)\r\n            {\r\n                if (m_Action == null)\r\n                    m_Macro.Insert(m_Idx + 1, a);\r\n                else\r\n                    m_Action.Parent.Convert(m_Action, a);\r\n                this.DialogResult = DialogResult.OK;\r\n                this.Close();\r\n            }\r\n        }\r\n\r\n        private void radioStat_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            statList.Enabled = statAmount.Enabled = statOpList.Enabled = radioStat.Checked;\r\n        }\r\n\r\n        private void radioPause_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            pause.Enabled = radioPause.Checked;\r\n        }\r\n\r\n        private void MacroInsertWait_Load(object sender, System.EventArgs e)\r\n        {\r\n            Language.LoadControlNames(this);\r\n\r\n            radioPause.Checked = m_Action is PauseAction;\r\n            radioGump.Checked = m_Action is WaitForGumpAction;\r\n            radioMenu.Checked = m_Action is WaitForMenuAction;\r\n            radioTarg.Checked = m_Action is WaitForTargetAction;\r\n            radioStat.Checked = m_Action is WaitForStatAction;\r\n\r\n            if (radioPause.Checked)\r\n            {\r\n                pause.Text = ((int) ((PauseAction) m_Action).Timeout.TotalMilliseconds).ToString();\r\n            }\r\n            else if (radioStat.Checked)\r\n            {\r\n                statList.SelectedIndex = (int) ((WaitForStatAction) m_Action).Stat;\r\n                statOpList.SelectedIndex = (int) ((WaitForStatAction) m_Action).Op;\r\n                statAmount.Text = ((WaitForStatAction) m_Action).Amount.ToString();\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/MacroInsertWait.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n</root>"
  },
  {
    "path": "Razor/UI/MacroInsertWhile.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Windows.Forms;\nusing Assistant.Macros;\nusing Ultima;\n\nnamespace Assistant\n{\n    /// <summary>\n    /// Summary description for MacroInsertIf.\n    /// </summary>\n    public class MacroInsertWhile : System.Windows.Forms.Form\n    {\n        private Macro m_Macro;\n        private int m_Idx;\n        private MacroAction m_Action;\n\n        private int m_SkillStart = -1;\n\n        private System.Windows.Forms.Button insert;\n        private System.Windows.Forms.TextBox txtAmount;\n        private System.Windows.Forms.Button cancel;\n        private System.Windows.Forms.ComboBox varList;\n        private System.Windows.Forms.ComboBox opList;\n        private System.Windows.Forms.Label label1;\n        private ComboBox whileVariables;\n\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.Container components = null;\n\n        public MacroInsertWhile(Macro m, int idx)\n        {\n            m_Macro = m;\n            m_Idx = idx;\n            //\n            // Required for Windows Form Designer support\n            //\n            InitializeComponent();\n\n            foreach (Counter c in Counter.List)\n                varList.Items.Add(c.Name);\n\n            m_SkillStart = varList.Items.Count;\n\n            if (World.Player != null && World.Player.SkillsSent)\n            {\n                foreach (Skill skill in World.Player.Skills)\n                {\n                    varList.Items.Add(Skills.GetSkillDisplayName(skill.Index));\n                }\n            }\n        }\n\n        public MacroInsertWhile(MacroAction a)\n        {\n            m_Action = a;\n            //\n            // Required for Windows Form Designer support\n            //\n            InitializeComponent();\n\n            foreach (Counter c in Counter.List)\n                varList.Items.Add(c.Name);\n\n            m_SkillStart = varList.Items.Count;\n\n            if (World.Player != null && World.Player.SkillsSent)\n            {\n                foreach (Skill skill in World.Player.Skills)\n                {\n                    varList.Items.Add(Skills.GetSkillDisplayName(skill.Index));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                if (components != null)\n                {\n                    components.Dispose();\n                }\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.insert = new System.Windows.Forms.Button();\n            this.txtAmount = new System.Windows.Forms.TextBox();\n            this.varList = new System.Windows.Forms.ComboBox();\n            this.cancel = new System.Windows.Forms.Button();\n            this.opList = new System.Windows.Forms.ComboBox();\n            this.label1 = new System.Windows.Forms.Label();\n            this.whileVariables = new System.Windows.Forms.ComboBox();\n            this.SuspendLayout();\n            // \n            // insert\n            // \n            this.insert.Location = new System.Drawing.Point(117, 38);\n            this.insert.Name = \"insert\";\n            this.insert.Size = new System.Drawing.Size(76, 33);\n            this.insert.TabIndex = 0;\n            this.insert.Text = \"&Insert\";\n            this.insert.Click += new System.EventHandler(this.insert_Click);\n            // \n            // txtAmount\n            // \n            this.txtAmount.Location = new System.Drawing.Point(266, 9);\n            this.txtAmount.Name = \"txtAmount\";\n            this.txtAmount.Size = new System.Drawing.Size(126, 23);\n            this.txtAmount.TabIndex = 7;\n            // \n            // varList\n            // \n            this.varList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.varList.Items.AddRange(new object[]\n            {\n                \"Hits\",\n                \"Mana\",\n                \"Stamina\",\n                \"Poisoned\",\n                \"SysMessage\",\n                \"Weight\",\n                \"Mounted\",\n                \"R Hand Empty\",\n                \"L Hand Empty\"\n            });\n            this.varList.Location = new System.Drawing.Point(58, 9);\n            this.varList.Name = \"varList\";\n            this.varList.Size = new System.Drawing.Size(143, 23);\n            this.varList.TabIndex = 8;\n            this.varList.SelectedIndexChanged += new System.EventHandler(this.varList_SelectedIndexChanged);\n            // \n            // cancel\n            // \n            this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\n            this.cancel.Location = new System.Drawing.Point(199, 38);\n            this.cancel.Name = \"cancel\";\n            this.cancel.Size = new System.Drawing.Size(76, 33);\n            this.cancel.TabIndex = 10;\n            this.cancel.Text = \"&Cancel\";\n            this.cancel.Click += new System.EventHandler(this.cancel_Click);\n            // \n            // opList\n            // \n            this.opList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.opList.Items.AddRange(new object[]\n            {\n                \"<=\",\n                \">=\",\n                \"<\",\n                \">\"\n            });\n            this.opList.Location = new System.Drawing.Point(207, 9);\n            this.opList.Name = \"opList\";\n            this.opList.Size = new System.Drawing.Size(53, 23);\n            this.opList.TabIndex = 11;\n            // \n            // label1\n            // \n            this.label1.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Bold,\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\n            this.label1.Location = new System.Drawing.Point(8, 12);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(44, 20);\n            this.label1.TabIndex = 12;\n            this.label1.Text = \"While:\";\n            // \n            // whileVariables\n            // \n            this.whileVariables.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.whileVariables.FormattingEnabled = true;\n            this.whileVariables.Items.AddRange(new object[]\n            {\n                \"{maxhp}\",\n                \"{maxstam}\",\n                \"{maxmana}\"\n            });\n            this.whileVariables.Location = new System.Drawing.Point(281, 44);\n            this.whileVariables.Name = \"whileVariables\";\n            this.whileVariables.Size = new System.Drawing.Size(104, 23);\n            this.whileVariables.TabIndex = 14;\n            this.whileVariables.SelectedIndexChanged += new System.EventHandler(this.ifVariables_SelectedIndexChanged);\n            // \n            // MacroInsertWhile\n            // \n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\n            this.ClientSize = new System.Drawing.Size(404, 79);\n            this.ControlBox = false;\n            this.Controls.Add(this.whileVariables);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.opList);\n            this.Controls.Add(this.cancel);\n            this.Controls.Add(this.varList);\n            this.Controls.Add(this.txtAmount);\n            this.Controls.Add(this.insert);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\n            this.Name = \"MacroInsertWhile\";\n            this.ShowInTaskbar = false;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\n            this.Text = \"Insert While...\";\n            this.Load += new System.EventHandler(this.MacroInsertWhile_Load);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n        }\n\n        #endregion\n\n        private void cancel_Click(object sender, System.EventArgs e)\n        {\n            this.DialogResult = DialogResult.Cancel;\n            this.Close();\n        }\n\n        private void insert_Click(object sender, System.EventArgs e)\n        {\n            MacroAction a = null;\n\n            try\n            {\n                if (varList.SelectedIndex == (int) WhileAction.WhileVarType.SysMessage)\n                {\n                    a = new WhileAction((WhileAction.WhileVarType) varList.SelectedIndex, txtAmount.Text);\n                }\n                else if (varList.SelectedIndex >= m_SkillStart)\n                {\n                    int skillId = -1;\n\n                    foreach (Skill skill in World.Player.Skills)\n                    {\n                        if (Skills.GetSkillDisplayName(skill.Index).Equals(varList.SelectedItem as string))\n                        {\n                            skillId = skill.Index;\n                            break;\n                        }\n                    }\n\n                    if (skillId != -1)\n                        a = new WhileAction(WhileAction.WhileVarType.Skill, (sbyte) opList.SelectedIndex,\n                            Utility.ToDouble(txtAmount.Text, 0.0), skillId);\n                }\n                else if (varList.SelectedIndex >= (int) WhileAction.WhileVarType.BeginCountersMarker)\n                {\n                    a = new WhileAction(WhileAction.WhileVarType.Counter, (sbyte) opList.SelectedIndex,\n                        Utility.ToInt32(txtAmount.Text, 0), varList.SelectedItem as string);\n                }\n                else\n                {\n                    a = txtAmount.Text.Contains(\"{\") // using an if variable\n                        ? new WhileAction((WhileAction.WhileVarType) varList.SelectedIndex,\n                            (sbyte) opList.SelectedIndex,\n                            txtAmount.Text)\n                        : new WhileAction((WhileAction.WhileVarType) varList.SelectedIndex,\n                            (sbyte) opList.SelectedIndex,\n                            Utility.ToInt32(txtAmount.Text, 0));\n                }\n            }\n            catch\n            {\n                return;\n            }\n\n            if (m_Action == null)\n                m_Macro.Insert(m_Idx + 1, a);\n            else\n                m_Action.Parent.Convert(m_Action, a);\n            this.DialogResult = DialogResult.OK;\n            this.Close();\n        }\n\n        private void MacroInsertWhile_Load(object sender, System.EventArgs e)\n        {\n            Language.LoadControlNames(this);\n\n            if (m_Action is WhileAction)\n            {\n                try\n                {\n                    varList.SelectedIndex = (int) ((WhileAction) m_Action).Variable;\n                }\n                catch\n                {\n                }\n\n                try\n                {\n                    opList.SelectedIndex = (int) ((WhileAction) m_Action).Op;\n                }\n                catch\n                {\n                }\n\n                try\n                {\n                    if (varList.SelectedIndex != 3 && (varList.SelectedIndex <= 5 ||\n                                                       varList.SelectedIndex >=\n                                                       (int) WhileAction.WhileVarType.BeginCountersMarker))\n                        txtAmount.Text = ((WhileAction) m_Action).Value.ToString();\n                }\n                catch\n                {\n                }\n\n                if (((WhileAction) m_Action).Counter != null &&\n                    ((WhileAction) m_Action).Variable == WhileAction.WhileVarType.Counter)\n                    try\n                    {\n                        varList.SelectedItem = ((WhileAction) m_Action).Counter;\n                    }\n                    catch\n                    {\n                    }\n\n                if (((WhileAction) m_Action).SkillId != -1 &&\n                    ((WhileAction) m_Action).Variable == WhileAction.WhileVarType.Skill)\n                    try\n                    {\n                        varList.SelectedItem = Skills.GetSkillDisplayName(((WhileAction) m_Action).SkillId);\n                    }\n                    catch\n                    {\n                    }\n            }\n        }\n\n        private void varList_SelectedIndexChanged(object sender, System.EventArgs e)\n        {\n            try\n            {\n                opList.Visible = varList.SelectedIndex < 3 || varList.SelectedIndex == 5 ||\n                                 varList.SelectedIndex >= (int) WhileAction.WhileVarType.BeginCountersMarker;\n                txtAmount.Visible = varList.SelectedIndex != 3 &&\n                                    (varList.SelectedIndex <= 5 || varList.SelectedIndex >=\n                                     (int) WhileAction.WhileVarType.BeginCountersMarker);\n            }\n            catch\n            {\n            }\n\n            /*if ( !opList.Visible )\n            {\n                if ( txtAmount.Visible )\n                {\n                    //varList.Size = new System.Drawing.Size(80, 21);\n\n                    //txtAmount.Location = new System.Drawing.Point(104, 9);\n                    //txtAmount.Size = new System.Drawing.Size(120, 20);\n                }\n                else\n                {\n                    //varList.Size = new System.Drawing.Size(200, 21);\n                }\n            }\n            else\n            {\n                varList.Size = new System.Drawing.Size(80, 21);\n\n                txtAmount.Location = new System.Drawing.Point(144, 9);\n                txtAmount.Size = new System.Drawing.Size(80, 20);\n            }*/\n        }\n\n        private void ifVariables_SelectedIndexChanged(object sender, EventArgs e)\n        {\n            if (whileVariables.SelectedItem.ToString().Substring(0, 1).Equals(\"{\") && whileVariables.Focused)\n            {\n                txtAmount.Text = $\"{whileVariables.SelectedItem}\";\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/MacroInsertWhile.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "Razor/UI/MessageDialog.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Windows.Forms;\r\n\r\nnamespace Assistant\r\n{\r\n    /// <summary>\r\n    /// Summary description for MessageDialog.\r\n    /// </summary>\r\n    public class MessageDialog : System.Windows.Forms.Form\r\n    {\r\n        private System.Windows.Forms.Button okay;\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        private string m_Title;\r\n        private string m_Message;\r\n        private System.Windows.Forms.TextBox message;\r\n        private bool m_CanIgnore;\r\n\r\n        public MessageDialog(string title, string message) : this(title, false, message)\r\n        {\r\n        }\r\n\r\n        public MessageDialog(string title, bool ignorable, string message, params object[] msgArgs) : this(title,\r\n            ignorable, String.Format(message, msgArgs))\r\n        {\r\n        }\r\n\r\n        public MessageDialog(string title, bool ignorable, string message)\r\n        {\r\n            m_Title = title;\r\n            m_Message = message;\r\n            m_CanIgnore = ignorable;\r\n            //\r\n            // Required for Windows Form Designer support\r\n            //\r\n            InitializeComponent();\r\n\r\n            //\r\n            // TODO: Add any constructor code after InitializeComponent call\r\n            //\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            this.message = new System.Windows.Forms.TextBox();\r\n            this.okay = new System.Windows.Forms.Button();\r\n            this.SuspendLayout();\r\n            // \r\n            // message\r\n            // \r\n            this.message.Location = new System.Drawing.Point(8, 8);\r\n            this.message.Multiline = true;\r\n            this.message.Name = \"message\";\r\n            this.message.ReadOnly = true;\r\n            this.message.ScrollBars = System.Windows.Forms.ScrollBars.Both;\r\n            this.message.Size = new System.Drawing.Size(552, 320);\r\n            this.message.TabIndex = 0;\r\n            // \r\n            // okay\r\n            // \r\n            this.okay.DialogResult = System.Windows.Forms.DialogResult.OK;\r\n            this.okay.Location = new System.Drawing.Point(8, 334);\r\n            this.okay.Name = \"okay\";\r\n            this.okay.Size = new System.Drawing.Size(88, 26);\r\n            this.okay.TabIndex = 1;\r\n            this.okay.Text = \"&Okay\";\r\n            this.okay.Click += new System.EventHandler(this.okay_Click);\r\n            // \r\n            // MessageDialog\r\n            // \r\n            this.AcceptButton = this.okay;\r\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\r\n            this.ClientSize = new System.Drawing.Size(567, 366);\r\n            this.ControlBox = false;\r\n            this.Controls.Add(this.okay);\r\n            this.Controls.Add(this.message);\r\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\r\n            this.Name = \"MessageDialog\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\r\n            this.Text = \"Message\";\r\n            this.Load += new System.EventHandler(this.MessageDialog_Load);\r\n            this.ResumeLayout(false);\r\n            this.PerformLayout();\r\n        }\r\n\r\n        #endregion\r\n\r\n        private void MessageDialog_Load(object sender, System.EventArgs e)\r\n        {\r\n            this.Text = m_Title;\r\n            this.message.Text = m_Message;\r\n            this.message.Select(0, 0);\r\n            this.BringToFront();\r\n\r\n            if (m_CanIgnore)\r\n                this.okay.Text = \"&Ignore\";\r\n        }\r\n\r\n        private void okay_Click(object sender, System.EventArgs e)\r\n        {\r\n            this.DialogResult = DialogResult.OK;\r\n            this.Close();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/MessageDialog.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n</root>"
  },
  {
    "path": "Razor/UI/Razor.Designer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Windows.Forms;\n\nnamespace Assistant\n{\n    public partial class MainForm : System.Windows.Forms.Form\n    {\n\n        #region Class Variables\n\n        private System.Windows.Forms.NotifyIcon m_NotifyIcon;\n        private System.Windows.Forms.TabControl tabs;\n        private System.Windows.Forms.ColumnHeader skillHDRName;\n        private System.Windows.Forms.ColumnHeader skillHDRvalue;\n        private System.Windows.Forms.ColumnHeader skillHDRbase;\n        private System.Windows.Forms.ColumnHeader skillHDRdelta;\n        private System.Windows.Forms.Button resetDelta;\n        private System.Windows.Forms.Button setlocks;\n        private System.Windows.Forms.ComboBox locks;\n        private System.Windows.Forms.ListView skillList;\n        private System.Windows.Forms.ColumnHeader skillHDRcap;\n        private System.Windows.Forms.Label label1;\n        private System.Windows.Forms.TextBox baseTotal;\n        private System.Windows.Forms.TabPage dressTab;\n        private System.Windows.Forms.Button skillCopySel;\n        private System.Windows.Forms.Button skillCopyAll;\n        private System.Windows.Forms.GroupBox groupBox5;\n        private System.Windows.Forms.Button removeDress;\n        private System.Windows.Forms.Button addDress;\n        private System.Windows.Forms.ListBox dressList;\n        private System.Windows.Forms.GroupBox groupBox6;\n        private System.Windows.Forms.Button targItem;\n        private System.Windows.Forms.ListBox dressItems;\n        private System.Windows.Forms.Button dressUseCur;\n        private System.Windows.Forms.TabPage generalTab;\n        private System.Windows.Forms.TabPage displayTab;\n        private System.Windows.Forms.TabPage skillsTab;\n        private System.Windows.Forms.TabPage hotkeysTab;\n        private System.Windows.Forms.CheckBox chkCtrl;\n        private System.Windows.Forms.CheckBox chkAlt;\n        private System.Windows.Forms.CheckBox chkShift;\n        private System.Windows.Forms.GroupBox groupBox8;\n        private System.Windows.Forms.TextBox hkKey;\n        private System.Windows.Forms.Button setHK;\n        private System.Windows.Forms.Button unsetHK;\n        private System.Windows.Forms.Label label2;\n        private System.Windows.Forms.CheckBox chkPass;\n        private System.Windows.Forms.TabPage moreOptTab;\n        private System.Windows.Forms.TabPage agentsTab;\n        private System.Windows.Forms.GroupBox agentGroup;\n        private System.Windows.Forms.ListBox agentSubList;\n        private System.Windows.Forms.Button agentB1;\n        private System.Windows.Forms.Button agentB2;\n        private System.Windows.Forms.Button agentB3;\n        private System.Windows.Forms.Button dohotkey;\n        private System.Windows.Forms.Button agentB4;\n        private System.Windows.Forms.CheckBox dispDelta;\n        private System.Windows.Forms.ComboBox agentList;\n        private System.Windows.Forms.TabPage macrosTab;\n        private System.Windows.Forms.TreeView hotkeyTree;\n        private System.Windows.Forms.TabPage screenshotTab;\n        private System.Windows.Forms.TabPage aboutTab;\n        private System.Windows.Forms.Button dressNow;\n        private System.Windows.Forms.Button undressList;\n        private System.Windows.Forms.PictureBox screenPrev;\n        private System.Windows.Forms.ListBox screensList;\n        private System.Windows.Forms.Button setScnPath;\n        private System.Windows.Forms.RadioButton radioFull;\n        private System.Windows.Forms.RadioButton radioUO;\n        private System.Windows.Forms.CheckBox captureOthersDeath;\n        private System.Windows.Forms.TextBox screenPath;\n        private System.Windows.Forms.Button capNow;\n        private System.Windows.Forms.CheckBox dispTime;\n        private System.Windows.Forms.Button agentB5;\n        private System.Windows.Forms.Button agentB6;\n        private System.Windows.Forms.CheckBox undressConflicts;\n        private System.Windows.Forms.ColumnHeader skillHDRlock;\n        private System.ComponentModel.IContainer components;\n        private System.Windows.Forms.Button undressBag;\n        private System.Windows.Forms.Button dressDelSel;\n        private System.Windows.Forms.Label hkStatus;\n        private System.Windows.Forms.Button clearDress;\n        private System.Windows.Forms.Label label12;\n        private System.Windows.Forms.ComboBox imgFmt;\n        private ToolTip m_Tip;\n\n        #endregion\n\n        private int m_LastKV = 0;\n        private bool m_ProfileConfirmLoad;\n        private LinkLabel linkMain;\n        private Label label21;\n        private Label aboutVer;\n        private TextBox filterHotkeys;\n        private Label label22;\n        private bool m_CanClose = true;\n        private TabPage advancedTab;\n        private Label aboutSubInfo;\n        private Label lblCredits1;\n        private Label label20;\n        private CheckBox logSkillChanges;\n        private TreeView _hotkeyTreeViewCache = new TreeView();\n        private LinkLabel linkHelp;\n        private TabControl tabControl2;\n        private TabPage subMacrosTab;\n        private TabPage subMacrosOptionsTab;\n        private CheckBox rangeCheckDoubleClick;\n        private CheckBox rangeCheckTargetByType;\n        private Button nextMacroAction;\n        private CheckBox stepThroughMacro;\n        private CheckBox targetByTypeDifferent;\n        private System.Windows.Forms.GroupBox macroVariableGroup;\n        private ComboBox macroVariableTypeList;\n        private Button retargetMacroVariable;\n        private Button insertMacroVariable;\n        private Button removeMacroVariable;\n        private Button addMacroVariable;\n        private ListBox macroVariables;\n        private TextBox filterMacros;\n        private Label filterLabel;\n        private TreeView macroTree;\n        private Button delMacro;\n        private Button newMacro;\n        private GroupBox macroActGroup;\n        private Button playMacro;\n        private Label waitDisp;\n        private CheckBox loopMacro;\n        private Button recMacro;\n        private ListBox actionList;\n        private TabControl optionsTabCtrl;\n        private System.Windows.Forms.TabPage subOptionsSpeechTab;\n        private Button setLTHilight;\n        private CheckBox lthilight;\n        private Button setHarmHue;\n        private Button setNeuHue;\n        private Label lblHarmHue;\n        private Label lblNeuHue;\n        private Label lblBeneHue;\n        private Button setBeneHue;\n        private Button setSpeechHue;\n        private Button setWarnHue;\n        private Button setMsgHue;\n        private Button setExHue;\n        private Label lblWarnHue;\n        private Label lblMsgHue;\n        private Label lblExHue;\n        private TextBox txtSpellFormat;\n        private CheckBox chkForceSpellHue;\n        private CheckBox chkForceSpeechHue;\n        private Label label3;\n        private TabPage subOptionsTargetTab;\n        private CheckBox incomingMob;\n        private CheckBox incomingCorpse;\n        private CheckBox showAttackTargetNewOnly;\n        private CheckBox showTextTargetIndicator;\n        private CheckBox showAttackTarget;\n        private CheckBox showTargetMessagesOverChar;\n        private TextBox txtObjDelay;\n        private CheckBox objectDelay;\n        private TextBox ltRange;\n        private CheckBox QueueActions;\n        private CheckBox rangeCheckLT;\n        private CheckBox actionStatusMsg;\n        private Label label8;\n        private Label label6;\n        private CheckBox queueTargets;\n        private CheckBox showtargtext;\n        private Button containerLabels;\n        private CheckBox showContainerLabels;\n        private System.Windows.Forms.CheckBox showBuffDebuffOverhead;\n        private TextBox healthFmt;\n        private Label label10;\n        private CheckBox showHealthOH;\n        private CheckBox chkPartyOverhead;\n        private TabPage subOptionsMiscTab;\n        private Button setMinLightLevel;\n        private Button setMaxLightLevel;\n        private ComboBox seasonList;\n        private Label lblSeason;\n        private Label lightLevel;\n        private TrackBar lightLevelBar;\n        private CheckBox minMaxLightLevel;\n        private CheckBox blockPartyInvites;\n        private CheckBox blockTradeRequests;\n        private CheckBox blockOpenCorpsesTwice;\n        private CheckBox preAOSstatbar;\n        private TextBox corpseRange;\n        private CheckBox autoStackRes;\n        private Label label4;\n        private CheckBox openCorpses;\n        private CheckBox blockDis;\n        private CheckBox showStaticWalls;\n        private CheckBox showStaticWallLabels;\n        private CheckBox stealthOverhead;\n        private TextBox forceSizeX;\n        private TextBox forceSizeY;\n        private CheckBox blockHealPoison;\n        private CheckBox potionEquip;\n        private CheckBox spellUnequip;\n        private CheckBox autoOpenDoors;\n        private CheckBox chkStealth;\n        private Label label18;\n        private CheckBox gameSize;\n        private CheckBox damageTakenOverhead;\n        private CheckBox showDamageTaken;\n        private CheckBox damageDealtOverhead;\n        private CheckBox showDamageDealt;\n        private CheckBox rememberPwds;\n        private System.Windows.Forms.TabControl displayCountersTabCtrl;\n        private TabPage subDisplayTab;\n        private GroupBox groupBox11;\n        private Button razorTitleBarKey;\n        private System.Windows.Forms.CheckBox showInRazorTitleBar;\n        private TextBox razorTitleBar;\n        private System.Windows.Forms.CheckBox trackDps;\n        private System.Windows.Forms.CheckBox trackIncomingGold;\n        private CheckBox showNotoHue;\n        private CheckBox highlightSpellReags;\n        private GroupBox groupBox3;\n        private ComboBox titleBarParams;\n        private TextBox titleStr;\n        private CheckBox showInBar;\n        private TabPage subCountersTab;\n        private TextBox warnNum;\n        private CheckBox warnCount;\n        private CheckBox excludePouches;\n        private CheckBox titlebarImages;\n        private CheckBox checkNewConts;\n        private System.Windows.Forms.GroupBox groupBox2;\n        private System.Windows.Forms.ListView counters;\n        private ColumnHeader cntName;\n        private ColumnHeader cntCount;\n        private System.Windows.Forms.Button delCounter;\n        private System.Windows.Forms.Button addCounter;\n        private System.Windows.Forms.Button recount;\n        private TabControl subGeneralTab;\n        private TabPage subGenTab;\n        private RadioButton systray;\n        private RadioButton taskbar;\n        private ComboBox langSel;\n        private Label label7;\n        private Label label11;\n        private CheckBox showWelcome;\n        private TrackBar opacity;\n        private CheckBox alwaysTop;\n        private Label opacityLabel;\n        private GroupBox groupBox4;\n        private Button saveProfile;\n        private Button cloneProfile;\n        private Button delProfile;\n        private Button newProfile;\n        private ComboBox profiles;\n        private TextBox targetIndicatorFormat;\n        private Label lblTargetFormat;\n        private Label lblStealthFormat;\n        private TextBox stealthStepsFormat;\n        private CheckBox dispDeltaOverhead;\n        private Label lblCredits2;\n        private LinkLabel linkGitHub;\n        private Label lblCredits3;\n        private GroupBox groupBox15;\n        private Button btnMap;\n        private Button boatControl;\n        private CheckBox captureMibs;\n        private CheckBox macroActionDelay;\n        private CheckBox autoOpenDoorWhenHidden;\n        private CheckBox disableMacroPlayFinish;\n        private TabPage subBandageTimerTab;\n        private CheckBox onlyShowBandageTimerSeconds;\n        private TextBox bandageTimerFormat;\n        private CheckBox showBandageTimer;\n        private ComboBox bandageTimerLocation;\n        private TextBox bandageTimerSeconds;\n        private Label lblBandageCountFormat;\n        private Button setBandageHue;\n        private Button setTargetIndicatorHue;\n        private GroupBox groupSmartTarget;\n        private CheckBox nonFriendlyHarmfulOnly;\n        private CheckBox friendBeneficialOnly;\n        private CheckBox onlyNextPrevBeneficial;\n        private CheckBox smartLT;\n        private TextBox bandageEndMessage;\n        private TextBox bandageStartMessage;\n        private System.Windows.Forms.CheckBox showBandageEnd;\n        private System.Windows.Forms.CheckBox showBandageStart;\n        private System.Windows.Forms.Button buffDebuffOptions;\n        private TextBox captureOthersDeathDelay;\n        private Label lblCaptureOthersDeathMs;\n        private TextBox captureOwnDeathDelay;\n        private Label lblOwnDeathMs;\n        private CheckBox captureOwnDeath;\n        private Button setMacroHotKey;\n        private TabPage subFilterSoundMusic;\n        private CheckedListBox soundFilterList;\n        private CheckBox soundFilterEnabled;\n        private Button playSound;\n        private CheckBox showFilteredSound;\n        private CheckBox showPlayingSoundInfo;\n        private CheckBox showPlayingMusic;\n        private CheckBox playInClient;\n        private Button playMusic;\n        private ComboBox playableMusicList;\n        private TreeView _macroTreeViewCache = new TreeView();\n        private TreeView _scriptTreeViewCache = new TreeView();\n        private TreeView _itemTreeCache = new TreeView();\n\n\n        public Label WaitDisplay\n        {\n            get { return waitDisp; }\n        }\n\n        public MainForm()\n        {\n            m_ProfileConfirmLoad = true;\n            m_Tip = new ToolTip();\n            //\n            // Required for Windows Form Designer support\n            //\n            InitializeComponent();\n\n            m_NotifyIcon.ContextMenuStrip = new ContextMenuStrip();\n            m_NotifyIcon.ContextMenuStrip.Items.Add(\"Show Razor\", null, new EventHandler(DoShowMe));\n            m_NotifyIcon.ContextMenuStrip.Items.Add(\"Hide Razor\", null, new EventHandler(HideMe));\n            m_NotifyIcon.ContextMenuStrip.Items.Add(\"-\");\n            m_NotifyIcon.ContextMenuStrip.Items.Add(\"Toggle Razor Visibility\", null, new EventHandler(ToggleVisible));\n            m_NotifyIcon.ContextMenuStrip.Items.Add(\"-\");\n            m_NotifyIcon.ContextMenuStrip.Items.Add(\"Close Razor && UO\", null, new EventHandler(OnClose));\n\n            m_NotifyIcon.ContextMenuStrip.Items[0].Select();\n        }\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                if (components != null)\n                {\n                    components.Dispose();\n                }\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.components = new System.ComponentModel.Container();\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));\n            this.m_NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components);\n            this.tabs = new System.Windows.Forms.TabControl();\n            this.generalTab = new System.Windows.Forms.TabPage();\n            this.subGeneralTab = new System.Windows.Forms.TabControl();\n            this.subGenTab = new System.Windows.Forms.TabPage();\n            this.groupBox15 = new System.Windows.Forms.GroupBox();\n            this.boatControl = new System.Windows.Forms.Button();\n            this.btnMap = new System.Windows.Forms.Button();\n            this.systray = new System.Windows.Forms.RadioButton();\n            this.taskbar = new System.Windows.Forms.RadioButton();\n            this.langSel = new System.Windows.Forms.ComboBox();\n            this.label7 = new System.Windows.Forms.Label();\n            this.label11 = new System.Windows.Forms.Label();\n            this.showWelcome = new System.Windows.Forms.CheckBox();\n            this.opacity = new System.Windows.Forms.TrackBar();\n            this.alwaysTop = new System.Windows.Forms.CheckBox();\n            this.opacityLabel = new System.Windows.Forms.Label();\n            this.groupBox4 = new System.Windows.Forms.GroupBox();\n            this.saveProfile = new System.Windows.Forms.Button();\n            this.cloneProfile = new System.Windows.Forms.Button();\n            this.delProfile = new System.Windows.Forms.Button();\n            this.newProfile = new System.Windows.Forms.Button();\n            this.profiles = new System.Windows.Forms.ComboBox();\n            this.moreOptTab = new System.Windows.Forms.TabPage();\n            this.optionsTabCtrl = new System.Windows.Forms.TabControl();\n            this.subOptionsSpeechTab = new System.Windows.Forms.TabPage();\n            this.playEmoteSound = new System.Windows.Forms.CheckBox();\n            this.overrideSpellFormat = new System.Windows.Forms.CheckBox();\n            this.damageTakenOverhead = new System.Windows.Forms.CheckBox();\n            this.showDamageTaken = new System.Windows.Forms.CheckBox();\n            this.damageDealtOverhead = new System.Windows.Forms.CheckBox();\n            this.showDamageDealt = new System.Windows.Forms.CheckBox();\n            this.healthFmt = new System.Windows.Forms.TextBox();\n            this.label10 = new System.Windows.Forms.Label();\n            this.showHealthOH = new System.Windows.Forms.CheckBox();\n            this.chkPartyOverhead = new System.Windows.Forms.CheckBox();\n            this.containerLabels = new System.Windows.Forms.Button();\n            this.showContainerLabels = new System.Windows.Forms.CheckBox();\n            this.incomingMob = new System.Windows.Forms.CheckBox();\n            this.incomingCorpse = new System.Windows.Forms.CheckBox();\n            this.setLTHilight = new System.Windows.Forms.Button();\n            this.lthilight = new System.Windows.Forms.CheckBox();\n            this.setHarmHue = new System.Windows.Forms.Button();\n            this.setNeuHue = new System.Windows.Forms.Button();\n            this.lblHarmHue = new System.Windows.Forms.Label();\n            this.lblNeuHue = new System.Windows.Forms.Label();\n            this.lblBeneHue = new System.Windows.Forms.Label();\n            this.setBeneHue = new System.Windows.Forms.Button();\n            this.setSpeechHue = new System.Windows.Forms.Button();\n            this.setWarnHue = new System.Windows.Forms.Button();\n            this.setMsgHue = new System.Windows.Forms.Button();\n            this.setExHue = new System.Windows.Forms.Button();\n            this.lblWarnHue = new System.Windows.Forms.Label();\n            this.lblMsgHue = new System.Windows.Forms.Label();\n            this.lblExHue = new System.Windows.Forms.Label();\n            this.txtSpellFormat = new System.Windows.Forms.TextBox();\n            this.chkForceSpellHue = new System.Windows.Forms.CheckBox();\n            this.chkForceSpeechHue = new System.Windows.Forms.CheckBox();\n            this.label3 = new System.Windows.Forms.Label();\n            this.subOptionsTargetTab = new System.Windows.Forms.TabPage();\n            this.groupSmartTarget = new System.Windows.Forms.GroupBox();\n            this.nextPrevAbcOrder = new System.Windows.Forms.CheckBox();\n            this.nonFriendlyHarmfulOnly = new System.Windows.Forms.CheckBox();\n            this.friendBeneficialOnly = new System.Windows.Forms.CheckBox();\n            this.onlyNextPrevBeneficial = new System.Windows.Forms.CheckBox();\n            this.smartLT = new System.Windows.Forms.CheckBox();\n            this.setTargetIndicatorHue = new System.Windows.Forms.Button();\n            this.targetIndicatorFormat = new System.Windows.Forms.TextBox();\n            this.showtargtext = new System.Windows.Forms.CheckBox();\n            this.showAttackTargetNewOnly = new System.Windows.Forms.CheckBox();\n            this.showTextTargetIndicator = new System.Windows.Forms.CheckBox();\n            this.showAttackTarget = new System.Windows.Forms.CheckBox();\n            this.showTargetMessagesOverChar = new System.Windows.Forms.CheckBox();\n            this.txtObjDelay = new System.Windows.Forms.TextBox();\n            this.objectDelay = new System.Windows.Forms.CheckBox();\n            this.ltRange = new System.Windows.Forms.TextBox();\n            this.QueueActions = new System.Windows.Forms.CheckBox();\n            this.rangeCheckLT = new System.Windows.Forms.CheckBox();\n            this.actionStatusMsg = new System.Windows.Forms.CheckBox();\n            this.label8 = new System.Windows.Forms.Label();\n            this.label6 = new System.Windows.Forms.Label();\n            this.queueTargets = new System.Windows.Forms.CheckBox();\n            this.lblTargetFormat = new System.Windows.Forms.Label();\n            this.subOptionsMiscTab = new System.Windows.Forms.TabPage();\n            this.buyAgentIgnoreGold = new System.Windows.Forms.CheckBox();\n            this.reequipHandsPotion = new System.Windows.Forms.CheckBox();\n            this.autoOpenDoorWhenHidden = new System.Windows.Forms.CheckBox();\n            this.lblStealthFormat = new System.Windows.Forms.Label();\n            this.stealthStepsFormat = new System.Windows.Forms.TextBox();\n            this.rememberPwds = new System.Windows.Forms.CheckBox();\n            this.showStaticWalls = new System.Windows.Forms.CheckBox();\n            this.showStaticWallLabels = new System.Windows.Forms.CheckBox();\n            this.stealthOverhead = new System.Windows.Forms.CheckBox();\n            this.forceSizeX = new System.Windows.Forms.TextBox();\n            this.forceSizeY = new System.Windows.Forms.TextBox();\n            this.blockHealPoison = new System.Windows.Forms.CheckBox();\n            this.potionEquip = new System.Windows.Forms.CheckBox();\n            this.spellUnequip = new System.Windows.Forms.CheckBox();\n            this.autoOpenDoors = new System.Windows.Forms.CheckBox();\n            this.chkStealth = new System.Windows.Forms.CheckBox();\n            this.label18 = new System.Windows.Forms.Label();\n            this.gameSize = new System.Windows.Forms.CheckBox();\n            this.setMinLightLevel = new System.Windows.Forms.Button();\n            this.setMaxLightLevel = new System.Windows.Forms.Button();\n            this.seasonList = new System.Windows.Forms.ComboBox();\n            this.lblSeason = new System.Windows.Forms.Label();\n            this.lightLevel = new System.Windows.Forms.Label();\n            this.lightLevelBar = new System.Windows.Forms.TrackBar();\n            this.minMaxLightLevel = new System.Windows.Forms.CheckBox();\n            this.blockPartyInvites = new System.Windows.Forms.CheckBox();\n            this.blockTradeRequests = new System.Windows.Forms.CheckBox();\n            this.blockOpenCorpsesTwice = new System.Windows.Forms.CheckBox();\n            this.preAOSstatbar = new System.Windows.Forms.CheckBox();\n            this.corpseRange = new System.Windows.Forms.TextBox();\n            this.autoStackRes = new System.Windows.Forms.CheckBox();\n            this.label4 = new System.Windows.Forms.Label();\n            this.openCorpses = new System.Windows.Forms.CheckBox();\n            this.blockDis = new System.Windows.Forms.CheckBox();\n            this.displayTab = new System.Windows.Forms.TabPage();\n            this.displayCountersTabCtrl = new System.Windows.Forms.TabControl();\n            this.subDisplayTab = new System.Windows.Forms.TabPage();\n            this.groupBox11 = new System.Windows.Forms.GroupBox();\n            this.razorTitleBarKey = new System.Windows.Forms.Button();\n            this.showInRazorTitleBar = new System.Windows.Forms.CheckBox();\n            this.razorTitleBar = new System.Windows.Forms.TextBox();\n            this.trackDps = new System.Windows.Forms.CheckBox();\n            this.trackIncomingGold = new System.Windows.Forms.CheckBox();\n            this.showNotoHue = new System.Windows.Forms.CheckBox();\n            this.highlightSpellReags = new System.Windows.Forms.CheckBox();\n            this.groupBox3 = new System.Windows.Forms.GroupBox();\n            this.titleBarParams = new System.Windows.Forms.ComboBox();\n            this.titleStr = new System.Windows.Forms.TextBox();\n            this.showInBar = new System.Windows.Forms.CheckBox();\n            this.subCountersTab = new System.Windows.Forms.TabPage();\n            this.warnNum = new System.Windows.Forms.TextBox();\n            this.warnCount = new System.Windows.Forms.CheckBox();\n            this.excludePouches = new System.Windows.Forms.CheckBox();\n            this.titlebarImages = new System.Windows.Forms.CheckBox();\n            this.checkNewConts = new System.Windows.Forms.CheckBox();\n            this.groupBox2 = new System.Windows.Forms.GroupBox();\n            this.counters = new System.Windows.Forms.ListView();\n            this.cntName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.cntCount = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.delCounter = new System.Windows.Forms.Button();\n            this.addCounter = new System.Windows.Forms.Button();\n            this.recount = new System.Windows.Forms.Button();\n            this.subBandageTimerTab = new System.Windows.Forms.TabPage();\n            this.bandageEndMessage = new System.Windows.Forms.TextBox();\n            this.bandageStartMessage = new System.Windows.Forms.TextBox();\n            this.showBandageEnd = new System.Windows.Forms.CheckBox();\n            this.showBandageStart = new System.Windows.Forms.CheckBox();\n            this.setBandageHue = new System.Windows.Forms.Button();\n            this.bandageTimerLocation = new System.Windows.Forms.ComboBox();\n            this.bandageTimerSeconds = new System.Windows.Forms.TextBox();\n            this.onlyShowBandageTimerSeconds = new System.Windows.Forms.CheckBox();\n            this.bandageTimerFormat = new System.Windows.Forms.TextBox();\n            this.showBandageTimer = new System.Windows.Forms.CheckBox();\n            this.lblBandageCountFormat = new System.Windows.Forms.Label();\n            this.subOverheadTab = new System.Windows.Forms.TabPage();\n            this.setSound = new System.Windows.Forms.Button();\n            this.label14 = new System.Windows.Forms.Label();\n            this.unicodeStyle = new System.Windows.Forms.RadioButton();\n            this.asciiStyle = new System.Windows.Forms.RadioButton();\n            this.editOverheadMessage = new System.Windows.Forms.Button();\n            this.setColorHue = new System.Windows.Forms.Button();\n            this.removeOverheadMessage = new System.Windows.Forms.Button();\n            this.label13 = new System.Windows.Forms.Label();\n            this.overheadFormat = new System.Windows.Forms.TextBox();\n            this.setOverheadMessage = new System.Windows.Forms.Button();\n            this.cliLocOverheadView = new System.Windows.Forms.ListView();\n            this.cliLocOriginal = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.cliLocOverheadMessage = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.cliLocSound = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.cliLocSearch = new System.Windows.Forms.Button();\n            this.cliLocTextSearch = new System.Windows.Forms.TextBox();\n            this.lblOhSearch = new System.Windows.Forms.Label();\n            this.cliLocSearchView = new System.Windows.Forms.ListView();\n            this.cliLocSearchNumber = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.cliLocSearchText = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.showOverheadMessages = new System.Windows.Forms.CheckBox();\n            this.subWaypoints = new System.Windows.Forms.TabPage();\n            this.waypointOnDeath = new System.Windows.Forms.CheckBox();\n            this.lblWaypointTiles = new System.Windows.Forms.Label();\n            this.hideWaypointDist = new System.Windows.Forms.TextBox();\n            this.hideWaypointWithin = new System.Windows.Forms.CheckBox();\n            this.txtWaypointDistanceSec = new System.Windows.Forms.TextBox();\n            this.lblWaypointSeconds = new System.Windows.Forms.Label();\n            this.showWaypointDistance = new System.Windows.Forms.CheckBox();\n            this.showWaypointOverhead = new System.Windows.Forms.CheckBox();\n            this.btnRemoveSelectedWaypoint = new System.Windows.Forms.Button();\n            this.btnHideWaypoint = new System.Windows.Forms.Button();\n            this.btnUseCurrentLoc = new System.Windows.Forms.Button();\n            this.txtWaypointName = new System.Windows.Forms.TextBox();\n            this.lblWaypointY = new System.Windows.Forms.Label();\n            this.lblWaypointX = new System.Windows.Forms.Label();\n            this.txtWaypointX = new System.Windows.Forms.TextBox();\n            this.txtWaypointY = new System.Windows.Forms.TextBox();\n            this.lblWaypoint = new System.Windows.Forms.Label();\n            this.btnAddWaypoint = new System.Windows.Forms.Button();\n            this.waypointList = new System.Windows.Forms.ListBox();\n            this.subBuffsDebuffs = new System.Windows.Forms.TabPage();\n            this.buffBarGroupBox = new System.Windows.Forms.GroupBox();\n            this.showBuffDebuffTimeType = new System.Windows.Forms.ComboBox();\n            this.lblShowBuffTime = new System.Windows.Forms.Label();\n            this.useBlackBuffDebuffBg = new System.Windows.Forms.CheckBox();\n            this.buffBarHeight = new System.Windows.Forms.TextBox();\n            this.lblBuffBarHeight = new System.Windows.Forms.Label();\n            this.buffBarSort = new System.Windows.Forms.ComboBox();\n            this.lblBuffSortBy = new System.Windows.Forms.Label();\n            this.buffBarWidth = new System.Windows.Forms.TextBox();\n            this.lblBuffBarWidth = new System.Windows.Forms.Label();\n            this.showBuffIcons = new System.Windows.Forms.CheckBox();\n            this.showBuffDebuffGump = new System.Windows.Forms.CheckBox();\n            this.buffDebuffOptions = new System.Windows.Forms.Button();\n            this.showBuffDebuffOverhead = new System.Windows.Forms.CheckBox();\n            this.dressTab = new System.Windows.Forms.TabPage();\n            this.groupBox6 = new System.Windows.Forms.GroupBox();\n            this.clearDress = new System.Windows.Forms.Button();\n            this.dressDelSel = new System.Windows.Forms.Button();\n            this.undressBag = new System.Windows.Forms.Button();\n            this.undressList = new System.Windows.Forms.Button();\n            this.dressUseCur = new System.Windows.Forms.Button();\n            this.targItem = new System.Windows.Forms.Button();\n            this.dressItems = new System.Windows.Forms.ListBox();\n            this.dressNow = new System.Windows.Forms.Button();\n            this.groupBox5 = new System.Windows.Forms.GroupBox();\n            this.removeDress = new System.Windows.Forms.Button();\n            this.addDress = new System.Windows.Forms.Button();\n            this.dressList = new System.Windows.Forms.ListBox();\n            this.undressConflicts = new System.Windows.Forms.CheckBox();\n            this.skillsTab = new System.Windows.Forms.TabPage();\n            this.captureMibs = new System.Windows.Forms.CheckBox();\n            this.dispDeltaOverhead = new System.Windows.Forms.CheckBox();\n            this.logSkillChanges = new System.Windows.Forms.CheckBox();\n            this.dispDelta = new System.Windows.Forms.CheckBox();\n            this.skillCopyAll = new System.Windows.Forms.Button();\n            this.skillCopySel = new System.Windows.Forms.Button();\n            this.baseTotal = new System.Windows.Forms.TextBox();\n            this.label1 = new System.Windows.Forms.Label();\n            this.locks = new System.Windows.Forms.ComboBox();\n            this.setlocks = new System.Windows.Forms.Button();\n            this.resetDelta = new System.Windows.Forms.Button();\n            this.skillList = new System.Windows.Forms.ListView();\n            this.skillHDRName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.skillHDRvalue = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.skillHDRbase = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.skillHDRdelta = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.skillHDRcap = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.skillHDRlock = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));\n            this.agentsTab = new System.Windows.Forms.TabPage();\n            this.agentSetHotKey = new System.Windows.Forms.Button();\n            this.agentB6 = new System.Windows.Forms.Button();\n            this.agentB5 = new System.Windows.Forms.Button();\n            this.agentList = new System.Windows.Forms.ComboBox();\n            this.agentGroup = new System.Windows.Forms.GroupBox();\n            this.agentSubList = new System.Windows.Forms.ListBox();\n            this.agentB4 = new System.Windows.Forms.Button();\n            this.agentB1 = new System.Windows.Forms.Button();\n            this.agentB2 = new System.Windows.Forms.Button();\n            this.agentB3 = new System.Windows.Forms.Button();\n            this.filtersTab = new System.Windows.Forms.TabPage();\n            this.filterTabs = new System.Windows.Forms.TabControl();\n            this.subFilterTab = new System.Windows.Forms.TabPage();\n            this.wyrmAnimationList = new System.Windows.Forms.ComboBox();\n            this.filterWhiteWyrm = new System.Windows.Forms.CheckBox();\n            this.daemonAnimationList = new System.Windows.Forms.ComboBox();\n            this.filterDaemonGraphics = new System.Windows.Forms.CheckBox();\n            this.drakeAnimationList = new System.Windows.Forms.ComboBox();\n            this.filterDrakeGraphics = new System.Windows.Forms.CheckBox();\n            this.dragonAnimationList = new System.Windows.Forms.ComboBox();\n            this.filterDragonGraphics = new System.Windows.Forms.CheckBox();\n            this.filters = new System.Windows.Forms.CheckedListBox();\n            this.subFilterText = new System.Windows.Forms.TabPage();\n            this.gbFilterText = new System.Windows.Forms.GroupBox();\n            this.removeFilterText = new System.Windows.Forms.Button();\n            this.addFilterText = new System.Windows.Forms.Button();\n            this.textFilterList = new System.Windows.Forms.ListBox();\n            this.enableTextFilter = new System.Windows.Forms.CheckBox();\n            this.gbFilterMessages = new System.Windows.Forms.GroupBox();\n            this.filterOverheadMessages = new System.Windows.Forms.CheckBox();\n            this.lblFilterDelaySeconds = new System.Windows.Forms.Label();\n            this.lblFilterDelay = new System.Windows.Forms.Label();\n            this.filterDelaySeconds = new System.Windows.Forms.TextBox();\n            this.filterRazorMessages = new System.Windows.Forms.CheckBox();\n            this.filterSystemMessages = new System.Windows.Forms.CheckBox();\n            this.filterSnoop = new System.Windows.Forms.CheckBox();\n            this.subFilterSoundMusic = new System.Windows.Forms.TabPage();\n            this.playableMusicList = new System.Windows.Forms.ComboBox();\n            this.playMusic = new System.Windows.Forms.Button();\n            this.showPlayingMusic = new System.Windows.Forms.CheckBox();\n            this.showPlayingSoundInfo = new System.Windows.Forms.CheckBox();\n            this.showFilteredSound = new System.Windows.Forms.CheckBox();\n            this.playInClient = new System.Windows.Forms.CheckBox();\n            this.playSound = new System.Windows.Forms.Button();\n            this.soundFilterEnabled = new System.Windows.Forms.CheckBox();\n            this.soundFilterList = new System.Windows.Forms.CheckedListBox();\n            this.subFilterTargets = new System.Windows.Forms.TabPage();\n            this.lblTargetFilter = new System.Windows.Forms.Label();\n            this.targetFilterClear = new System.Windows.Forms.Button();\n            this.targetFilterRemove = new System.Windows.Forms.Button();\n            this.targetFilterAdd = new System.Windows.Forms.Button();\n            this.targetFilter = new System.Windows.Forms.ListBox();\n            this.targetFilterEnabled = new System.Windows.Forms.CheckBox();\n            this.hotkeysTab = new System.Windows.Forms.TabPage();\n            this.filterHotkeys = new System.Windows.Forms.TextBox();\n            this.label22 = new System.Windows.Forms.Label();\n            this.hkStatus = new System.Windows.Forms.Label();\n            this.hotkeyTree = new System.Windows.Forms.TreeView();\n            this.dohotkey = new System.Windows.Forms.Button();\n            this.groupBox8 = new System.Windows.Forms.GroupBox();\n            this.hkCommand = new System.Windows.Forms.TextBox();\n            this.hkCmdLabel = new System.Windows.Forms.Label();\n            this.chkAlt = new System.Windows.Forms.CheckBox();\n            this.chkPass = new System.Windows.Forms.CheckBox();\n            this.label2 = new System.Windows.Forms.Label();\n            this.unsetHK = new System.Windows.Forms.Button();\n            this.setHK = new System.Windows.Forms.Button();\n            this.hkKey = new System.Windows.Forms.TextBox();\n            this.chkCtrl = new System.Windows.Forms.CheckBox();\n            this.chkShift = new System.Windows.Forms.CheckBox();\n            this.macrosTab = new System.Windows.Forms.TabPage();\n            this.tabControl2 = new System.Windows.Forms.TabControl();\n            this.subMacrosTab = new System.Windows.Forms.TabPage();\n            this.macroActGroup = new System.Windows.Forms.GroupBox();\n            this.setMacroHotKey = new System.Windows.Forms.Button();\n            this.playMacro = new System.Windows.Forms.Button();\n            this.waitDisp = new System.Windows.Forms.Label();\n            this.loopMacro = new System.Windows.Forms.CheckBox();\n            this.recMacro = new System.Windows.Forms.Button();\n            this.actionList = new System.Windows.Forms.ListBox();\n            this.filterMacros = new System.Windows.Forms.TextBox();\n            this.filterLabel = new System.Windows.Forms.Label();\n            this.macroTree = new System.Windows.Forms.TreeView();\n            this.delMacro = new System.Windows.Forms.Button();\n            this.newMacro = new System.Windows.Forms.Button();\n            this.subMacrosOptionsTab = new System.Windows.Forms.TabPage();\n            this.disableMacroPlayFinish = new System.Windows.Forms.CheckBox();\n            this.macroActionDelay = new System.Windows.Forms.CheckBox();\n            this.rangeCheckDoubleClick = new System.Windows.Forms.CheckBox();\n            this.rangeCheckTargetByType = new System.Windows.Forms.CheckBox();\n            this.nextMacroAction = new System.Windows.Forms.Button();\n            this.stepThroughMacro = new System.Windows.Forms.CheckBox();\n            this.targetByTypeDifferent = new System.Windows.Forms.CheckBox();\n            this.macroVariableGroup = new System.Windows.Forms.GroupBox();\n            this.macroVariableTypeList = new System.Windows.Forms.ComboBox();\n            this.retargetMacroVariable = new System.Windows.Forms.Button();\n            this.insertMacroVariable = new System.Windows.Forms.Button();\n            this.removeMacroVariable = new System.Windows.Forms.Button();\n            this.addMacroVariable = new System.Windows.Forms.Button();\n            this.macroVariables = new System.Windows.Forms.ListBox();\n            this.scriptsTab = new System.Windows.Forms.TabPage();\n            this.subTabScripts = new System.Windows.Forms.TabControl();\n            this.subScripts = new System.Windows.Forms.TabPage();\n            this.scriptHotkey = new System.Windows.Forms.Label();\n            this.scriptSplitContainer = new System.Windows.Forms.SplitContainer();\n            this.scriptTree = new System.Windows.Forms.TreeView();\n            this.scriptFilter = new System.Windows.Forms.TextBox();\n            this.scriptDocMap = new FastColoredTextBoxNS.DocumentMap();\n            this.scriptEditor = new FastColoredTextBoxNS.FastColoredTextBox();\n            this.scriptGuide = new System.Windows.Forms.Button();\n            this.saveScript = new System.Windows.Forms.Button();\n            this.newScript = new System.Windows.Forms.Button();\n            this.setScriptHotkey = new System.Windows.Forms.Button();\n            this.recordScript = new System.Windows.Forms.Button();\n            this.playScript = new System.Windows.Forms.Button();\n            this.subScriptOptions = new System.Windows.Forms.TabPage();\n            this.disableScriptStopwatch = new System.Windows.Forms.CheckBox();\n            this.enableHighlight = new System.Windows.Forms.CheckBox();\n            this.defaultScriptDelay = new System.Windows.Forms.CheckBox();\n            this.disableScriptTooltips = new System.Windows.Forms.CheckBox();\n            this.scriptDisablePlayFinish = new System.Windows.Forms.CheckBox();\n            this.autoSaveScriptPlay = new System.Windows.Forms.CheckBox();\n            this.autoSaveScript = new System.Windows.Forms.CheckBox();\n            this.scriptVariablesBox = new System.Windows.Forms.GroupBox();\n            this.changeScriptVariable = new System.Windows.Forms.Button();\n            this.removeScriptVariable = new System.Windows.Forms.Button();\n            this.addScriptVariable = new System.Windows.Forms.Button();\n            this.scriptVariables = new System.Windows.Forms.ListBox();\n            this.friendsTab = new System.Windows.Forms.TabPage();\n            this.showPartyFriendOverhead = new System.Windows.Forms.CheckBox();\n            this.highlightFriend = new System.Windows.Forms.CheckBox();\n            this.autoAcceptParty = new System.Windows.Forms.CheckBox();\n            this.nextPrevIgnoresFriends = new System.Windows.Forms.CheckBox();\n            this.autoFriend = new System.Windows.Forms.CheckBox();\n            this.friendsGroupBox = new System.Windows.Forms.GroupBox();\n            this.showFriendOverhead = new System.Windows.Forms.CheckBox();\n            this.setFriendsFormatHue = new System.Windows.Forms.Button();\n            this.friendOverheadFormat = new System.Windows.Forms.TextBox();\n            this.friendFormat = new System.Windows.Forms.Label();\n            this.friendsGroupRemove = new System.Windows.Forms.Button();\n            this.friendsGroupAdd = new System.Windows.Forms.Button();\n            this.friendClearList = new System.Windows.Forms.Button();\n            this.friendRemoveSelected = new System.Windows.Forms.Button();\n            this.friendAddTarget = new System.Windows.Forms.Button();\n            this.friendsList = new System.Windows.Forms.ListBox();\n            this.friendsGroup = new System.Windows.Forms.ComboBox();\n            this.friendsListEnabled = new System.Windows.Forms.CheckBox();\n            this.screenshotTab = new System.Windows.Forms.TabPage();\n            this.openScreenshotFolder = new System.Windows.Forms.Button();\n            this.captureOwnDeathDelay = new System.Windows.Forms.TextBox();\n            this.lblOwnDeathMs = new System.Windows.Forms.Label();\n            this.captureOwnDeath = new System.Windows.Forms.CheckBox();\n            this.captureOthersDeathDelay = new System.Windows.Forms.TextBox();\n            this.lblCaptureOthersDeathMs = new System.Windows.Forms.Label();\n            this.imgFmt = new System.Windows.Forms.ComboBox();\n            this.label12 = new System.Windows.Forms.Label();\n            this.capNow = new System.Windows.Forms.Button();\n            this.screenPath = new System.Windows.Forms.TextBox();\n            this.radioUO = new System.Windows.Forms.RadioButton();\n            this.radioFull = new System.Windows.Forms.RadioButton();\n            this.captureOthersDeath = new System.Windows.Forms.CheckBox();\n            this.setScnPath = new System.Windows.Forms.Button();\n            this.screensList = new System.Windows.Forms.ListBox();\n            this.screenPrev = new System.Windows.Forms.PictureBox();\n            this.dispTime = new System.Windows.Forms.CheckBox();\n            this.advancedTab = new System.Windows.Forms.TabPage();\n            this.subAdvancedTab = new System.Windows.Forms.TabControl();\n            this.advancedInfoTab = new System.Windows.Forms.TabPage();\n            this.fontDecrease = new System.Windows.Forms.Button();\n            this.fontIncrease = new System.Windows.Forms.Button();\n            this.groupBox16 = new System.Windows.Forms.GroupBox();\n            this.lastBackup = new System.Windows.Forms.Label();\n            this.openBackupFolder = new System.Windows.Forms.Button();\n            this.setBackupFolder = new System.Windows.Forms.Button();\n            this.createBackup = new System.Windows.Forms.Button();\n            this.enableUOAAPI = new System.Windows.Forms.CheckBox();\n            this.disableSmartCPU = new System.Windows.Forms.Button();\n            this.negotiate = new System.Windows.Forms.CheckBox();\n            this.openRazorDataDir = new System.Windows.Forms.Button();\n            this.msglvl = new System.Windows.Forms.ComboBox();\n            this.label17 = new System.Windows.Forms.Label();\n            this.logPackets = new System.Windows.Forms.CheckBox();\n            this.statusBox = new System.Windows.Forms.TextBox();\n            this.features = new System.Windows.Forms.TextBox();\n            this.advancedStaffDeco = new System.Windows.Forms.TabPage();\n            this.itemAppendM = new System.Windows.Forms.CheckBox();\n            this.itemCopyToClipboard = new System.Windows.Forms.CheckBox();\n            this.itemSearch = new System.Windows.Forms.TextBox();\n            this.itemMovable = new System.Windows.Forms.CheckBox();\n            this.itemRandomNumber = new System.Windows.Forms.NumericUpDown();\n            this.itemRandom = new System.Windows.Forms.CheckBox();\n            this.itemTileCount = new System.Windows.Forms.NumericUpDown();\n            this.itemTile = new System.Windows.Forms.Button();\n            this.itemAdd = new System.Windows.Forms.Button();\n            this.itemTree = new System.Windows.Forms.TreeView();\n            this.advancedStaffDoors = new System.Windows.Forms.TabPage();\n            this.doorTree = new System.Windows.Forms.TreeView();\n            this.doorSouthCW = new System.Windows.Forms.Button();\n            this.doorSouthCCW = new System.Windows.Forms.Button();\n            this.doorEastCW = new System.Windows.Forms.Button();\n            this.doorEastCCW = new System.Windows.Forms.Button();\n            this.doorNorthCCW = new System.Windows.Forms.Button();\n            this.doorNorthCW = new System.Windows.Forms.Button();\n            this.doorWestCCW = new System.Windows.Forms.Button();\n            this.doorWestCW = new System.Windows.Forms.Button();\n            this.aboutTab = new System.Windows.Forms.TabPage();\n            this.linkGitHub = new System.Windows.Forms.LinkLabel();\n            this.lblCredits3 = new System.Windows.Forms.Label();\n            this.linkHelp = new System.Windows.Forms.LinkLabel();\n            this.lblCredits2 = new System.Windows.Forms.Label();\n            this.label20 = new System.Windows.Forms.Label();\n            this.lblCredits1 = new System.Windows.Forms.Label();\n            this.aboutSubInfo = new System.Windows.Forms.Label();\n            this.linkMain = new System.Windows.Forms.LinkLabel();\n            this.label21 = new System.Windows.Forms.Label();\n            this.aboutVer = new System.Windows.Forms.Label();\n            this.cooldownGumpBox = new System.Windows.Forms.GroupBox();\n            this.cooldownHeight = new System.Windows.Forms.TextBox();\n            this.lblCooldownHeight = new System.Windows.Forms.Label();\n            this.cooldownWidth = new System.Windows.Forms.TextBox();\n            this.lblCooldownWidth = new System.Windows.Forms.Label();\n            this.artViewer = new Assistant.UI.ArtViewer();\n            this.doorViewer = new Assistant.UI.ArtViewer();\n            this.tabs.SuspendLayout();\n            this.generalTab.SuspendLayout();\n            this.subGeneralTab.SuspendLayout();\n            this.subGenTab.SuspendLayout();\n            this.groupBox15.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.opacity)).BeginInit();\n            this.groupBox4.SuspendLayout();\n            this.moreOptTab.SuspendLayout();\n            this.optionsTabCtrl.SuspendLayout();\n            this.subOptionsSpeechTab.SuspendLayout();\n            this.subOptionsTargetTab.SuspendLayout();\n            this.groupSmartTarget.SuspendLayout();\n            this.subOptionsMiscTab.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.lightLevelBar)).BeginInit();\n            this.displayTab.SuspendLayout();\n            this.displayCountersTabCtrl.SuspendLayout();\n            this.subDisplayTab.SuspendLayout();\n            this.groupBox11.SuspendLayout();\n            this.groupBox3.SuspendLayout();\n            this.subCountersTab.SuspendLayout();\n            this.groupBox2.SuspendLayout();\n            this.subBandageTimerTab.SuspendLayout();\n            this.subOverheadTab.SuspendLayout();\n            this.subWaypoints.SuspendLayout();\n            this.subBuffsDebuffs.SuspendLayout();\n            this.buffBarGroupBox.SuspendLayout();\n            this.dressTab.SuspendLayout();\n            this.groupBox6.SuspendLayout();\n            this.groupBox5.SuspendLayout();\n            this.skillsTab.SuspendLayout();\n            this.agentsTab.SuspendLayout();\n            this.agentGroup.SuspendLayout();\n            this.filtersTab.SuspendLayout();\n            this.filterTabs.SuspendLayout();\n            this.subFilterTab.SuspendLayout();\n            this.subFilterText.SuspendLayout();\n            this.gbFilterText.SuspendLayout();\n            this.gbFilterMessages.SuspendLayout();\n            this.subFilterSoundMusic.SuspendLayout();\n            this.subFilterTargets.SuspendLayout();\n            this.hotkeysTab.SuspendLayout();\n            this.groupBox8.SuspendLayout();\n            this.macrosTab.SuspendLayout();\n            this.tabControl2.SuspendLayout();\n            this.subMacrosTab.SuspendLayout();\n            this.macroActGroup.SuspendLayout();\n            this.subMacrosOptionsTab.SuspendLayout();\n            this.macroVariableGroup.SuspendLayout();\n            this.scriptsTab.SuspendLayout();\n            this.subTabScripts.SuspendLayout();\n            this.subScripts.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.scriptSplitContainer)).BeginInit();\n            this.scriptSplitContainer.Panel1.SuspendLayout();\n            this.scriptSplitContainer.Panel2.SuspendLayout();\n            this.scriptSplitContainer.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.scriptEditor)).BeginInit();\n            this.subScriptOptions.SuspendLayout();\n            this.scriptVariablesBox.SuspendLayout();\n            this.friendsTab.SuspendLayout();\n            this.friendsGroupBox.SuspendLayout();\n            this.screenshotTab.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.screenPrev)).BeginInit();\n            this.advancedTab.SuspendLayout();\n            this.subAdvancedTab.SuspendLayout();\n            this.advancedInfoTab.SuspendLayout();\n            this.groupBox16.SuspendLayout();\n            this.advancedStaffDeco.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.itemRandomNumber)).BeginInit();\n            ((System.ComponentModel.ISupportInitialize)(this.itemTileCount)).BeginInit();\n            this.advancedStaffDoors.SuspendLayout();\n            this.aboutTab.SuspendLayout();\n            this.cooldownGumpBox.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // m_NotifyIcon\n            // \n            this.m_NotifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject(\"m_NotifyIcon.Icon\")));\n            this.m_NotifyIcon.Text = \"Razor\";\n            this.m_NotifyIcon.DoubleClick += new System.EventHandler(this.NotifyIcon_DoubleClick);\n            // \n            // tabs\n            // \n            this.tabs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.tabs.Controls.Add(this.generalTab);\n            this.tabs.Controls.Add(this.moreOptTab);\n            this.tabs.Controls.Add(this.displayTab);\n            this.tabs.Controls.Add(this.dressTab);\n            this.tabs.Controls.Add(this.skillsTab);\n            this.tabs.Controls.Add(this.agentsTab);\n            this.tabs.Controls.Add(this.filtersTab);\n            this.tabs.Controls.Add(this.hotkeysTab);\n            this.tabs.Controls.Add(this.macrosTab);\n            this.tabs.Controls.Add(this.scriptsTab);\n            this.tabs.Controls.Add(this.friendsTab);\n            this.tabs.Controls.Add(this.screenshotTab);\n            this.tabs.Controls.Add(this.advancedTab);\n            this.tabs.Controls.Add(this.aboutTab);\n            this.tabs.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.tabs.Location = new System.Drawing.Point(2, 0);\n            this.tabs.Multiline = true;\n            this.tabs.Name = \"tabs\";\n            this.tabs.SelectedIndex = 0;\n            this.tabs.Size = new System.Drawing.Size(527, 370);\n            this.tabs.SizeMode = System.Windows.Forms.TabSizeMode.FillToRight;\n            this.tabs.TabIndex = 0;\n            this.tabs.SelectedIndexChanged += new System.EventHandler(this.tabs_IndexChanged);\n            this.tabs.KeyDown += new System.Windows.Forms.KeyEventHandler(this.tabs_KeyDown);\n            // \n            // generalTab\n            // \n            this.generalTab.Controls.Add(this.subGeneralTab);\n            this.generalTab.Location = new System.Drawing.Point(4, 44);\n            this.generalTab.Name = \"generalTab\";\n            this.generalTab.Size = new System.Drawing.Size(519, 322);\n            this.generalTab.TabIndex = 0;\n            this.generalTab.Text = \"General\";\n            // \n            // subGeneralTab\n            // \n            this.subGeneralTab.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.subGeneralTab.Controls.Add(this.subGenTab);\n            this.subGeneralTab.Location = new System.Drawing.Point(6, 3);\n            this.subGeneralTab.Name = \"subGeneralTab\";\n            this.subGeneralTab.SelectedIndex = 0;\n            this.subGeneralTab.Size = new System.Drawing.Size(510, 314);\n            this.subGeneralTab.TabIndex = 63;\n            this.subGeneralTab.SelectedIndexChanged += new System.EventHandler(this.subGeneralTab_IndexChanged);\n            // \n            // subGenTab\n            // \n            this.subGenTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subGenTab.Controls.Add(this.groupBox15);\n            this.subGenTab.Controls.Add(this.systray);\n            this.subGenTab.Controls.Add(this.taskbar);\n            this.subGenTab.Controls.Add(this.langSel);\n            this.subGenTab.Controls.Add(this.label7);\n            this.subGenTab.Controls.Add(this.label11);\n            this.subGenTab.Controls.Add(this.showWelcome);\n            this.subGenTab.Controls.Add(this.opacity);\n            this.subGenTab.Controls.Add(this.alwaysTop);\n            this.subGenTab.Controls.Add(this.opacityLabel);\n            this.subGenTab.Controls.Add(this.groupBox4);\n            this.subGenTab.Location = new System.Drawing.Point(4, 24);\n            this.subGenTab.Name = \"subGenTab\";\n            this.subGenTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subGenTab.Size = new System.Drawing.Size(502, 286);\n            this.subGenTab.TabIndex = 0;\n            this.subGenTab.Text = \"General\";\n            // \n            // groupBox15\n            // \n            this.groupBox15.Controls.Add(this.boatControl);\n            this.groupBox15.Controls.Add(this.btnMap);\n            this.groupBox15.Location = new System.Drawing.Point(14, 232);\n            this.groupBox15.Name = \"groupBox15\";\n            this.groupBox15.Size = new System.Drawing.Size(223, 48);\n            this.groupBox15.TabIndex = 77;\n            this.groupBox15.TabStop = false;\n            this.groupBox15.Text = \"Map / Boat\";\n            // \n            // boatControl\n            // \n            this.boatControl.Location = new System.Drawing.Point(119, 16);\n            this.boatControl.Name = \"boatControl\";\n            this.boatControl.Size = new System.Drawing.Size(96, 26);\n            this.boatControl.TabIndex = 70;\n            this.boatControl.Text = \"Boat Control\";\n            this.boatControl.UseVisualStyleBackColor = true;\n            this.boatControl.Click += new System.EventHandler(this.boatControl_Click);\n            // \n            // btnMap\n            // \n            this.btnMap.Location = new System.Drawing.Point(6, 16);\n            this.btnMap.Name = \"btnMap\";\n            this.btnMap.Size = new System.Drawing.Size(107, 26);\n            this.btnMap.TabIndex = 67;\n            this.btnMap.Text = \"UOPS\";\n            this.btnMap.Click += new System.EventHandler(this.btnMap_Click);\n            // \n            // systray\n            // \n            this.systray.Location = new System.Drawing.Point(164, 118);\n            this.systray.Name = \"systray\";\n            this.systray.Size = new System.Drawing.Size(88, 23);\n            this.systray.TabIndex = 69;\n            this.systray.Text = \"System Tray\";\n            this.systray.CheckedChanged += new System.EventHandler(this.systray_CheckedChanged);\n            // \n            // taskbar\n            // \n            this.taskbar.Location = new System.Drawing.Point(92, 118);\n            this.taskbar.Name = \"taskbar\";\n            this.taskbar.Size = new System.Drawing.Size(79, 23);\n            this.taskbar.TabIndex = 68;\n            this.taskbar.Text = \"Taskbar\";\n            this.taskbar.CheckedChanged += new System.EventHandler(this.taskbar_CheckedChanged);\n            // \n            // langSel\n            // \n            this.langSel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.langSel.Location = new System.Drawing.Point(341, 169);\n            this.langSel.Name = \"langSel\";\n            this.langSel.Size = new System.Drawing.Size(136, 23);\n            this.langSel.TabIndex = 71;\n            this.langSel.SelectedIndexChanged += new System.EventHandler(this.langSel_SelectedIndexChanged);\n            // \n            // label7\n            // \n            this.label7.Location = new System.Drawing.Point(267, 172);\n            this.label7.Name = \"label7\";\n            this.label7.Size = new System.Drawing.Size(68, 18);\n            this.label7.TabIndex = 70;\n            this.label7.Text = \"Language:\";\n            // \n            // label11\n            // \n            this.label11.Location = new System.Drawing.Point(11, 122);\n            this.label11.Name = \"label11\";\n            this.label11.Size = new System.Drawing.Size(54, 16);\n            this.label11.TabIndex = 67;\n            this.label11.Text = \"Show in:\";\n            // \n            // showWelcome\n            // \n            this.showWelcome.Location = new System.Drawing.Point(270, 107);\n            this.showWelcome.Name = \"showWelcome\";\n            this.showWelcome.Size = new System.Drawing.Size(152, 23);\n            this.showWelcome.TabIndex = 66;\n            this.showWelcome.Text = \"Show Welcome Screen\";\n            this.showWelcome.CheckedChanged += new System.EventHandler(this.showWelcome_CheckedChanged);\n            // \n            // opacity\n            // \n            this.opacity.AutoSize = false;\n            this.opacity.Cursor = System.Windows.Forms.Cursors.SizeWE;\n            this.opacity.Location = new System.Drawing.Point(97, 150);\n            this.opacity.Maximum = 100;\n            this.opacity.Minimum = 10;\n            this.opacity.Name = \"opacity\";\n            this.opacity.Size = new System.Drawing.Size(155, 21);\n            this.opacity.TabIndex = 64;\n            this.opacity.TickFrequency = 0;\n            this.opacity.TickStyle = System.Windows.Forms.TickStyle.None;\n            this.opacity.Value = 100;\n            this.opacity.Scroll += new System.EventHandler(this.opacity_Scroll);\n            // \n            // alwaysTop\n            // \n            this.alwaysTop.Location = new System.Drawing.Point(270, 136);\n            this.alwaysTop.Name = \"alwaysTop\";\n            this.alwaysTop.Size = new System.Drawing.Size(162, 23);\n            this.alwaysTop.TabIndex = 63;\n            this.alwaysTop.Text = \"Use Smart Always on Top\";\n            this.alwaysTop.CheckedChanged += new System.EventHandler(this.alwaysTop_CheckedChanged);\n            // \n            // opacityLabel\n            // \n            this.opacityLabel.Location = new System.Drawing.Point(11, 152);\n            this.opacityLabel.Name = \"opacityLabel\";\n            this.opacityLabel.Size = new System.Drawing.Size(58, 19);\n            this.opacityLabel.TabIndex = 65;\n            this.opacityLabel.Text = \"Opacity: 100%\";\n            // \n            // groupBox4\n            // \n            this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.groupBox4.Controls.Add(this.saveProfile);\n            this.groupBox4.Controls.Add(this.cloneProfile);\n            this.groupBox4.Controls.Add(this.delProfile);\n            this.groupBox4.Controls.Add(this.newProfile);\n            this.groupBox4.Controls.Add(this.profiles);\n            this.groupBox4.Location = new System.Drawing.Point(6, 6);\n            this.groupBox4.Name = \"groupBox4\";\n            this.groupBox4.Size = new System.Drawing.Size(490, 95);\n            this.groupBox4.TabIndex = 5;\n            this.groupBox4.TabStop = false;\n            this.groupBox4.Text = \"Profiles\";\n            // \n            // saveProfile\n            // \n            this.saveProfile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.saveProfile.AutoSize = true;\n            this.saveProfile.Location = new System.Drawing.Point(320, 56);\n            this.saveProfile.Name = \"saveProfile\";\n            this.saveProfile.Size = new System.Drawing.Size(50, 30);\n            this.saveProfile.TabIndex = 4;\n            this.saveProfile.Text = \"Save\";\n            this.saveProfile.Click += new System.EventHandler(this.saveProfile_Click);\n            // \n            // cloneProfile\n            // \n            this.cloneProfile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.cloneProfile.AutoSize = true;\n            this.cloneProfile.Location = new System.Drawing.Point(376, 56);\n            this.cloneProfile.Name = \"cloneProfile\";\n            this.cloneProfile.Size = new System.Drawing.Size(50, 30);\n            this.cloneProfile.TabIndex = 3;\n            this.cloneProfile.Text = \"Clone\";\n            this.cloneProfile.Click += new System.EventHandler(this.cloneProfile_Click);\n            // \n            // delProfile\n            // \n            this.delProfile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.delProfile.AutoSize = true;\n            this.delProfile.Location = new System.Drawing.Point(432, 56);\n            this.delProfile.Name = \"delProfile\";\n            this.delProfile.Size = new System.Drawing.Size(50, 30);\n            this.delProfile.TabIndex = 2;\n            this.delProfile.Text = \"Delete\";\n            this.delProfile.Click += new System.EventHandler(this.delProfile_Click);\n            // \n            // newProfile\n            // \n            this.newProfile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.newProfile.AutoSize = true;\n            this.newProfile.Location = new System.Drawing.Point(264, 56);\n            this.newProfile.Name = \"newProfile\";\n            this.newProfile.Size = new System.Drawing.Size(50, 30);\n            this.newProfile.TabIndex = 1;\n            this.newProfile.Text = \"New\";\n            this.newProfile.Click += new System.EventHandler(this.newProfile_Click);\n            // \n            // profiles\n            // \n            this.profiles.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.profiles.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.profiles.Font = new System.Drawing.Font(\"Segoe UI\", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.profiles.ItemHeight = 20;\n            this.profiles.Location = new System.Drawing.Point(6, 22);\n            this.profiles.MaxDropDownItems = 5;\n            this.profiles.Name = \"profiles\";\n            this.profiles.Size = new System.Drawing.Size(476, 28);\n            this.profiles.TabIndex = 0;\n            this.profiles.SelectedIndexChanged += new System.EventHandler(this.profiles_SelectedIndexChanged);\n            // \n            // moreOptTab\n            // \n            this.moreOptTab.Controls.Add(this.optionsTabCtrl);\n            this.moreOptTab.Location = new System.Drawing.Point(4, 24);\n            this.moreOptTab.Name = \"moreOptTab\";\n            this.moreOptTab.Size = new System.Drawing.Size(519, 342);\n            this.moreOptTab.TabIndex = 5;\n            this.moreOptTab.Text = \"Options\";\n            // \n            // optionsTabCtrl\n            // \n            this.optionsTabCtrl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.optionsTabCtrl.Controls.Add(this.subOptionsSpeechTab);\n            this.optionsTabCtrl.Controls.Add(this.subOptionsTargetTab);\n            this.optionsTabCtrl.Controls.Add(this.subOptionsMiscTab);\n            this.optionsTabCtrl.Location = new System.Drawing.Point(6, 3);\n            this.optionsTabCtrl.Name = \"optionsTabCtrl\";\n            this.optionsTabCtrl.SelectedIndex = 0;\n            this.optionsTabCtrl.Size = new System.Drawing.Size(510, 334);\n            this.optionsTabCtrl.TabIndex = 93;\n            // \n            // subOptionsSpeechTab\n            // \n            this.subOptionsSpeechTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subOptionsSpeechTab.Controls.Add(this.playEmoteSound);\n            this.subOptionsSpeechTab.Controls.Add(this.overrideSpellFormat);\n            this.subOptionsSpeechTab.Controls.Add(this.damageTakenOverhead);\n            this.subOptionsSpeechTab.Controls.Add(this.showDamageTaken);\n            this.subOptionsSpeechTab.Controls.Add(this.damageDealtOverhead);\n            this.subOptionsSpeechTab.Controls.Add(this.showDamageDealt);\n            this.subOptionsSpeechTab.Controls.Add(this.healthFmt);\n            this.subOptionsSpeechTab.Controls.Add(this.label10);\n            this.subOptionsSpeechTab.Controls.Add(this.showHealthOH);\n            this.subOptionsSpeechTab.Controls.Add(this.chkPartyOverhead);\n            this.subOptionsSpeechTab.Controls.Add(this.containerLabels);\n            this.subOptionsSpeechTab.Controls.Add(this.showContainerLabels);\n            this.subOptionsSpeechTab.Controls.Add(this.incomingMob);\n            this.subOptionsSpeechTab.Controls.Add(this.incomingCorpse);\n            this.subOptionsSpeechTab.Controls.Add(this.setLTHilight);\n            this.subOptionsSpeechTab.Controls.Add(this.lthilight);\n            this.subOptionsSpeechTab.Controls.Add(this.setHarmHue);\n            this.subOptionsSpeechTab.Controls.Add(this.setNeuHue);\n            this.subOptionsSpeechTab.Controls.Add(this.lblHarmHue);\n            this.subOptionsSpeechTab.Controls.Add(this.lblNeuHue);\n            this.subOptionsSpeechTab.Controls.Add(this.lblBeneHue);\n            this.subOptionsSpeechTab.Controls.Add(this.setBeneHue);\n            this.subOptionsSpeechTab.Controls.Add(this.setSpeechHue);\n            this.subOptionsSpeechTab.Controls.Add(this.setWarnHue);\n            this.subOptionsSpeechTab.Controls.Add(this.setMsgHue);\n            this.subOptionsSpeechTab.Controls.Add(this.setExHue);\n            this.subOptionsSpeechTab.Controls.Add(this.lblWarnHue);\n            this.subOptionsSpeechTab.Controls.Add(this.lblMsgHue);\n            this.subOptionsSpeechTab.Controls.Add(this.lblExHue);\n            this.subOptionsSpeechTab.Controls.Add(this.txtSpellFormat);\n            this.subOptionsSpeechTab.Controls.Add(this.chkForceSpellHue);\n            this.subOptionsSpeechTab.Controls.Add(this.chkForceSpeechHue);\n            this.subOptionsSpeechTab.Controls.Add(this.label3);\n            this.subOptionsSpeechTab.Location = new System.Drawing.Point(4, 24);\n            this.subOptionsSpeechTab.Name = \"subOptionsSpeechTab\";\n            this.subOptionsSpeechTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subOptionsSpeechTab.Size = new System.Drawing.Size(502, 306);\n            this.subOptionsSpeechTab.TabIndex = 0;\n            this.subOptionsSpeechTab.Text = \"Speech & Messages  \";\n            // \n            // playEmoteSound\n            // \n            this.playEmoteSound.AutoSize = true;\n            this.playEmoteSound.Location = new System.Drawing.Point(260, 210);\n            this.playEmoteSound.Name = \"playEmoteSound\";\n            this.playEmoteSound.Size = new System.Drawing.Size(136, 19);\n            this.playEmoteSound.TabIndex = 131;\n            this.playEmoteSound.Text = \"Play *emote* sounds\";\n            this.playEmoteSound.UseVisualStyleBackColor = true;\n            this.playEmoteSound.CheckedChanged += new System.EventHandler(this.playEmoteSound_CheckedChanged);\n            // \n            // overrideSpellFormat\n            // \n            this.overrideSpellFormat.Location = new System.Drawing.Point(9, 205);\n            this.overrideSpellFormat.Name = \"overrideSpellFormat\";\n            this.overrideSpellFormat.Size = new System.Drawing.Size(152, 20);\n            this.overrideSpellFormat.TabIndex = 130;\n            this.overrideSpellFormat.Text = \"Override spell format\";\n            this.overrideSpellFormat.CheckedChanged += new System.EventHandler(this.overrideSpellFormat_CheckedChanged);\n            // \n            // damageTakenOverhead\n            // \n            this.damageTakenOverhead.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.damageTakenOverhead.Location = new System.Drawing.Point(394, 185);\n            this.damageTakenOverhead.Name = \"damageTakenOverhead\";\n            this.damageTakenOverhead.Size = new System.Drawing.Size(77, 19);\n            this.damageTakenOverhead.TabIndex = 128;\n            this.damageTakenOverhead.Text = \"Overhead\";\n            this.damageTakenOverhead.UseVisualStyleBackColor = true;\n            this.damageTakenOverhead.CheckedChanged += new System.EventHandler(this.damageTakenOverhead_CheckedChanged);\n            // \n            // showDamageTaken\n            // \n            this.showDamageTaken.Font = new System.Drawing.Font(\"Segoe UI\", 9F);\n            this.showDamageTaken.Location = new System.Drawing.Point(260, 185);\n            this.showDamageTaken.Name = \"showDamageTaken\";\n            this.showDamageTaken.Size = new System.Drawing.Size(139, 19);\n            this.showDamageTaken.TabIndex = 127;\n            this.showDamageTaken.Text = \"Show damage taken\";\n            this.showDamageTaken.UseVisualStyleBackColor = true;\n            this.showDamageTaken.CheckedChanged += new System.EventHandler(this.showDamageTaken_CheckedChanged);\n            // \n            // damageDealtOverhead\n            // \n            this.damageDealtOverhead.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.damageDealtOverhead.Location = new System.Drawing.Point(394, 160);\n            this.damageDealtOverhead.Name = \"damageDealtOverhead\";\n            this.damageDealtOverhead.Size = new System.Drawing.Size(77, 19);\n            this.damageDealtOverhead.TabIndex = 126;\n            this.damageDealtOverhead.Text = \"Overhead\";\n            this.damageDealtOverhead.UseVisualStyleBackColor = true;\n            this.damageDealtOverhead.CheckedChanged += new System.EventHandler(this.damageDealtOverhead_CheckedChanged);\n            // \n            // showDamageDealt\n            // \n            this.showDamageDealt.AutoSize = true;\n            this.showDamageDealt.Location = new System.Drawing.Point(260, 160);\n            this.showDamageDealt.Name = \"showDamageDealt\";\n            this.showDamageDealt.Size = new System.Drawing.Size(130, 19);\n            this.showDamageDealt.TabIndex = 125;\n            this.showDamageDealt.Text = \"Show damage dealt\";\n            this.showDamageDealt.UseVisualStyleBackColor = true;\n            this.showDamageDealt.CheckedChanged += new System.EventHandler(this.showDamageDealt_CheckedChanged);\n            // \n            // healthFmt\n            // \n            this.healthFmt.Location = new System.Drawing.Point(377, 110);\n            this.healthFmt.Name = \"healthFmt\";\n            this.healthFmt.Size = new System.Drawing.Size(53, 23);\n            this.healthFmt.TabIndex = 89;\n            this.healthFmt.Text = \"[{0}%]\";\n            this.healthFmt.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.healthFmt.TextChanged += new System.EventHandler(this.healthFmt_TextChanged);\n            // \n            // label10\n            // \n            this.label10.Location = new System.Drawing.Point(283, 111);\n            this.label10.Name = \"label10\";\n            this.label10.Size = new System.Drawing.Size(115, 18);\n            this.label10.TabIndex = 88;\n            this.label10.Text = \"Health Format:\";\n            this.label10.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // showHealthOH\n            // \n            this.showHealthOH.Location = new System.Drawing.Point(260, 88);\n            this.showHealthOH.Name = \"showHealthOH\";\n            this.showHealthOH.Size = new System.Drawing.Size(231, 20);\n            this.showHealthOH.TabIndex = 87;\n            this.showHealthOH.Text = \"Show health above people/creatures\";\n            this.showHealthOH.CheckedChanged += new System.EventHandler(this.showHealthOH_CheckedChanged);\n            // \n            // chkPartyOverhead\n            // \n            this.chkPartyOverhead.Location = new System.Drawing.Point(260, 134);\n            this.chkPartyOverhead.Name = \"chkPartyOverhead\";\n            this.chkPartyOverhead.Size = new System.Drawing.Size(238, 20);\n            this.chkPartyOverhead.TabIndex = 90;\n            this.chkPartyOverhead.Text = \"Show mana/stam above party members\";\n            this.chkPartyOverhead.CheckedChanged += new System.EventHandler(this.chkPartyOverhead_CheckedChanged);\n            // \n            // containerLabels\n            // \n            this.containerLabels.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.containerLabels.Location = new System.Drawing.Point(438, 63);\n            this.containerLabels.Name = \"containerLabels\";\n            this.containerLabels.Size = new System.Drawing.Size(33, 19);\n            this.containerLabels.TabIndex = 86;\n            this.containerLabels.Text = \"...\";\n            this.containerLabels.UseVisualStyleBackColor = true;\n            this.containerLabels.Click += new System.EventHandler(this.containerLabels_Click);\n            // \n            // showContainerLabels\n            // \n            this.showContainerLabels.AutoSize = true;\n            this.showContainerLabels.Location = new System.Drawing.Point(260, 63);\n            this.showContainerLabels.Name = \"showContainerLabels\";\n            this.showContainerLabels.Size = new System.Drawing.Size(141, 19);\n            this.showContainerLabels.TabIndex = 85;\n            this.showContainerLabels.Text = \"Show container labels\";\n            this.showContainerLabels.UseVisualStyleBackColor = true;\n            this.showContainerLabels.CheckedChanged += new System.EventHandler(this.showContainerLabels_CheckedChanged);\n            // \n            // incomingMob\n            // \n            this.incomingMob.Location = new System.Drawing.Point(260, 10);\n            this.incomingMob.Name = \"incomingMob\";\n            this.incomingMob.Size = new System.Drawing.Size(211, 20);\n            this.incomingMob.TabIndex = 71;\n            this.incomingMob.Text = \"Show Names of Incoming People/Creatures\";\n            this.incomingMob.CheckedChanged += new System.EventHandler(this.incomingMob_CheckedChanged);\n            // \n            // incomingCorpse\n            // \n            this.incomingCorpse.Location = new System.Drawing.Point(260, 36);\n            this.incomingCorpse.Name = \"incomingCorpse\";\n            this.incomingCorpse.Size = new System.Drawing.Size(238, 20);\n            this.incomingCorpse.TabIndex = 72;\n            this.incomingCorpse.Text = \"Show Names of New/Incoming Corpses\";\n            this.incomingCorpse.CheckedChanged += new System.EventHandler(this.incomingCorpse_CheckedChanged);\n            // \n            // setLTHilight\n            // \n            this.setLTHilight.Location = new System.Drawing.Point(168, 116);\n            this.setLTHilight.Name = \"setLTHilight\";\n            this.setLTHilight.Size = new System.Drawing.Size(47, 20);\n            this.setLTHilight.TabIndex = 70;\n            this.setLTHilight.Text = \"Set\";\n            this.setLTHilight.Click += new System.EventHandler(this.setLTHilight_Click);\n            // \n            // lthilight\n            // \n            this.lthilight.Location = new System.Drawing.Point(9, 116);\n            this.lthilight.Name = \"lthilight\";\n            this.lthilight.Size = new System.Drawing.Size(206, 19);\n            this.lthilight.TabIndex = 69;\n            this.lthilight.Text = \"Last Target Highlight:\";\n            this.lthilight.CheckedChanged += new System.EventHandler(this.lthilight_CheckedChanged);\n            // \n            // setHarmHue\n            // \n            this.setHarmHue.Enabled = false;\n            this.setHarmHue.Location = new System.Drawing.Point(99, 179);\n            this.setHarmHue.Name = \"setHarmHue\";\n            this.setHarmHue.Size = new System.Drawing.Size(32, 20);\n            this.setHarmHue.TabIndex = 64;\n            this.setHarmHue.Text = \"Set\";\n            this.setHarmHue.Click += new System.EventHandler(this.setHarmHue_Click);\n            // \n            // setNeuHue\n            // \n            this.setNeuHue.Enabled = false;\n            this.setNeuHue.Location = new System.Drawing.Point(172, 179);\n            this.setNeuHue.Name = \"setNeuHue\";\n            this.setNeuHue.Size = new System.Drawing.Size(32, 20);\n            this.setNeuHue.TabIndex = 65;\n            this.setNeuHue.Text = \"Set\";\n            this.setNeuHue.Click += new System.EventHandler(this.setNeuHue_Click);\n            // \n            // lblHarmHue\n            // \n            this.lblHarmHue.Location = new System.Drawing.Point(86, 165);\n            this.lblHarmHue.Name = \"lblHarmHue\";\n            this.lblHarmHue.Size = new System.Drawing.Size(59, 14);\n            this.lblHarmHue.TabIndex = 68;\n            this.lblHarmHue.Text = \"Harmful\";\n            this.lblHarmHue.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // lblNeuHue\n            // \n            this.lblNeuHue.Location = new System.Drawing.Point(163, 165);\n            this.lblNeuHue.Name = \"lblNeuHue\";\n            this.lblNeuHue.Size = new System.Drawing.Size(52, 14);\n            this.lblNeuHue.TabIndex = 67;\n            this.lblNeuHue.Text = \"Neutral\";\n            this.lblNeuHue.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // lblBeneHue\n            // \n            this.lblBeneHue.Location = new System.Drawing.Point(9, 165);\n            this.lblBeneHue.Name = \"lblBeneHue\";\n            this.lblBeneHue.Size = new System.Drawing.Size(66, 14);\n            this.lblBeneHue.TabIndex = 66;\n            this.lblBeneHue.Text = \"Beneficial\";\n            this.lblBeneHue.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // setBeneHue\n            // \n            this.setBeneHue.Enabled = false;\n            this.setBeneHue.Location = new System.Drawing.Point(27, 179);\n            this.setBeneHue.Name = \"setBeneHue\";\n            this.setBeneHue.Size = new System.Drawing.Size(32, 20);\n            this.setBeneHue.TabIndex = 63;\n            this.setBeneHue.Text = \"Set\";\n            this.setBeneHue.Click += new System.EventHandler(this.setBeneHue_Click);\n            // \n            // setSpeechHue\n            // \n            this.setSpeechHue.Location = new System.Drawing.Point(168, 90);\n            this.setSpeechHue.Name = \"setSpeechHue\";\n            this.setSpeechHue.Size = new System.Drawing.Size(47, 20);\n            this.setSpeechHue.TabIndex = 62;\n            this.setSpeechHue.Text = \"Set\";\n            this.setSpeechHue.Click += new System.EventHandler(this.setSpeechHue_Click);\n            // \n            // setWarnHue\n            // \n            this.setWarnHue.Location = new System.Drawing.Point(168, 64);\n            this.setWarnHue.Name = \"setWarnHue\";\n            this.setWarnHue.Size = new System.Drawing.Size(47, 20);\n            this.setWarnHue.TabIndex = 61;\n            this.setWarnHue.Text = \"Set\";\n            this.setWarnHue.Click += new System.EventHandler(this.setWarnHue_Click);\n            // \n            // setMsgHue\n            // \n            this.setMsgHue.Location = new System.Drawing.Point(168, 38);\n            this.setMsgHue.Name = \"setMsgHue\";\n            this.setMsgHue.Size = new System.Drawing.Size(47, 20);\n            this.setMsgHue.TabIndex = 60;\n            this.setMsgHue.Text = \"Set\";\n            this.setMsgHue.Click += new System.EventHandler(this.setMsgHue_Click);\n            // \n            // setExHue\n            // \n            this.setExHue.Location = new System.Drawing.Point(168, 12);\n            this.setExHue.Name = \"setExHue\";\n            this.setExHue.Size = new System.Drawing.Size(47, 20);\n            this.setExHue.TabIndex = 59;\n            this.setExHue.Text = \"Set\";\n            this.setExHue.Click += new System.EventHandler(this.setExHue_Click);\n            // \n            // lblWarnHue\n            // \n            this.lblWarnHue.Location = new System.Drawing.Point(9, 64);\n            this.lblWarnHue.Name = \"lblWarnHue\";\n            this.lblWarnHue.Size = new System.Drawing.Size(206, 18);\n            this.lblWarnHue.TabIndex = 58;\n            this.lblWarnHue.Text = \"Warning Message Hue:\";\n            // \n            // lblMsgHue\n            // \n            this.lblMsgHue.Location = new System.Drawing.Point(9, 38);\n            this.lblMsgHue.Name = \"lblMsgHue\";\n            this.lblMsgHue.Size = new System.Drawing.Size(206, 18);\n            this.lblMsgHue.TabIndex = 57;\n            this.lblMsgHue.Text = \"Razor Message Hue:\";\n            // \n            // lblExHue\n            // \n            this.lblExHue.Location = new System.Drawing.Point(9, 12);\n            this.lblExHue.Name = \"lblExHue\";\n            this.lblExHue.Size = new System.Drawing.Size(206, 18);\n            this.lblExHue.TabIndex = 56;\n            this.lblExHue.Text = \"Search Exemption Hue:\";\n            // \n            // txtSpellFormat\n            // \n            this.txtSpellFormat.Location = new System.Drawing.Point(89, 228);\n            this.txtSpellFormat.Name = \"txtSpellFormat\";\n            this.txtSpellFormat.Size = new System.Drawing.Size(126, 23);\n            this.txtSpellFormat.TabIndex = 55;\n            this.txtSpellFormat.TextChanged += new System.EventHandler(this.txtSpellFormat_TextChanged);\n            // \n            // chkForceSpellHue\n            // \n            this.chkForceSpellHue.Location = new System.Drawing.Point(9, 142);\n            this.chkForceSpellHue.Name = \"chkForceSpellHue\";\n            this.chkForceSpellHue.Size = new System.Drawing.Size(152, 20);\n            this.chkForceSpellHue.TabIndex = 53;\n            this.chkForceSpellHue.Text = \"Override Spell Hues:\";\n            this.chkForceSpellHue.CheckedChanged += new System.EventHandler(this.chkForceSpellHue_CheckedChanged);\n            // \n            // chkForceSpeechHue\n            // \n            this.chkForceSpeechHue.Location = new System.Drawing.Point(9, 90);\n            this.chkForceSpeechHue.Name = \"chkForceSpeechHue\";\n            this.chkForceSpeechHue.Size = new System.Drawing.Size(206, 19);\n            this.chkForceSpeechHue.TabIndex = 52;\n            this.chkForceSpeechHue.Text = \"Override Speech Hue:\";\n            this.chkForceSpeechHue.CheckedChanged += new System.EventHandler(this.chkForceSpeechHue_CheckedChanged);\n            // \n            // label3\n            // \n            this.label3.Location = new System.Drawing.Point(11, 228);\n            this.label3.Name = \"label3\";\n            this.label3.Size = new System.Drawing.Size(87, 20);\n            this.label3.TabIndex = 54;\n            this.label3.Text = \"Spell Format:\";\n            this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // subOptionsTargetTab\n            // \n            this.subOptionsTargetTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subOptionsTargetTab.Controls.Add(this.groupSmartTarget);\n            this.subOptionsTargetTab.Controls.Add(this.setTargetIndicatorHue);\n            this.subOptionsTargetTab.Controls.Add(this.targetIndicatorFormat);\n            this.subOptionsTargetTab.Controls.Add(this.showtargtext);\n            this.subOptionsTargetTab.Controls.Add(this.showAttackTargetNewOnly);\n            this.subOptionsTargetTab.Controls.Add(this.showTextTargetIndicator);\n            this.subOptionsTargetTab.Controls.Add(this.showAttackTarget);\n            this.subOptionsTargetTab.Controls.Add(this.showTargetMessagesOverChar);\n            this.subOptionsTargetTab.Controls.Add(this.txtObjDelay);\n            this.subOptionsTargetTab.Controls.Add(this.objectDelay);\n            this.subOptionsTargetTab.Controls.Add(this.ltRange);\n            this.subOptionsTargetTab.Controls.Add(this.QueueActions);\n            this.subOptionsTargetTab.Controls.Add(this.rangeCheckLT);\n            this.subOptionsTargetTab.Controls.Add(this.actionStatusMsg);\n            this.subOptionsTargetTab.Controls.Add(this.label8);\n            this.subOptionsTargetTab.Controls.Add(this.label6);\n            this.subOptionsTargetTab.Controls.Add(this.queueTargets);\n            this.subOptionsTargetTab.Controls.Add(this.lblTargetFormat);\n            this.subOptionsTargetTab.Location = new System.Drawing.Point(4, 22);\n            this.subOptionsTargetTab.Name = \"subOptionsTargetTab\";\n            this.subOptionsTargetTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subOptionsTargetTab.Size = new System.Drawing.Size(502, 308);\n            this.subOptionsTargetTab.TabIndex = 1;\n            this.subOptionsTargetTab.Text = \"Targeting & Queues  \";\n            // \n            // groupSmartTarget\n            // \n            this.groupSmartTarget.Controls.Add(this.nextPrevAbcOrder);\n            this.groupSmartTarget.Controls.Add(this.nonFriendlyHarmfulOnly);\n            this.groupSmartTarget.Controls.Add(this.friendBeneficialOnly);\n            this.groupSmartTarget.Controls.Add(this.onlyNextPrevBeneficial);\n            this.groupSmartTarget.Controls.Add(this.smartLT);\n            this.groupSmartTarget.Location = new System.Drawing.Point(243, 11);\n            this.groupSmartTarget.Name = \"groupSmartTarget\";\n            this.groupSmartTarget.Size = new System.Drawing.Size(253, 153);\n            this.groupSmartTarget.TabIndex = 138;\n            this.groupSmartTarget.TabStop = false;\n            this.groupSmartTarget.Text = \"Smart Targeting:\";\n            // \n            // nextPrevAbcOrder\n            // \n            this.nextPrevAbcOrder.Location = new System.Drawing.Point(6, 123);\n            this.nextPrevAbcOrder.Name = \"nextPrevAbcOrder\";\n            this.nextPrevAbcOrder.Size = new System.Drawing.Size(232, 19);\n            this.nextPrevAbcOrder.TabIndex = 142;\n            this.nextPrevAbcOrder.Text = \"\\'Next/Prev\\' by alphabetical order\";\n            this.nextPrevAbcOrder.UseVisualStyleBackColor = true;\n            this.nextPrevAbcOrder.CheckedChanged += new System.EventHandler(this.nextPrevAbcOrder_CheckedChanged);\n            // \n            // nonFriendlyHarmfulOnly\n            // \n            this.nonFriendlyHarmfulOnly.Location = new System.Drawing.Point(6, 98);\n            this.nonFriendlyHarmfulOnly.Name = \"nonFriendlyHarmfulOnly\";\n            this.nonFriendlyHarmfulOnly.Size = new System.Drawing.Size(232, 19);\n            this.nonFriendlyHarmfulOnly.TabIndex = 141;\n            this.nonFriendlyHarmfulOnly.Text = \"\\'Next/Prev Non-Friendly\\' harmful only\";\n            this.nonFriendlyHarmfulOnly.UseVisualStyleBackColor = true;\n            this.nonFriendlyHarmfulOnly.CheckedChanged += new System.EventHandler(this.nonFriendlyHarmfulOnly_CheckedChanged);\n            // \n            // friendBeneficialOnly\n            // \n            this.friendBeneficialOnly.AutoSize = true;\n            this.friendBeneficialOnly.Location = new System.Drawing.Point(6, 73);\n            this.friendBeneficialOnly.Name = \"friendBeneficialOnly\";\n            this.friendBeneficialOnly.Size = new System.Drawing.Size(233, 19);\n            this.friendBeneficialOnly.TabIndex = 140;\n            this.friendBeneficialOnly.Text = \"\\'Next/Prev Friendly\\' sets beneficial only\";\n            this.friendBeneficialOnly.UseVisualStyleBackColor = true;\n            this.friendBeneficialOnly.CheckedChanged += new System.EventHandler(this.friendBeneficialOnly_CheckedChanged);\n            // \n            // onlyNextPrevBeneficial\n            // \n            this.onlyNextPrevBeneficial.AutoSize = true;\n            this.onlyNextPrevBeneficial.Location = new System.Drawing.Point(6, 48);\n            this.onlyNextPrevBeneficial.Name = \"onlyNextPrevBeneficial\";\n            this.onlyNextPrevBeneficial.Size = new System.Drawing.Size(224, 19);\n            this.onlyNextPrevBeneficial.TabIndex = 139;\n            this.onlyNextPrevBeneficial.Text = \"\\'Next/Prev Friend\\' sets beneficial only\";\n            this.onlyNextPrevBeneficial.UseVisualStyleBackColor = true;\n            this.onlyNextPrevBeneficial.CheckedChanged += new System.EventHandler(this.onlyNextPrevBeneficial_CheckedChanged);\n            // \n            // smartLT\n            // \n            this.smartLT.Location = new System.Drawing.Point(6, 22);\n            this.smartLT.Name = \"smartLT\";\n            this.smartLT.Size = new System.Drawing.Size(212, 20);\n            this.smartLT.TabIndex = 138;\n            this.smartLT.Text = \"Use Smart Last Target\";\n            this.smartLT.CheckedChanged += new System.EventHandler(this.smartLT_CheckedChanged);\n            // \n            // setTargetIndicatorHue\n            // \n            this.setTargetIndicatorHue.Location = new System.Drawing.Point(177, 246);\n            this.setTargetIndicatorHue.Name = \"setTargetIndicatorHue\";\n            this.setTargetIndicatorHue.Size = new System.Drawing.Size(59, 23);\n            this.setTargetIndicatorHue.TabIndex = 134;\n            this.setTargetIndicatorHue.Text = \"Set Hue\";\n            this.setTargetIndicatorHue.UseVisualStyleBackColor = true;\n            this.setTargetIndicatorHue.Click += new System.EventHandler(this.setTargetIndicatorHue_Click);\n            // \n            // targetIndicatorFormat\n            // \n            this.targetIndicatorFormat.Location = new System.Drawing.Point(64, 246);\n            this.targetIndicatorFormat.Name = \"targetIndicatorFormat\";\n            this.targetIndicatorFormat.Size = new System.Drawing.Size(107, 23);\n            this.targetIndicatorFormat.TabIndex = 93;\n            this.targetIndicatorFormat.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.targetIndicatorFormat.TextChanged += new System.EventHandler(this.targetIndicatorFormat_TextChanged);\n            // \n            // showtargtext\n            // \n            this.showtargtext.Location = new System.Drawing.Point(9, 170);\n            this.showtargtext.Name = \"showtargtext\";\n            this.showtargtext.Size = new System.Drawing.Size(212, 20);\n            this.showtargtext.TabIndex = 91;\n            this.showtargtext.Text = \"Show target flag on single click\";\n            this.showtargtext.CheckedChanged += new System.EventHandler(this.showtargtext_CheckedChanged);\n            // \n            // showAttackTargetNewOnly\n            // \n            this.showAttackTargetNewOnly.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.showAttackTargetNewOnly.Location = new System.Drawing.Point(195, 196);\n            this.showAttackTargetNewOnly.Name = \"showAttackTargetNewOnly\";\n            this.showAttackTargetNewOnly.Size = new System.Drawing.Size(121, 44);\n            this.showAttackTargetNewOnly.TabIndex = 90;\n            this.showAttackTargetNewOnly.Text = \"New targets only\";\n            this.showAttackTargetNewOnly.UseVisualStyleBackColor = true;\n            this.showAttackTargetNewOnly.CheckedChanged += new System.EventHandler(this.showAttackTargetNewOnly_CheckedChanged);\n            // \n            // showTextTargetIndicator\n            // \n            this.showTextTargetIndicator.Location = new System.Drawing.Point(9, 221);\n            this.showTextTargetIndicator.Name = \"showTextTargetIndicator\";\n            this.showTextTargetIndicator.Size = new System.Drawing.Size(232, 19);\n            this.showTextTargetIndicator.TabIndex = 89;\n            this.showTextTargetIndicator.Text = \"Show text target indicator\";\n            this.showTextTargetIndicator.UseVisualStyleBackColor = true;\n            this.showTextTargetIndicator.CheckedChanged += new System.EventHandler(this.showTextTargetIndicator_CheckedChanged);\n            // \n            // showAttackTarget\n            // \n            this.showAttackTarget.Location = new System.Drawing.Point(9, 196);\n            this.showAttackTarget.Name = \"showAttackTarget\";\n            this.showAttackTarget.Size = new System.Drawing.Size(232, 19);\n            this.showAttackTarget.TabIndex = 88;\n            this.showAttackTarget.Text = \"Attack/target name overhead\";\n            this.showAttackTarget.UseVisualStyleBackColor = true;\n            this.showAttackTarget.CheckedChanged += new System.EventHandler(this.showAttackTarget_CheckedChanged);\n            // \n            // showTargetMessagesOverChar\n            // \n            this.showTargetMessagesOverChar.AutoSize = true;\n            this.showTargetMessagesOverChar.Location = new System.Drawing.Point(9, 118);\n            this.showTargetMessagesOverChar.Name = \"showTargetMessagesOverChar\";\n            this.showTargetMessagesOverChar.Size = new System.Drawing.Size(224, 19);\n            this.showTargetMessagesOverChar.TabIndex = 74;\n            this.showTargetMessagesOverChar.Text = \"Show Target Self/Last/Clear Overhead\";\n            this.showTargetMessagesOverChar.UseVisualStyleBackColor = true;\n            this.showTargetMessagesOverChar.CheckedChanged += new System.EventHandler(this.showTargetMessagesOverChar_CheckedChanged);\n            // \n            // txtObjDelay\n            // \n            this.txtObjDelay.Location = new System.Drawing.Point(109, 89);\n            this.txtObjDelay.Name = \"txtObjDelay\";\n            this.txtObjDelay.Size = new System.Drawing.Size(32, 23);\n            this.txtObjDelay.TabIndex = 56;\n            this.txtObjDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.txtObjDelay.TextChanged += new System.EventHandler(this.txtObjDelay_TextChanged);\n            // \n            // objectDelay\n            // \n            this.objectDelay.Location = new System.Drawing.Point(9, 88);\n            this.objectDelay.Name = \"objectDelay\";\n            this.objectDelay.Size = new System.Drawing.Size(104, 24);\n            this.objectDelay.TabIndex = 53;\n            this.objectDelay.Text = \"Object Delay:\";\n            this.objectDelay.CheckedChanged += new System.EventHandler(this.objectDelay_CheckedChanged);\n            // \n            // ltRange\n            // \n            this.ltRange.Location = new System.Drawing.Point(165, 141);\n            this.ltRange.Name = \"ltRange\";\n            this.ltRange.Size = new System.Drawing.Size(30, 23);\n            this.ltRange.TabIndex = 59;\n            this.ltRange.TextChanged += new System.EventHandler(this.ltRange_TextChanged);\n            // \n            // QueueActions\n            // \n            this.QueueActions.Location = new System.Drawing.Point(9, 64);\n            this.QueueActions.Name = \"QueueActions\";\n            this.QueueActions.Size = new System.Drawing.Size(202, 20);\n            this.QueueActions.TabIndex = 54;\n            this.QueueActions.Text = \"Auto-Queue Object Delay actions \";\n            this.QueueActions.CheckedChanged += new System.EventHandler(this.QueueActions_CheckedChanged);\n            // \n            // rangeCheckLT\n            // \n            this.rangeCheckLT.Location = new System.Drawing.Point(9, 142);\n            this.rangeCheckLT.Name = \"rangeCheckLT\";\n            this.rangeCheckLT.Size = new System.Drawing.Size(162, 20);\n            this.rangeCheckLT.TabIndex = 58;\n            this.rangeCheckLT.Text = \"Range check Last Target:\";\n            this.rangeCheckLT.CheckedChanged += new System.EventHandler(this.rangeCheckLT_CheckedChanged);\n            // \n            // actionStatusMsg\n            // \n            this.actionStatusMsg.Location = new System.Drawing.Point(9, 38);\n            this.actionStatusMsg.Name = \"actionStatusMsg\";\n            this.actionStatusMsg.Size = new System.Drawing.Size(212, 20);\n            this.actionStatusMsg.TabIndex = 57;\n            this.actionStatusMsg.Text = \"Show Action-Queue status messages\";\n            this.actionStatusMsg.CheckedChanged += new System.EventHandler(this.actionStatusMsg_CheckedChanged);\n            // \n            // label8\n            // \n            this.label8.Location = new System.Drawing.Point(201, 144);\n            this.label8.Name = \"label8\";\n            this.label8.Size = new System.Drawing.Size(30, 18);\n            this.label8.TabIndex = 60;\n            this.label8.Text = \"tiles\";\n            // \n            // label6\n            // \n            this.label6.Location = new System.Drawing.Point(147, 93);\n            this.label6.Name = \"label6\";\n            this.label6.Size = new System.Drawing.Size(32, 18);\n            this.label6.TabIndex = 55;\n            this.label6.Text = \"ms\";\n            // \n            // queueTargets\n            // \n            this.queueTargets.Location = new System.Drawing.Point(9, 12);\n            this.queueTargets.Name = \"queueTargets\";\n            this.queueTargets.Size = new System.Drawing.Size(228, 20);\n            this.queueTargets.TabIndex = 35;\n            this.queueTargets.Text = \"Queue LastTarget and TargetSelf\";\n            this.queueTargets.CheckedChanged += new System.EventHandler(this.queueTargets_CheckedChanged);\n            // \n            // lblTargetFormat\n            // \n            this.lblTargetFormat.Location = new System.Drawing.Point(10, 246);\n            this.lblTargetFormat.Name = \"lblTargetFormat\";\n            this.lblTargetFormat.Size = new System.Drawing.Size(140, 23);\n            this.lblTargetFormat.TabIndex = 94;\n            this.lblTargetFormat.Text = \"Format:\";\n            this.lblTargetFormat.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // subOptionsMiscTab\n            // \n            this.subOptionsMiscTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subOptionsMiscTab.Controls.Add(this.buyAgentIgnoreGold);\n            this.subOptionsMiscTab.Controls.Add(this.reequipHandsPotion);\n            this.subOptionsMiscTab.Controls.Add(this.autoOpenDoorWhenHidden);\n            this.subOptionsMiscTab.Controls.Add(this.lblStealthFormat);\n            this.subOptionsMiscTab.Controls.Add(this.stealthStepsFormat);\n            this.subOptionsMiscTab.Controls.Add(this.rememberPwds);\n            this.subOptionsMiscTab.Controls.Add(this.showStaticWalls);\n            this.subOptionsMiscTab.Controls.Add(this.showStaticWallLabels);\n            this.subOptionsMiscTab.Controls.Add(this.stealthOverhead);\n            this.subOptionsMiscTab.Controls.Add(this.forceSizeX);\n            this.subOptionsMiscTab.Controls.Add(this.forceSizeY);\n            this.subOptionsMiscTab.Controls.Add(this.blockHealPoison);\n            this.subOptionsMiscTab.Controls.Add(this.potionEquip);\n            this.subOptionsMiscTab.Controls.Add(this.spellUnequip);\n            this.subOptionsMiscTab.Controls.Add(this.autoOpenDoors);\n            this.subOptionsMiscTab.Controls.Add(this.chkStealth);\n            this.subOptionsMiscTab.Controls.Add(this.label18);\n            this.subOptionsMiscTab.Controls.Add(this.gameSize);\n            this.subOptionsMiscTab.Controls.Add(this.setMinLightLevel);\n            this.subOptionsMiscTab.Controls.Add(this.setMaxLightLevel);\n            this.subOptionsMiscTab.Controls.Add(this.seasonList);\n            this.subOptionsMiscTab.Controls.Add(this.lblSeason);\n            this.subOptionsMiscTab.Controls.Add(this.lightLevel);\n            this.subOptionsMiscTab.Controls.Add(this.lightLevelBar);\n            this.subOptionsMiscTab.Controls.Add(this.minMaxLightLevel);\n            this.subOptionsMiscTab.Controls.Add(this.blockPartyInvites);\n            this.subOptionsMiscTab.Controls.Add(this.blockTradeRequests);\n            this.subOptionsMiscTab.Controls.Add(this.blockOpenCorpsesTwice);\n            this.subOptionsMiscTab.Controls.Add(this.preAOSstatbar);\n            this.subOptionsMiscTab.Controls.Add(this.corpseRange);\n            this.subOptionsMiscTab.Controls.Add(this.autoStackRes);\n            this.subOptionsMiscTab.Controls.Add(this.label4);\n            this.subOptionsMiscTab.Controls.Add(this.openCorpses);\n            this.subOptionsMiscTab.Controls.Add(this.blockDis);\n            this.subOptionsMiscTab.Location = new System.Drawing.Point(4, 22);\n            this.subOptionsMiscTab.Name = \"subOptionsMiscTab\";\n            this.subOptionsMiscTab.Size = new System.Drawing.Size(502, 308);\n            this.subOptionsMiscTab.TabIndex = 2;\n            this.subOptionsMiscTab.Text = \"Additional Options  \";\n            // \n            // buyAgentIgnoreGold\n            // \n            this.buyAgentIgnoreGold.AutoSize = true;\n            this.buyAgentIgnoreGold.Location = new System.Drawing.Point(260, 244);\n            this.buyAgentIgnoreGold.Name = \"buyAgentIgnoreGold\";\n            this.buyAgentIgnoreGold.Size = new System.Drawing.Size(185, 19);\n            this.buyAgentIgnoreGold.TabIndex = 126;\n            this.buyAgentIgnoreGold.Text = \"Buy Agents ignore player gold\";\n            this.buyAgentIgnoreGold.UseVisualStyleBackColor = true;\n            this.buyAgentIgnoreGold.CheckedChanged += new System.EventHandler(this.buyAgentIgnoreGold_CheckedChanged);\n            // \n            // reequipHandsPotion\n            // \n            this.reequipHandsPotion.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.reequipHandsPotion.Location = new System.Drawing.Point(423, 140);\n            this.reequipHandsPotion.Name = \"reequipHandsPotion\";\n            this.reequipHandsPotion.Size = new System.Drawing.Size(69, 20);\n            this.reequipHandsPotion.TabIndex = 125;\n            this.reequipHandsPotion.Text = \"Re-equip\";\n            this.reequipHandsPotion.CheckedChanged += new System.EventHandler(this.reequipHandsPotion_CheckedChanged);\n            // \n            // autoOpenDoorWhenHidden\n            // \n            this.autoOpenDoorWhenHidden.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.autoOpenDoorWhenHidden.Location = new System.Drawing.Point(393, 88);\n            this.autoOpenDoorWhenHidden.Name = \"autoOpenDoorWhenHidden\";\n            this.autoOpenDoorWhenHidden.Size = new System.Drawing.Size(95, 20);\n            this.autoOpenDoorWhenHidden.TabIndex = 124;\n            this.autoOpenDoorWhenHidden.Text = \"When hidden\";\n            this.autoOpenDoorWhenHidden.CheckedChanged += new System.EventHandler(this.autoDoorWhenHidden_CheckedChanged);\n            // \n            // lblStealthFormat\n            // \n            this.lblStealthFormat.AutoSize = true;\n            this.lblStealthFormat.Location = new System.Drawing.Point(280, 62);\n            this.lblStealthFormat.Name = \"lblStealthFormat\";\n            this.lblStealthFormat.Size = new System.Drawing.Size(48, 15);\n            this.lblStealthFormat.TabIndex = 123;\n            this.lblStealthFormat.Text = \"Format:\";\n            // \n            // stealthStepsFormat\n            // \n            this.stealthStepsFormat.Location = new System.Drawing.Point(334, 59);\n            this.stealthStepsFormat.Name = \"stealthStepsFormat\";\n            this.stealthStepsFormat.Size = new System.Drawing.Size(114, 23);\n            this.stealthStepsFormat.TabIndex = 122;\n            this.stealthStepsFormat.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.stealthStepsFormat.TextChanged += new System.EventHandler(this.stealthStepsFormat_TextChanged);\n            // \n            // rememberPwds\n            // \n            this.rememberPwds.Location = new System.Drawing.Point(260, 12);\n            this.rememberPwds.Name = \"rememberPwds\";\n            this.rememberPwds.Size = new System.Drawing.Size(148, 20);\n            this.rememberPwds.TabIndex = 121;\n            this.rememberPwds.Text = \"Remember passwords \";\n            this.rememberPwds.CheckedChanged += new System.EventHandler(this.rememberPwds_CheckedChanged);\n            // \n            // showStaticWalls\n            // \n            this.showStaticWalls.AutoSize = true;\n            this.showStaticWalls.Location = new System.Drawing.Point(260, 219);\n            this.showStaticWalls.Name = \"showStaticWalls\";\n            this.showStaticWalls.Size = new System.Drawing.Size(153, 19);\n            this.showStaticWalls.TabIndex = 119;\n            this.showStaticWalls.Text = \"Static magic fields/walls\";\n            this.showStaticWalls.UseVisualStyleBackColor = true;\n            this.showStaticWalls.CheckedChanged += new System.EventHandler(this.showStaticWalls_CheckedChanged);\n            // \n            // showStaticWallLabels\n            // \n            this.showStaticWallLabels.AutoSize = true;\n            this.showStaticWallLabels.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.showStaticWallLabels.Location = new System.Drawing.Point(421, 220);\n            this.showStaticWallLabels.Name = \"showStaticWallLabels\";\n            this.showStaticWallLabels.Size = new System.Drawing.Size(55, 17);\n            this.showStaticWallLabels.TabIndex = 120;\n            this.showStaticWallLabels.Text = \"Labels\";\n            this.showStaticWallLabels.UseVisualStyleBackColor = true;\n            this.showStaticWallLabels.CheckedChanged += new System.EventHandler(this.showStaticWallLabels_CheckedChanged);\n            // \n            // stealthOverhead\n            // \n            this.stealthOverhead.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.stealthOverhead.Location = new System.Drawing.Point(393, 37);\n            this.stealthOverhead.Name = \"stealthOverhead\";\n            this.stealthOverhead.Size = new System.Drawing.Size(99, 20);\n            this.stealthOverhead.TabIndex = 117;\n            this.stealthOverhead.Text = \"Overhead\";\n            this.stealthOverhead.UseVisualStyleBackColor = true;\n            this.stealthOverhead.CheckedChanged += new System.EventHandler(this.stealthOverhead_CheckedChanged);\n            // \n            // forceSizeX\n            // \n            this.forceSizeX.Location = new System.Drawing.Point(387, 190);\n            this.forceSizeX.Name = \"forceSizeX\";\n            this.forceSizeX.Size = new System.Drawing.Size(34, 23);\n            this.forceSizeX.TabIndex = 111;\n            this.forceSizeX.TextChanged += new System.EventHandler(this.forceSizeX_TextChanged);\n            // \n            // forceSizeY\n            // \n            this.forceSizeY.Location = new System.Drawing.Point(443, 191);\n            this.forceSizeY.Name = \"forceSizeY\";\n            this.forceSizeY.Size = new System.Drawing.Size(33, 23);\n            this.forceSizeY.TabIndex = 112;\n            this.forceSizeY.TextChanged += new System.EventHandler(this.forceSizeY_TextChanged);\n            // \n            // blockHealPoison\n            // \n            this.blockHealPoison.Location = new System.Drawing.Point(260, 166);\n            this.blockHealPoison.Name = \"blockHealPoison\";\n            this.blockHealPoison.Size = new System.Drawing.Size(201, 20);\n            this.blockHealPoison.TabIndex = 116;\n            this.blockHealPoison.Text = \"Block heal if target is poisoned\";\n            this.blockHealPoison.CheckedChanged += new System.EventHandler(this.blockHealPoison_CheckedChanged);\n            // \n            // potionEquip\n            // \n            this.potionEquip.Location = new System.Drawing.Point(260, 140);\n            this.potionEquip.Name = \"potionEquip\";\n            this.potionEquip.Size = new System.Drawing.Size(232, 20);\n            this.potionEquip.TabIndex = 115;\n            this.potionEquip.Text = \"Auto Unequip for potions\";\n            this.potionEquip.CheckedChanged += new System.EventHandler(this.potionEquip_CheckedChanged);\n            // \n            // spellUnequip\n            // \n            this.spellUnequip.Location = new System.Drawing.Point(260, 114);\n            this.spellUnequip.Name = \"spellUnequip\";\n            this.spellUnequip.Size = new System.Drawing.Size(213, 20);\n            this.spellUnequip.TabIndex = 108;\n            this.spellUnequip.Text = \"Auto Unequip hands before casting\";\n            this.spellUnequip.CheckedChanged += new System.EventHandler(this.spellUnequip_CheckedChanged);\n            // \n            // autoOpenDoors\n            // \n            this.autoOpenDoors.Location = new System.Drawing.Point(260, 88);\n            this.autoOpenDoors.Name = \"autoOpenDoors\";\n            this.autoOpenDoors.Size = new System.Drawing.Size(118, 20);\n            this.autoOpenDoors.TabIndex = 110;\n            this.autoOpenDoors.Text = \"Auto-open doors\";\n            this.autoOpenDoors.CheckedChanged += new System.EventHandler(this.autoOpenDoors_CheckedChanged);\n            // \n            // chkStealth\n            // \n            this.chkStealth.Location = new System.Drawing.Point(260, 37);\n            this.chkStealth.Name = \"chkStealth\";\n            this.chkStealth.Size = new System.Drawing.Size(190, 20);\n            this.chkStealth.TabIndex = 107;\n            this.chkStealth.Text = \"Count stealth steps\";\n            this.chkStealth.CheckedChanged += new System.EventHandler(this.chkStealth_CheckedChanged);\n            // \n            // label18\n            // \n            this.label18.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.label18.Location = new System.Drawing.Point(427, 193);\n            this.label18.Name = \"label18\";\n            this.label18.Size = new System.Drawing.Size(10, 18);\n            this.label18.TabIndex = 114;\n            this.label18.Text = \"x\";\n            this.label18.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // gameSize\n            // \n            this.gameSize.Location = new System.Drawing.Point(260, 192);\n            this.gameSize.Name = \"gameSize\";\n            this.gameSize.Size = new System.Drawing.Size(118, 18);\n            this.gameSize.TabIndex = 113;\n            this.gameSize.Text = \"Force Game Size:\";\n            this.gameSize.CheckedChanged += new System.EventHandler(this.gameSize_CheckedChanged);\n            // \n            // setMinLightLevel\n            // \n            this.setMinLightLevel.Location = new System.Drawing.Point(117, 247);\n            this.setMinLightLevel.Name = \"setMinLightLevel\";\n            this.setMinLightLevel.Size = new System.Drawing.Size(58, 25);\n            this.setMinLightLevel.TabIndex = 105;\n            this.setMinLightLevel.Text = \"Set Min\";\n            this.setMinLightLevel.Click += new System.EventHandler(this.setMinLightLevel_Click);\n            // \n            // setMaxLightLevel\n            // \n            this.setMaxLightLevel.Location = new System.Drawing.Point(181, 247);\n            this.setMaxLightLevel.Name = \"setMaxLightLevel\";\n            this.setMaxLightLevel.Size = new System.Drawing.Size(58, 25);\n            this.setMaxLightLevel.TabIndex = 104;\n            this.setMaxLightLevel.Text = \"Set Max\";\n            this.setMaxLightLevel.Click += new System.EventHandler(this.setMaxLightLevel_Click);\n            // \n            // seasonList\n            // \n            this.seasonList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.seasonList.FormattingEnabled = true;\n            this.seasonList.Items.AddRange(new object[] {\n            \"Spring\",\n            \"Summer\",\n            \"Fall\",\n            \"Winter\",\n            \"Desolation\",\n            \"(Server Default)\"});\n            this.seasonList.Location = new System.Drawing.Point(59, 195);\n            this.seasonList.Name = \"seasonList\";\n            this.seasonList.Size = new System.Drawing.Size(111, 23);\n            this.seasonList.TabIndex = 102;\n            this.seasonList.SelectedIndexChanged += new System.EventHandler(this.seasonList_SelectedIndexChanged);\n            // \n            // lblSeason\n            // \n            this.lblSeason.AutoSize = true;\n            this.lblSeason.Location = new System.Drawing.Point(6, 198);\n            this.lblSeason.Name = \"lblSeason\";\n            this.lblSeason.Size = new System.Drawing.Size(47, 15);\n            this.lblSeason.TabIndex = 101;\n            this.lblSeason.Text = \"Season:\";\n            // \n            // lightLevel\n            // \n            this.lightLevel.AutoSize = true;\n            this.lightLevel.Location = new System.Drawing.Point(6, 223);\n            this.lightLevel.Name = \"lightLevel\";\n            this.lightLevel.Size = new System.Drawing.Size(67, 15);\n            this.lightLevel.TabIndex = 100;\n            this.lightLevel.Text = \"Light Level:\";\n            // \n            // lightLevelBar\n            // \n            this.lightLevelBar.AutoSize = false;\n            this.lightLevelBar.Location = new System.Drawing.Point(79, 223);\n            this.lightLevelBar.Maximum = 31;\n            this.lightLevelBar.Name = \"lightLevelBar\";\n            this.lightLevelBar.Size = new System.Drawing.Size(161, 21);\n            this.lightLevelBar.TabIndex = 99;\n            this.lightLevelBar.TickStyle = System.Windows.Forms.TickStyle.None;\n            this.lightLevelBar.Value = 15;\n            this.lightLevelBar.Scroll += new System.EventHandler(this.lightLevelBar_Scroll);\n            // \n            // minMaxLightLevel\n            // \n            this.minMaxLightLevel.Location = new System.Drawing.Point(9, 250);\n            this.minMaxLightLevel.Name = \"minMaxLightLevel\";\n            this.minMaxLightLevel.Size = new System.Drawing.Size(114, 20);\n            this.minMaxLightLevel.TabIndex = 106;\n            this.minMaxLightLevel.Text = \"Enable Min/Max\";\n            this.minMaxLightLevel.CheckedChanged += new System.EventHandler(this.minMaxLightLevel_CheckedChanged);\n            // \n            // blockPartyInvites\n            // \n            this.blockPartyInvites.Location = new System.Drawing.Point(9, 169);\n            this.blockPartyInvites.Name = \"blockPartyInvites\";\n            this.blockPartyInvites.Size = new System.Drawing.Size(184, 20);\n            this.blockPartyInvites.TabIndex = 98;\n            this.blockPartyInvites.Text = \"Block party invites\";\n            this.blockPartyInvites.CheckedChanged += new System.EventHandler(this.blockPartyInvites_CheckedChanged);\n            // \n            // blockTradeRequests\n            // \n            this.blockTradeRequests.Location = new System.Drawing.Point(9, 143);\n            this.blockTradeRequests.Name = \"blockTradeRequests\";\n            this.blockTradeRequests.Size = new System.Drawing.Size(184, 20);\n            this.blockTradeRequests.TabIndex = 97;\n            this.blockTradeRequests.Text = \"Block trade requests\";\n            this.blockTradeRequests.CheckedChanged += new System.EventHandler(this.blockTradeRequests_CheckedChanged);\n            // \n            // blockOpenCorpsesTwice\n            // \n            this.blockOpenCorpsesTwice.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.blockOpenCorpsesTwice.Location = new System.Drawing.Point(9, 91);\n            this.blockOpenCorpsesTwice.Name = \"blockOpenCorpsesTwice\";\n            this.blockOpenCorpsesTwice.Size = new System.Drawing.Size(209, 20);\n            this.blockOpenCorpsesTwice.TabIndex = 96;\n            this.blockOpenCorpsesTwice.Text = \"Block opening corpses twice\";\n            this.blockOpenCorpsesTwice.CheckedChanged += new System.EventHandler(this.blockOpenCorpsesTwice_CheckedChanged);\n            // \n            // preAOSstatbar\n            // \n            this.preAOSstatbar.Location = new System.Drawing.Point(9, 12);\n            this.preAOSstatbar.Name = \"preAOSstatbar\";\n            this.preAOSstatbar.Size = new System.Drawing.Size(190, 20);\n            this.preAOSstatbar.TabIndex = 95;\n            this.preAOSstatbar.Text = \"Use Pre-AOS status window\";\n            this.preAOSstatbar.CheckedChanged += new System.EventHandler(this.preAOSstatbar_CheckedChanged);\n            // \n            // corpseRange\n            // \n            this.corpseRange.Location = new System.Drawing.Point(169, 63);\n            this.corpseRange.Name = \"corpseRange\";\n            this.corpseRange.Size = new System.Drawing.Size(24, 23);\n            this.corpseRange.TabIndex = 91;\n            this.corpseRange.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.corpseRange.TextChanged += new System.EventHandler(this.corpseRange_TextChanged);\n            // \n            // autoStackRes\n            // \n            this.autoStackRes.Location = new System.Drawing.Point(9, 37);\n            this.autoStackRes.Name = \"autoStackRes\";\n            this.autoStackRes.Size = new System.Drawing.Size(228, 20);\n            this.autoStackRes.TabIndex = 93;\n            this.autoStackRes.Text = \"Auto-Stack Ore/Fish/Logs at Feet\";\n            this.autoStackRes.CheckedChanged += new System.EventHandler(this.autoStackRes_CheckedChanged);\n            // \n            // label4\n            // \n            this.label4.Location = new System.Drawing.Point(201, 67);\n            this.label4.Name = \"label4\";\n            this.label4.Size = new System.Drawing.Size(36, 16);\n            this.label4.TabIndex = 92;\n            this.label4.Text = \"tiles\";\n            // \n            // openCorpses\n            // \n            this.openCorpses.Location = new System.Drawing.Point(9, 65);\n            this.openCorpses.Name = \"openCorpses\";\n            this.openCorpses.Size = new System.Drawing.Size(165, 20);\n            this.openCorpses.TabIndex = 90;\n            this.openCorpses.Text = \"Open new corpses within\";\n            this.openCorpses.CheckedChanged += new System.EventHandler(this.openCorpses_CheckedChanged);\n            // \n            // blockDis\n            // \n            this.blockDis.Location = new System.Drawing.Point(9, 117);\n            this.blockDis.Name = \"blockDis\";\n            this.blockDis.Size = new System.Drawing.Size(184, 20);\n            this.blockDis.TabIndex = 94;\n            this.blockDis.Text = \"Block dismount in war mode\";\n            this.blockDis.CheckedChanged += new System.EventHandler(this.blockDis_CheckedChanged);\n            // \n            // displayTab\n            // \n            this.displayTab.Controls.Add(this.displayCountersTabCtrl);\n            this.displayTab.Location = new System.Drawing.Point(4, 44);\n            this.displayTab.Name = \"displayTab\";\n            this.displayTab.Size = new System.Drawing.Size(519, 322);\n            this.displayTab.TabIndex = 1;\n            this.displayTab.Text = \"Display/Counters\";\n            // \n            // displayCountersTabCtrl\n            // \n            this.displayCountersTabCtrl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.displayCountersTabCtrl.Controls.Add(this.subDisplayTab);\n            this.displayCountersTabCtrl.Controls.Add(this.subCountersTab);\n            this.displayCountersTabCtrl.Controls.Add(this.subBandageTimerTab);\n            this.displayCountersTabCtrl.Controls.Add(this.subOverheadTab);\n            this.displayCountersTabCtrl.Controls.Add(this.subWaypoints);\n            this.displayCountersTabCtrl.Controls.Add(this.subBuffsDebuffs);\n            this.displayCountersTabCtrl.Location = new System.Drawing.Point(6, 3);\n            this.displayCountersTabCtrl.Name = \"displayCountersTabCtrl\";\n            this.displayCountersTabCtrl.SelectedIndex = 0;\n            this.displayCountersTabCtrl.Size = new System.Drawing.Size(510, 314);\n            this.displayCountersTabCtrl.TabIndex = 51;\n            this.displayCountersTabCtrl.SelectedIndexChanged += new System.EventHandler(this.displayCountersTabCtrl_SelectedIndexChanged);\n            // \n            // subDisplayTab\n            // \n            this.subDisplayTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subDisplayTab.Controls.Add(this.groupBox11);\n            this.subDisplayTab.Controls.Add(this.trackDps);\n            this.subDisplayTab.Controls.Add(this.trackIncomingGold);\n            this.subDisplayTab.Controls.Add(this.showNotoHue);\n            this.subDisplayTab.Controls.Add(this.highlightSpellReags);\n            this.subDisplayTab.Controls.Add(this.groupBox3);\n            this.subDisplayTab.Location = new System.Drawing.Point(4, 24);\n            this.subDisplayTab.Name = \"subDisplayTab\";\n            this.subDisplayTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subDisplayTab.Size = new System.Drawing.Size(502, 286);\n            this.subDisplayTab.TabIndex = 0;\n            this.subDisplayTab.Text = \"Display\";\n            // \n            // groupBox11\n            // \n            this.groupBox11.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.groupBox11.Controls.Add(this.razorTitleBarKey);\n            this.groupBox11.Controls.Add(this.showInRazorTitleBar);\n            this.groupBox11.Controls.Add(this.razorTitleBar);\n            this.groupBox11.Location = new System.Drawing.Point(6, 175);\n            this.groupBox11.Name = \"groupBox11\";\n            this.groupBox11.Size = new System.Drawing.Size(490, 71);\n            this.groupBox11.TabIndex = 51;\n            this.groupBox11.TabStop = false;\n            this.groupBox11.Text = \"Razor Title Bar\";\n            // \n            // razorTitleBarKey\n            // \n            this.razorTitleBarKey.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.razorTitleBarKey.Location = new System.Drawing.Point(468, 17);\n            this.razorTitleBarKey.Name = \"razorTitleBarKey\";\n            this.razorTitleBarKey.Size = new System.Drawing.Size(16, 20);\n            this.razorTitleBarKey.TabIndex = 2;\n            this.razorTitleBarKey.Text = \"?\";\n            this.razorTitleBarKey.UseVisualStyleBackColor = true;\n            this.razorTitleBarKey.Click += new System.EventHandler(this.razorTitleBarKey_Click);\n            // \n            // showInRazorTitleBar\n            // \n            this.showInRazorTitleBar.AutoSize = true;\n            this.showInRazorTitleBar.Location = new System.Drawing.Point(6, 17);\n            this.showInRazorTitleBar.Name = \"showInRazorTitleBar\";\n            this.showInRazorTitleBar.Size = new System.Drawing.Size(146, 19);\n            this.showInRazorTitleBar.TabIndex = 1;\n            this.showInRazorTitleBar.Text = \"Show in Razor title bar:\";\n            this.showInRazorTitleBar.UseVisualStyleBackColor = true;\n            this.showInRazorTitleBar.CheckedChanged += new System.EventHandler(this.showInRazorTitleBar_CheckedChanged);\n            // \n            // razorTitleBar\n            // \n            this.razorTitleBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.razorTitleBar.Font = new System.Drawing.Font(\"Consolas\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.razorTitleBar.Location = new System.Drawing.Point(6, 42);\n            this.razorTitleBar.Name = \"razorTitleBar\";\n            this.razorTitleBar.Size = new System.Drawing.Size(478, 22);\n            this.razorTitleBar.TabIndex = 0;\n            this.razorTitleBar.Text = \"{name} ({profile} - {shard}) - Razor v{version}\";\n            this.razorTitleBar.TextChanged += new System.EventHandler(this.razorTitleBar_TextChanged);\n            // \n            // trackDps\n            // \n            this.trackDps.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.trackDps.AutoSize = true;\n            this.trackDps.Location = new System.Drawing.Point(273, 146);\n            this.trackDps.Name = \"trackDps\";\n            this.trackDps.Size = new System.Drawing.Size(146, 19);\n            this.trackDps.TabIndex = 53;\n            this.trackDps.Text = \"Enable damage tracker\";\n            this.trackDps.UseVisualStyleBackColor = true;\n            this.trackDps.CheckedChanged += new System.EventHandler(this.trackDps_CheckedChanged);\n            // \n            // trackIncomingGold\n            // \n            this.trackIncomingGold.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.trackIncomingGold.AutoSize = true;\n            this.trackIncomingGold.Location = new System.Drawing.Point(273, 120);\n            this.trackIncomingGold.Name = \"trackIncomingGold\";\n            this.trackIncomingGold.Size = new System.Drawing.Size(223, 19);\n            this.trackIncomingGold.TabIndex = 52;\n            this.trackIncomingGold.Text = \"Enable gold per sec/min/hour tracker\";\n            this.trackIncomingGold.UseVisualStyleBackColor = true;\n            this.trackIncomingGold.CheckedChanged += new System.EventHandler(this.trackIncomingGold_CheckedChanged);\n            // \n            // showNotoHue\n            // \n            this.showNotoHue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.showNotoHue.Location = new System.Drawing.Point(6, 145);\n            this.showNotoHue.Name = \"showNotoHue\";\n            this.showNotoHue.Size = new System.Drawing.Size(221, 20);\n            this.showNotoHue.TabIndex = 51;\n            this.showNotoHue.Text = \"Show noto hue on {char} in TitleBar\";\n            this.showNotoHue.CheckedChanged += new System.EventHandler(this.showNotoHue_CheckedChanged);\n            // \n            // highlightSpellReags\n            // \n            this.highlightSpellReags.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.highlightSpellReags.Location = new System.Drawing.Point(6, 119);\n            this.highlightSpellReags.Name = \"highlightSpellReags\";\n            this.highlightSpellReags.Size = new System.Drawing.Size(205, 20);\n            this.highlightSpellReags.TabIndex = 50;\n            this.highlightSpellReags.Text = \"Highlight Spell Reagents on Cast\";\n            this.highlightSpellReags.CheckedChanged += new System.EventHandler(this.highlightSpellReags_CheckedChanged);\n            // \n            // groupBox3\n            // \n            this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.groupBox3.Controls.Add(this.titleBarParams);\n            this.groupBox3.Controls.Add(this.titleStr);\n            this.groupBox3.Controls.Add(this.showInBar);\n            this.groupBox3.Location = new System.Drawing.Point(6, 6);\n            this.groupBox3.Name = \"groupBox3\";\n            this.groupBox3.Size = new System.Drawing.Size(490, 107);\n            this.groupBox3.TabIndex = 4;\n            this.groupBox3.TabStop = false;\n            this.groupBox3.Text = \"Title Bar Display\";\n            // \n            // titleBarParams\n            // \n            this.titleBarParams.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.titleBarParams.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.titleBarParams.FormattingEnabled = true;\n            this.titleBarParams.Items.AddRange(new object[] {\n            \"{ar}\",\n            \"{bandage}\",\n            \"{char}\",\n            \"{crimtime}\",\n            \"{buffsdebuffs}\",\n            \"{damage}\",\n            \"-\",\n            \"{dps}\",\n            \"{maxdps}\",\n            \"{maxdamagedealt}\",\n            \"{maxdamagetaken}\",\n            \"{totaldamagedealt}\",\n            \"{totaldamagetaken}\",\n            \"-\",\n            \"{dex}\",\n            \"{followersmax}\",\n            \"{followers}\",\n            \"-\",\n            \"{gold}\",\n            \"{goldtotal}\",\n            \"{goldtotalmin}\",\n            \"{gpm}\",\n            \"{gps}\",\n            \"{gph}\",\n            \"-\",\n            \"{gate}\",\n            \"{hpmax}\",\n            \"{hp}\",\n            \"{int}\",\n            \"{largestatbar}\",\n            \"{manamax}\",\n            \"{mana}\",\n            \"{maxweight}\",\n            \"{mediumstatbar}\",\n            \"{shard}\",\n            \"{skill}\",\n            \"{stammax}\",\n            \"{stam}\",\n            \"{statbar}\",\n            \"{stealthsteps}\",\n            \"{str}\",\n            \"{uptime}\",\n            \"{weight}\",\n            \"-\",\n            \"{coldresist}\",\n            \"{energyresist}\",\n            \"{fireresist}\",\n            \"{luck}\",\n            \"{physresist}\",\n            \"{poisonresist}\",\n            \"{tithe}\"});\n            this.titleBarParams.Location = new System.Drawing.Point(380, 19);\n            this.titleBarParams.Name = \"titleBarParams\";\n            this.titleBarParams.Size = new System.Drawing.Size(104, 23);\n            this.titleBarParams.TabIndex = 5;\n            this.titleBarParams.SelectedIndexChanged += new System.EventHandler(this.titleBarParams_SelectedIndexChanged);\n            // \n            // titleStr\n            // \n            this.titleStr.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.titleStr.Font = new System.Drawing.Font(\"Consolas\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.titleStr.Location = new System.Drawing.Point(6, 48);\n            this.titleStr.Multiline = true;\n            this.titleStr.Name = \"titleStr\";\n            this.titleStr.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;\n            this.titleStr.Size = new System.Drawing.Size(478, 53);\n            this.titleStr.TabIndex = 4;\n            this.titleStr.TextChanged += new System.EventHandler(this.titleStr_TextChanged);\n            // \n            // showInBar\n            // \n            this.showInBar.Location = new System.Drawing.Point(11, 22);\n            this.showInBar.Name = \"showInBar\";\n            this.showInBar.Size = new System.Drawing.Size(141, 20);\n            this.showInBar.TabIndex = 3;\n            this.showInBar.Text = \"Show in UO title bar:\";\n            this.showInBar.CheckedChanged += new System.EventHandler(this.showInBar_CheckedChanged);\n            // \n            // subCountersTab\n            // \n            this.subCountersTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subCountersTab.Controls.Add(this.warnNum);\n            this.subCountersTab.Controls.Add(this.warnCount);\n            this.subCountersTab.Controls.Add(this.excludePouches);\n            this.subCountersTab.Controls.Add(this.titlebarImages);\n            this.subCountersTab.Controls.Add(this.checkNewConts);\n            this.subCountersTab.Controls.Add(this.groupBox2);\n            this.subCountersTab.Location = new System.Drawing.Point(4, 22);\n            this.subCountersTab.Name = \"subCountersTab\";\n            this.subCountersTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subCountersTab.Size = new System.Drawing.Size(502, 288);\n            this.subCountersTab.TabIndex = 1;\n            this.subCountersTab.Text = \"Counters\";\n            // \n            // warnNum\n            // \n            this.warnNum.Location = new System.Drawing.Point(430, 99);\n            this.warnNum.Name = \"warnNum\";\n            this.warnNum.Size = new System.Drawing.Size(30, 23);\n            this.warnNum.TabIndex = 51;\n            this.warnNum.Text = \"3\";\n            this.warnNum.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.warnNum.TextChanged += new System.EventHandler(this.warnNum_TextChanged);\n            // \n            // warnCount\n            // \n            this.warnCount.Location = new System.Drawing.Point(299, 101);\n            this.warnCount.Name = \"warnCount\";\n            this.warnCount.Size = new System.Drawing.Size(192, 19);\n            this.warnCount.TabIndex = 50;\n            this.warnCount.Text = \"Warn when below:\";\n            this.warnCount.CheckedChanged += new System.EventHandler(this.warnCount_CheckedChanged);\n            // \n            // excludePouches\n            // \n            this.excludePouches.Location = new System.Drawing.Point(299, 48);\n            this.excludePouches.Name = \"excludePouches\";\n            this.excludePouches.Size = new System.Drawing.Size(192, 21);\n            this.excludePouches.TabIndex = 49;\n            this.excludePouches.Text = \"Never auto-search pouches\";\n            this.excludePouches.CheckedChanged += new System.EventHandler(this.excludePouches_CheckedChanged);\n            // \n            // titlebarImages\n            // \n            this.titlebarImages.Location = new System.Drawing.Point(299, 75);\n            this.titlebarImages.Name = \"titlebarImages\";\n            this.titlebarImages.Size = new System.Drawing.Size(180, 20);\n            this.titlebarImages.TabIndex = 48;\n            this.titlebarImages.Text = \"Show Images with Counters\";\n            this.titlebarImages.CheckedChanged += new System.EventHandler(this.titlebarImages_CheckedChanged);\n            // \n            // checkNewConts\n            // \n            this.checkNewConts.Location = new System.Drawing.Point(299, 24);\n            this.checkNewConts.Name = \"checkNewConts\";\n            this.checkNewConts.Size = new System.Drawing.Size(200, 20);\n            this.checkNewConts.TabIndex = 47;\n            this.checkNewConts.Text = \"Auto search new containers\";\n            this.checkNewConts.CheckedChanged += new System.EventHandler(this.checkNewConts_CheckedChanged);\n            // \n            // groupBox2\n            // \n            this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.groupBox2.Controls.Add(this.counters);\n            this.groupBox2.Controls.Add(this.delCounter);\n            this.groupBox2.Controls.Add(this.addCounter);\n            this.groupBox2.Controls.Add(this.recount);\n            this.groupBox2.Location = new System.Drawing.Point(6, 6);\n            this.groupBox2.Name = \"groupBox2\";\n            this.groupBox2.Size = new System.Drawing.Size(284, 254);\n            this.groupBox2.TabIndex = 2;\n            this.groupBox2.TabStop = false;\n            this.groupBox2.Text = \"Counters\";\n            // \n            // counters\n            // \n            this.counters.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.counters.CheckBoxes = true;\n            this.counters.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {\n            this.cntName,\n            this.cntCount});\n            this.counters.GridLines = true;\n            this.counters.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;\n            this.counters.HideSelection = false;\n            this.counters.LabelWrap = false;\n            this.counters.Location = new System.Drawing.Point(6, 18);\n            this.counters.MultiSelect = false;\n            this.counters.Name = \"counters\";\n            this.counters.Size = new System.Drawing.Size(272, 187);\n            this.counters.TabIndex = 11;\n            this.counters.UseCompatibleStateImageBehavior = false;\n            this.counters.View = System.Windows.Forms.View.Details;\n            this.counters.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.counters_ItemCheck);\n            // \n            // cntName\n            // \n            this.cntName.Text = \"Name (Format)\";\n            this.cntName.Width = 216;\n            // \n            // cntCount\n            // \n            this.cntCount.Text = \"Count\";\n            this.cntCount.Width = 51;\n            // \n            // delCounter\n            // \n            this.delCounter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.delCounter.Location = new System.Drawing.Point(108, 211);\n            this.delCounter.Name = \"delCounter\";\n            this.delCounter.Size = new System.Drawing.Size(71, 37);\n            this.delCounter.TabIndex = 4;\n            this.delCounter.Text = \"Del/Edit\";\n            this.delCounter.Click += new System.EventHandler(this.delCounter_Click);\n            // \n            // addCounter\n            // \n            this.addCounter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.addCounter.Location = new System.Drawing.Point(6, 211);\n            this.addCounter.Name = \"addCounter\";\n            this.addCounter.Size = new System.Drawing.Size(70, 37);\n            this.addCounter.TabIndex = 3;\n            this.addCounter.Text = \"Add...\";\n            this.addCounter.Click += new System.EventHandler(this.addCounter_Click);\n            // \n            // recount\n            // \n            this.recount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.recount.Location = new System.Drawing.Point(208, 211);\n            this.recount.Name = \"recount\";\n            this.recount.Size = new System.Drawing.Size(70, 37);\n            this.recount.TabIndex = 2;\n            this.recount.Text = \"Recount\";\n            this.recount.Click += new System.EventHandler(this.recount_Click);\n            // \n            // subBandageTimerTab\n            // \n            this.subBandageTimerTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subBandageTimerTab.Controls.Add(this.bandageEndMessage);\n            this.subBandageTimerTab.Controls.Add(this.bandageStartMessage);\n            this.subBandageTimerTab.Controls.Add(this.showBandageEnd);\n            this.subBandageTimerTab.Controls.Add(this.showBandageStart);\n            this.subBandageTimerTab.Controls.Add(this.setBandageHue);\n            this.subBandageTimerTab.Controls.Add(this.bandageTimerLocation);\n            this.subBandageTimerTab.Controls.Add(this.bandageTimerSeconds);\n            this.subBandageTimerTab.Controls.Add(this.onlyShowBandageTimerSeconds);\n            this.subBandageTimerTab.Controls.Add(this.bandageTimerFormat);\n            this.subBandageTimerTab.Controls.Add(this.showBandageTimer);\n            this.subBandageTimerTab.Controls.Add(this.lblBandageCountFormat);\n            this.subBandageTimerTab.Location = new System.Drawing.Point(4, 22);\n            this.subBandageTimerTab.Name = \"subBandageTimerTab\";\n            this.subBandageTimerTab.Size = new System.Drawing.Size(502, 288);\n            this.subBandageTimerTab.TabIndex = 2;\n            this.subBandageTimerTab.Text = \"Bandage Timer\";\n            // \n            // bandageEndMessage\n            // \n            this.bandageEndMessage.Location = new System.Drawing.Point(205, 123);\n            this.bandageEndMessage.Name = \"bandageEndMessage\";\n            this.bandageEndMessage.Size = new System.Drawing.Size(146, 23);\n            this.bandageEndMessage.TabIndex = 62;\n            this.bandageEndMessage.Text = \"Bandage: Ending\";\n            this.bandageEndMessage.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.bandageEndMessage.TextChanged += new System.EventHandler(this.BandageEndMessage_TextChanged);\n            // \n            // bandageStartMessage\n            // \n            this.bandageStartMessage.Location = new System.Drawing.Point(205, 98);\n            this.bandageStartMessage.Name = \"bandageStartMessage\";\n            this.bandageStartMessage.Size = new System.Drawing.Size(146, 23);\n            this.bandageStartMessage.TabIndex = 61;\n            this.bandageStartMessage.Text = \"Bandage: Starting\";\n            this.bandageStartMessage.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.bandageStartMessage.TextChanged += new System.EventHandler(this.BandageStartMessage_TextChanged);\n            // \n            // showBandageEnd\n            // \n            this.showBandageEnd.AutoSize = true;\n            this.showBandageEnd.Location = new System.Drawing.Point(9, 125);\n            this.showBandageEnd.Name = \"showBandageEnd\";\n            this.showBandageEnd.Size = new System.Drawing.Size(187, 19);\n            this.showBandageEnd.TabIndex = 60;\n            this.showBandageEnd.Text = \"Show bandaging end message\";\n            this.showBandageEnd.UseVisualStyleBackColor = true;\n            this.showBandageEnd.CheckedChanged += new System.EventHandler(this.ShowBandageEnd_CheckedChanged);\n            // \n            // showBandageStart\n            // \n            this.showBandageStart.AutoSize = true;\n            this.showBandageStart.Location = new System.Drawing.Point(9, 100);\n            this.showBandageStart.Name = \"showBandageStart\";\n            this.showBandageStart.Size = new System.Drawing.Size(190, 19);\n            this.showBandageStart.TabIndex = 58;\n            this.showBandageStart.Text = \"Show bandaging start message\";\n            this.showBandageStart.UseVisualStyleBackColor = true;\n            this.showBandageStart.CheckedChanged += new System.EventHandler(this.ShowBandageStart_CheckedChanged);\n            // \n            // setBandageHue\n            // \n            this.setBandageHue.Location = new System.Drawing.Point(269, 41);\n            this.setBandageHue.Name = \"setBandageHue\";\n            this.setBandageHue.Size = new System.Drawing.Size(67, 23);\n            this.setBandageHue.TabIndex = 57;\n            this.setBandageHue.Text = \"Set Hue\";\n            this.setBandageHue.UseVisualStyleBackColor = true;\n            this.setBandageHue.Click += new System.EventHandler(this.setBandageHue_Click);\n            // \n            // bandageTimerLocation\n            // \n            this.bandageTimerLocation.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.bandageTimerLocation.FormattingEnabled = true;\n            this.bandageTimerLocation.Items.AddRange(new object[] {\n            \"Overhead\",\n            \"System Messages\"});\n            this.bandageTimerLocation.Location = new System.Drawing.Point(145, 10);\n            this.bandageTimerLocation.Name = \"bandageTimerLocation\";\n            this.bandageTimerLocation.Size = new System.Drawing.Size(118, 23);\n            this.bandageTimerLocation.TabIndex = 56;\n            this.bandageTimerLocation.SelectedIndexChanged += new System.EventHandler(this.bandageTimerLocation_SelectedIndexChanged);\n            // \n            // bandageTimerSeconds\n            // \n            this.bandageTimerSeconds.Location = new System.Drawing.Point(180, 71);\n            this.bandageTimerSeconds.Name = \"bandageTimerSeconds\";\n            this.bandageTimerSeconds.Size = new System.Drawing.Size(48, 23);\n            this.bandageTimerSeconds.TabIndex = 55;\n            this.bandageTimerSeconds.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.bandageTimerSeconds.TextChanged += new System.EventHandler(this.bandageTimerSeconds_TextChanged);\n            // \n            // onlyShowBandageTimerSeconds\n            // \n            this.onlyShowBandageTimerSeconds.Location = new System.Drawing.Point(9, 72);\n            this.onlyShowBandageTimerSeconds.Name = \"onlyShowBandageTimerSeconds\";\n            this.onlyShowBandageTimerSeconds.Size = new System.Drawing.Size(205, 20);\n            this.onlyShowBandageTimerSeconds.TabIndex = 53;\n            this.onlyShowBandageTimerSeconds.Text = \"Only show every X seconds:\";\n            this.onlyShowBandageTimerSeconds.CheckedChanged += new System.EventHandler(this.onlyShowBandageTimerSeconds_CheckedChanged);\n            // \n            // bandageTimerFormat\n            // \n            this.bandageTimerFormat.Location = new System.Drawing.Point(113, 41);\n            this.bandageTimerFormat.Name = \"bandageTimerFormat\";\n            this.bandageTimerFormat.Size = new System.Drawing.Size(150, 23);\n            this.bandageTimerFormat.TabIndex = 52;\n            this.bandageTimerFormat.Text = \"Bandage: {count}s\";\n            this.bandageTimerFormat.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.bandageTimerFormat.TextChanged += new System.EventHandler(this.bandageTimerFormat_TextChanged);\n            // \n            // showBandageTimer\n            // \n            this.showBandageTimer.Location = new System.Drawing.Point(9, 11);\n            this.showBandageTimer.Name = \"showBandageTimer\";\n            this.showBandageTimer.Size = new System.Drawing.Size(205, 20);\n            this.showBandageTimer.TabIndex = 51;\n            this.showBandageTimer.Text = \"Show bandage timer\";\n            this.showBandageTimer.CheckedChanged += new System.EventHandler(this.showBandageTimer_CheckedChanged);\n            // \n            // lblBandageCountFormat\n            // \n            this.lblBandageCountFormat.Location = new System.Drawing.Point(21, 41);\n            this.lblBandageCountFormat.Name = \"lblBandageCountFormat\";\n            this.lblBandageCountFormat.Size = new System.Drawing.Size(159, 23);\n            this.lblBandageCountFormat.TabIndex = 54;\n            this.lblBandageCountFormat.Text = \"Format && Hue:\";\n            this.lblBandageCountFormat.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // subOverheadTab\n            // \n            this.subOverheadTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subOverheadTab.Controls.Add(this.setSound);\n            this.subOverheadTab.Controls.Add(this.label14);\n            this.subOverheadTab.Controls.Add(this.unicodeStyle);\n            this.subOverheadTab.Controls.Add(this.asciiStyle);\n            this.subOverheadTab.Controls.Add(this.editOverheadMessage);\n            this.subOverheadTab.Controls.Add(this.setColorHue);\n            this.subOverheadTab.Controls.Add(this.removeOverheadMessage);\n            this.subOverheadTab.Controls.Add(this.label13);\n            this.subOverheadTab.Controls.Add(this.overheadFormat);\n            this.subOverheadTab.Controls.Add(this.setOverheadMessage);\n            this.subOverheadTab.Controls.Add(this.cliLocOverheadView);\n            this.subOverheadTab.Controls.Add(this.cliLocSearch);\n            this.subOverheadTab.Controls.Add(this.cliLocTextSearch);\n            this.subOverheadTab.Controls.Add(this.lblOhSearch);\n            this.subOverheadTab.Controls.Add(this.cliLocSearchView);\n            this.subOverheadTab.Controls.Add(this.showOverheadMessages);\n            this.subOverheadTab.Location = new System.Drawing.Point(4, 22);\n            this.subOverheadTab.Name = \"subOverheadTab\";\n            this.subOverheadTab.Size = new System.Drawing.Size(502, 288);\n            this.subOverheadTab.TabIndex = 3;\n            this.subOverheadTab.Text = \"Overhead Messages\";\n            // \n            // setSound\n            // \n            this.setSound.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.setSound.Location = new System.Drawing.Point(8, 237);\n            this.setSound.Name = \"setSound\";\n            this.setSound.Size = new System.Drawing.Size(84, 28);\n            this.setSound.TabIndex = 103;\n            this.setSound.Text = \"Set Sound\";\n            this.setSound.UseVisualStyleBackColor = true;\n            this.setSound.Click += new System.EventHandler(this.setSound_Click);\n            // \n            // label14\n            // \n            this.label14.AutoSize = true;\n            this.label14.Location = new System.Drawing.Point(5, 83);\n            this.label14.Name = \"label14\";\n            this.label14.Size = new System.Drawing.Size(84, 15);\n            this.label14.TabIndex = 102;\n            this.label14.Text = \"Message Style:\";\n            // \n            // unicodeStyle\n            // \n            this.unicodeStyle.AutoSize = true;\n            this.unicodeStyle.Location = new System.Drawing.Point(8, 101);\n            this.unicodeStyle.Name = \"unicodeStyle\";\n            this.unicodeStyle.Size = new System.Drawing.Size(69, 19);\n            this.unicodeStyle.TabIndex = 101;\n            this.unicodeStyle.TabStop = true;\n            this.unicodeStyle.Text = \"Unicode\";\n            this.unicodeStyle.UseVisualStyleBackColor = true;\n            this.unicodeStyle.CheckedChanged += new System.EventHandler(this.unicodeStyle_CheckedChanged);\n            // \n            // asciiStyle\n            // \n            this.asciiStyle.AutoSize = true;\n            this.asciiStyle.Location = new System.Drawing.Point(8, 126);\n            this.asciiStyle.Name = \"asciiStyle\";\n            this.asciiStyle.Size = new System.Drawing.Size(53, 19);\n            this.asciiStyle.TabIndex = 100;\n            this.asciiStyle.TabStop = true;\n            this.asciiStyle.Text = \"ASCII\";\n            this.asciiStyle.UseVisualStyleBackColor = true;\n            this.asciiStyle.CheckedChanged += new System.EventHandler(this.asciiStyle_CheckedChanged);\n            // \n            // editOverheadMessage\n            // \n            this.editOverheadMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.editOverheadMessage.Location = new System.Drawing.Point(8, 135);\n            this.editOverheadMessage.Name = \"editOverheadMessage\";\n            this.editOverheadMessage.Size = new System.Drawing.Size(84, 28);\n            this.editOverheadMessage.TabIndex = 97;\n            this.editOverheadMessage.Text = \"Edit\";\n            this.editOverheadMessage.UseVisualStyleBackColor = true;\n            this.editOverheadMessage.Click += new System.EventHandler(this.editOverheadMessage_Click);\n            // \n            // setColorHue\n            // \n            this.setColorHue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.setColorHue.Location = new System.Drawing.Point(8, 203);\n            this.setColorHue.Name = \"setColorHue\";\n            this.setColorHue.Size = new System.Drawing.Size(84, 28);\n            this.setColorHue.TabIndex = 96;\n            this.setColorHue.Text = \"Set Hue\";\n            this.setColorHue.UseVisualStyleBackColor = true;\n            this.setColorHue.Click += new System.EventHandler(this.setColorHue_Click);\n            // \n            // removeOverheadMessage\n            // \n            this.removeOverheadMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.removeOverheadMessage.Location = new System.Drawing.Point(8, 169);\n            this.removeOverheadMessage.Name = \"removeOverheadMessage\";\n            this.removeOverheadMessage.Size = new System.Drawing.Size(84, 28);\n            this.removeOverheadMessage.TabIndex = 95;\n            this.removeOverheadMessage.Text = \"Remove\";\n            this.removeOverheadMessage.UseVisualStyleBackColor = true;\n            this.removeOverheadMessage.Click += new System.EventHandler(this.removeOverheadMessage_Click);\n            // \n            // label13\n            // \n            this.label13.AutoSize = true;\n            this.label13.Location = new System.Drawing.Point(5, 39);\n            this.label13.Name = \"label13\";\n            this.label13.Size = new System.Drawing.Size(48, 15);\n            this.label13.TabIndex = 94;\n            this.label13.Text = \"Format:\";\n            // \n            // overheadFormat\n            // \n            this.overheadFormat.Location = new System.Drawing.Point(8, 57);\n            this.overheadFormat.Name = \"overheadFormat\";\n            this.overheadFormat.Size = new System.Drawing.Size(84, 23);\n            this.overheadFormat.TabIndex = 93;\n            this.overheadFormat.Text = \"[{msg}]\";\n            this.overheadFormat.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.overheadFormat.TextChanged += new System.EventHandler(this.overheadFormat_TextChanged);\n            // \n            // setOverheadMessage\n            // \n            this.setOverheadMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.setOverheadMessage.Location = new System.Drawing.Point(443, 9);\n            this.setOverheadMessage.Name = \"setOverheadMessage\";\n            this.setOverheadMessage.Size = new System.Drawing.Size(56, 24);\n            this.setOverheadMessage.TabIndex = 92;\n            this.setOverheadMessage.Text = \"Add\";\n            this.setOverheadMessage.UseVisualStyleBackColor = true;\n            this.setOverheadMessage.Click += new System.EventHandler(this.setOverheadMessage_Click);\n            // \n            // cliLocOverheadView\n            // \n            this.cliLocOverheadView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.cliLocOverheadView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {\n            this.cliLocOriginal,\n            this.cliLocOverheadMessage,\n            this.cliLocSound});\n            this.cliLocOverheadView.HideSelection = false;\n            this.cliLocOverheadView.Location = new System.Drawing.Point(98, 156);\n            this.cliLocOverheadView.Name = \"cliLocOverheadView\";\n            this.cliLocOverheadView.Size = new System.Drawing.Size(401, 109);\n            this.cliLocOverheadView.TabIndex = 91;\n            this.cliLocOverheadView.UseCompatibleStateImageBehavior = false;\n            this.cliLocOverheadView.View = System.Windows.Forms.View.Details;\n            // \n            // cliLocOriginal\n            // \n            this.cliLocOriginal.Text = \"Original Text\";\n            this.cliLocOriginal.Width = 168;\n            // \n            // cliLocOverheadMessage\n            // \n            this.cliLocOverheadMessage.Text = \"Overhead Message\";\n            this.cliLocOverheadMessage.Width = 181;\n            // \n            // cliLocSound\n            // \n            this.cliLocSound.Text = \"Sound\";\n            this.cliLocSound.Width = 48;\n            // \n            // cliLocSearch\n            // \n            this.cliLocSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.cliLocSearch.Location = new System.Drawing.Point(377, 9);\n            this.cliLocSearch.Name = \"cliLocSearch\";\n            this.cliLocSearch.Size = new System.Drawing.Size(60, 24);\n            this.cliLocSearch.TabIndex = 90;\n            this.cliLocSearch.Text = \"Search\";\n            this.cliLocSearch.UseVisualStyleBackColor = true;\n            this.cliLocSearch.Click += new System.EventHandler(this.cliLocSearch_Click);\n            // \n            // cliLocTextSearch\n            // \n            this.cliLocTextSearch.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.cliLocTextSearch.Location = new System.Drawing.Point(146, 9);\n            this.cliLocTextSearch.Name = \"cliLocTextSearch\";\n            this.cliLocTextSearch.Size = new System.Drawing.Size(225, 23);\n            this.cliLocTextSearch.TabIndex = 89;\n            // \n            // lblOhSearch\n            // \n            this.lblOhSearch.AutoSize = true;\n            this.lblOhSearch.Location = new System.Drawing.Point(95, 12);\n            this.lblOhSearch.Name = \"lblOhSearch\";\n            this.lblOhSearch.Size = new System.Drawing.Size(45, 15);\n            this.lblOhSearch.TabIndex = 88;\n            this.lblOhSearch.Text = \"Search:\";\n            // \n            // cliLocSearchView\n            // \n            this.cliLocSearchView.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.cliLocSearchView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {\n            this.cliLocSearchNumber,\n            this.cliLocSearchText});\n            this.cliLocSearchView.HideSelection = false;\n            this.cliLocSearchView.Location = new System.Drawing.Point(98, 39);\n            this.cliLocSearchView.Name = \"cliLocSearchView\";\n            this.cliLocSearchView.Size = new System.Drawing.Size(401, 111);\n            this.cliLocSearchView.TabIndex = 87;\n            this.cliLocSearchView.UseCompatibleStateImageBehavior = false;\n            this.cliLocSearchView.View = System.Windows.Forms.View.Details;\n            // \n            // cliLocSearchNumber\n            // \n            this.cliLocSearchNumber.Text = \"Number\";\n            this.cliLocSearchNumber.Width = 75;\n            // \n            // cliLocSearchText\n            // \n            this.cliLocSearchText.Text = \"Text\";\n            this.cliLocSearchText.Width = 313;\n            // \n            // showOverheadMessages\n            // \n            this.showOverheadMessages.Location = new System.Drawing.Point(8, 9);\n            this.showOverheadMessages.Name = \"showOverheadMessages\";\n            this.showOverheadMessages.Size = new System.Drawing.Size(71, 24);\n            this.showOverheadMessages.TabIndex = 85;\n            this.showOverheadMessages.Text = \"Enabled\";\n            this.showOverheadMessages.UseVisualStyleBackColor = true;\n            this.showOverheadMessages.CheckedChanged += new System.EventHandler(this.showOverheadMessages_CheckedChanged);\n            // \n            // subWaypoints\n            // \n            this.subWaypoints.BackColor = System.Drawing.SystemColors.Control;\n            this.subWaypoints.Controls.Add(this.waypointOnDeath);\n            this.subWaypoints.Controls.Add(this.lblWaypointTiles);\n            this.subWaypoints.Controls.Add(this.hideWaypointDist);\n            this.subWaypoints.Controls.Add(this.hideWaypointWithin);\n            this.subWaypoints.Controls.Add(this.txtWaypointDistanceSec);\n            this.subWaypoints.Controls.Add(this.lblWaypointSeconds);\n            this.subWaypoints.Controls.Add(this.showWaypointDistance);\n            this.subWaypoints.Controls.Add(this.showWaypointOverhead);\n            this.subWaypoints.Controls.Add(this.btnRemoveSelectedWaypoint);\n            this.subWaypoints.Controls.Add(this.btnHideWaypoint);\n            this.subWaypoints.Controls.Add(this.btnUseCurrentLoc);\n            this.subWaypoints.Controls.Add(this.txtWaypointName);\n            this.subWaypoints.Controls.Add(this.lblWaypointY);\n            this.subWaypoints.Controls.Add(this.lblWaypointX);\n            this.subWaypoints.Controls.Add(this.txtWaypointX);\n            this.subWaypoints.Controls.Add(this.txtWaypointY);\n            this.subWaypoints.Controls.Add(this.lblWaypoint);\n            this.subWaypoints.Controls.Add(this.btnAddWaypoint);\n            this.subWaypoints.Controls.Add(this.waypointList);\n            this.subWaypoints.Location = new System.Drawing.Point(4, 22);\n            this.subWaypoints.Name = \"subWaypoints\";\n            this.subWaypoints.Size = new System.Drawing.Size(502, 288);\n            this.subWaypoints.TabIndex = 4;\n            this.subWaypoints.Text = \"Waypoints\";\n            // \n            // waypointOnDeath\n            // \n            this.waypointOnDeath.AutoSize = true;\n            this.waypointOnDeath.Location = new System.Drawing.Point(184, 87);\n            this.waypointOnDeath.Name = \"waypointOnDeath\";\n            this.waypointOnDeath.Size = new System.Drawing.Size(162, 19);\n            this.waypointOnDeath.TabIndex = 66;\n            this.waypointOnDeath.Text = \"Create waypoint on death\";\n            this.waypointOnDeath.UseVisualStyleBackColor = true;\n            this.waypointOnDeath.CheckedChanged += new System.EventHandler(this.waypointOnDeath_CheckedChanged);\n            // \n            // lblWaypointTiles\n            // \n            this.lblWaypointTiles.Location = new System.Drawing.Point(374, 63);\n            this.lblWaypointTiles.Name = \"lblWaypointTiles\";\n            this.lblWaypointTiles.Size = new System.Drawing.Size(58, 18);\n            this.lblWaypointTiles.TabIndex = 65;\n            this.lblWaypointTiles.Text = \"tiles\";\n            // \n            // hideWaypointDist\n            // \n            this.hideWaypointDist.Location = new System.Drawing.Point(336, 60);\n            this.hideWaypointDist.Name = \"hideWaypointDist\";\n            this.hideWaypointDist.Size = new System.Drawing.Size(32, 23);\n            this.hideWaypointDist.TabIndex = 64;\n            this.hideWaypointDist.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.hideWaypointDist.TextChanged += new System.EventHandler(this.hideWaypointDist_TextChanged);\n            // \n            // hideWaypointWithin\n            // \n            this.hideWaypointWithin.AutoSize = true;\n            this.hideWaypointWithin.Location = new System.Drawing.Point(184, 62);\n            this.hideWaypointWithin.Name = \"hideWaypointWithin\";\n            this.hideWaypointWithin.Size = new System.Drawing.Size(139, 19);\n            this.hideWaypointWithin.TabIndex = 63;\n            this.hideWaypointWithin.Text = \"Hide waypoint within\";\n            this.hideWaypointWithin.UseVisualStyleBackColor = true;\n            this.hideWaypointWithin.CheckedChanged += new System.EventHandler(this.hideWaypointWithin_CheckedChanged);\n            // \n            // txtWaypointDistanceSec\n            // \n            this.txtWaypointDistanceSec.Location = new System.Drawing.Point(336, 35);\n            this.txtWaypointDistanceSec.Name = \"txtWaypointDistanceSec\";\n            this.txtWaypointDistanceSec.Size = new System.Drawing.Size(32, 23);\n            this.txtWaypointDistanceSec.TabIndex = 62;\n            this.txtWaypointDistanceSec.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.txtWaypointDistanceSec.TextChanged += new System.EventHandler(this.txtWaypointDistanceSec_TextChanged);\n            // \n            // lblWaypointSeconds\n            // \n            this.lblWaypointSeconds.Location = new System.Drawing.Point(374, 37);\n            this.lblWaypointSeconds.Name = \"lblWaypointSeconds\";\n            this.lblWaypointSeconds.Size = new System.Drawing.Size(58, 18);\n            this.lblWaypointSeconds.TabIndex = 61;\n            this.lblWaypointSeconds.Text = \"secs\";\n            // \n            // showWaypointDistance\n            // \n            this.showWaypointDistance.AutoSize = true;\n            this.showWaypointDistance.Location = new System.Drawing.Point(184, 37);\n            this.showWaypointDistance.Name = \"showWaypointDistance\";\n            this.showWaypointDistance.Size = new System.Drawing.Size(152, 19);\n            this.showWaypointDistance.TabIndex = 60;\n            this.showWaypointDistance.Text = \"Show tile distance every\";\n            this.showWaypointDistance.UseVisualStyleBackColor = true;\n            this.showWaypointDistance.CheckedChanged += new System.EventHandler(this.showWaypointDistance_CheckedChanged);\n            // \n            // showWaypointOverhead\n            // \n            this.showWaypointOverhead.AutoSize = true;\n            this.showWaypointOverhead.Location = new System.Drawing.Point(184, 12);\n            this.showWaypointOverhead.Name = \"showWaypointOverhead\";\n            this.showWaypointOverhead.Size = new System.Drawing.Size(213, 19);\n            this.showWaypointOverhead.TabIndex = 59;\n            this.showWaypointOverhead.Text = \"Show waypoint messages overhead\";\n            this.showWaypointOverhead.UseVisualStyleBackColor = true;\n            this.showWaypointOverhead.CheckedChanged += new System.EventHandler(this.showWaypointOverhead_CheckedChanged);\n            // \n            // btnRemoveSelectedWaypoint\n            // \n            this.btnRemoveSelectedWaypoint.Location = new System.Drawing.Point(184, 242);\n            this.btnRemoveSelectedWaypoint.Name = \"btnRemoveSelectedWaypoint\";\n            this.btnRemoveSelectedWaypoint.Size = new System.Drawing.Size(135, 29);\n            this.btnRemoveSelectedWaypoint.TabIndex = 10;\n            this.btnRemoveSelectedWaypoint.Text = \"Remove Selected\";\n            this.btnRemoveSelectedWaypoint.UseVisualStyleBackColor = true;\n            this.btnRemoveSelectedWaypoint.Click += new System.EventHandler(this.btnRemoveSelectedWaypoint_Click);\n            // \n            // btnHideWaypoint\n            // \n            this.btnHideWaypoint.Location = new System.Drawing.Point(364, 242);\n            this.btnHideWaypoint.Name = \"btnHideWaypoint\";\n            this.btnHideWaypoint.Size = new System.Drawing.Size(129, 29);\n            this.btnHideWaypoint.TabIndex = 9;\n            this.btnHideWaypoint.Text = \"Clear Waypoint\";\n            this.btnHideWaypoint.UseVisualStyleBackColor = true;\n            this.btnHideWaypoint.Click += new System.EventHandler(this.btnHideWaypoint_Click);\n            // \n            // btnUseCurrentLoc\n            // \n            this.btnUseCurrentLoc.Location = new System.Drawing.Point(364, 151);\n            this.btnUseCurrentLoc.Name = \"btnUseCurrentLoc\";\n            this.btnUseCurrentLoc.Size = new System.Drawing.Size(129, 23);\n            this.btnUseCurrentLoc.TabIndex = 8;\n            this.btnUseCurrentLoc.Text = \"Use Current Position\";\n            this.btnUseCurrentLoc.UseVisualStyleBackColor = true;\n            this.btnUseCurrentLoc.Click += new System.EventHandler(this.btnUseCurrentLoc_Click);\n            // \n            // txtWaypointName\n            // \n            this.txtWaypointName.Location = new System.Drawing.Point(229, 121);\n            this.txtWaypointName.Name = \"txtWaypointName\";\n            this.txtWaypointName.Size = new System.Drawing.Size(129, 23);\n            this.txtWaypointName.TabIndex = 7;\n            // \n            // lblWaypointY\n            // \n            this.lblWaypointY.AutoSize = true;\n            this.lblWaypointY.Location = new System.Drawing.Point(285, 154);\n            this.lblWaypointY.Name = \"lblWaypointY\";\n            this.lblWaypointY.Size = new System.Drawing.Size(17, 15);\n            this.lblWaypointY.TabIndex = 6;\n            this.lblWaypointY.Text = \"Y:\";\n            // \n            // lblWaypointX\n            // \n            this.lblWaypointX.AutoSize = true;\n            this.lblWaypointX.Location = new System.Drawing.Point(206, 154);\n            this.lblWaypointX.Name = \"lblWaypointX\";\n            this.lblWaypointX.Size = new System.Drawing.Size(17, 15);\n            this.lblWaypointX.TabIndex = 5;\n            this.lblWaypointX.Text = \"X:\";\n            // \n            // txtWaypointX\n            // \n            this.txtWaypointX.Location = new System.Drawing.Point(229, 151);\n            this.txtWaypointX.Name = \"txtWaypointX\";\n            this.txtWaypointX.Size = new System.Drawing.Size(50, 23);\n            this.txtWaypointX.TabIndex = 4;\n            // \n            // txtWaypointY\n            // \n            this.txtWaypointY.Location = new System.Drawing.Point(308, 151);\n            this.txtWaypointY.Name = \"txtWaypointY\";\n            this.txtWaypointY.Size = new System.Drawing.Size(50, 23);\n            this.txtWaypointY.TabIndex = 3;\n            // \n            // lblWaypoint\n            // \n            this.lblWaypoint.AutoSize = true;\n            this.lblWaypoint.Location = new System.Drawing.Point(181, 124);\n            this.lblWaypoint.Name = \"lblWaypoint\";\n            this.lblWaypoint.Size = new System.Drawing.Size(42, 15);\n            this.lblWaypoint.TabIndex = 2;\n            this.lblWaypoint.Text = \"Name:\";\n            // \n            // btnAddWaypoint\n            // \n            this.btnAddWaypoint.Location = new System.Drawing.Point(364, 121);\n            this.btnAddWaypoint.Name = \"btnAddWaypoint\";\n            this.btnAddWaypoint.Size = new System.Drawing.Size(129, 24);\n            this.btnAddWaypoint.TabIndex = 1;\n            this.btnAddWaypoint.Text = \"Add Waypoint\";\n            this.btnAddWaypoint.UseVisualStyleBackColor = true;\n            this.btnAddWaypoint.Click += new System.EventHandler(this.btnAddWaypoint_Click);\n            // \n            // waypointList\n            // \n            this.waypointList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.waypointList.FormattingEnabled = true;\n            this.waypointList.ItemHeight = 15;\n            this.waypointList.Location = new System.Drawing.Point(11, 12);\n            this.waypointList.Name = \"waypointList\";\n            this.waypointList.Size = new System.Drawing.Size(164, 154);\n            this.waypointList.TabIndex = 0;\n            this.waypointList.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.listWaypoints_MouseDoubleClick);\n            this.waypointList.MouseDown += new System.Windows.Forms.MouseEventHandler(this.listWaypoints_MouseDown);\n            // \n            // subBuffsDebuffs\n            // \n            this.subBuffsDebuffs.BackColor = System.Drawing.SystemColors.Control;\n            this.subBuffsDebuffs.Controls.Add(this.cooldownGumpBox);\n            this.subBuffsDebuffs.Controls.Add(this.buffBarGroupBox);\n            this.subBuffsDebuffs.Controls.Add(this.buffDebuffOptions);\n            this.subBuffsDebuffs.Controls.Add(this.showBuffDebuffOverhead);\n            this.subBuffsDebuffs.Location = new System.Drawing.Point(4, 24);\n            this.subBuffsDebuffs.Name = \"subBuffsDebuffs\";\n            this.subBuffsDebuffs.Size = new System.Drawing.Size(502, 286);\n            this.subBuffsDebuffs.TabIndex = 5;\n            this.subBuffsDebuffs.Text = \"Buffs / Cooldowns\";\n            // \n            // buffBarGroupBox\n            // \n            this.buffBarGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.buffBarGroupBox.Controls.Add(this.showBuffDebuffTimeType);\n            this.buffBarGroupBox.Controls.Add(this.lblShowBuffTime);\n            this.buffBarGroupBox.Controls.Add(this.useBlackBuffDebuffBg);\n            this.buffBarGroupBox.Controls.Add(this.buffBarHeight);\n            this.buffBarGroupBox.Controls.Add(this.lblBuffBarHeight);\n            this.buffBarGroupBox.Controls.Add(this.buffBarSort);\n            this.buffBarGroupBox.Controls.Add(this.lblBuffSortBy);\n            this.buffBarGroupBox.Controls.Add(this.buffBarWidth);\n            this.buffBarGroupBox.Controls.Add(this.lblBuffBarWidth);\n            this.buffBarGroupBox.Controls.Add(this.showBuffIcons);\n            this.buffBarGroupBox.Controls.Add(this.showBuffDebuffGump);\n            this.buffBarGroupBox.Location = new System.Drawing.Point(252, 12);\n            this.buffBarGroupBox.Name = \"buffBarGroupBox\";\n            this.buffBarGroupBox.Size = new System.Drawing.Size(235, 263);\n            this.buffBarGroupBox.TabIndex = 132;\n            this.buffBarGroupBox.TabStop = false;\n            this.buffBarGroupBox.Text = \"Buff/Debuff Gump:\";\n            // \n            // showBuffDebuffTimeType\n            // \n            this.showBuffDebuffTimeType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.showBuffDebuffTimeType.FormattingEnabled = true;\n            this.showBuffDebuffTimeType.Items.AddRange(new object[] {\n            \"Next to name\",\n            \"Outside of bar\",\n            \"Right side of bar\",\n            \"Under Icon\",\n            \"None\"});\n            this.showBuffDebuffTimeType.Location = new System.Drawing.Point(84, 112);\n            this.showBuffDebuffTimeType.Name = \"showBuffDebuffTimeType\";\n            this.showBuffDebuffTimeType.Size = new System.Drawing.Size(126, 23);\n            this.showBuffDebuffTimeType.TabIndex = 12;\n            this.showBuffDebuffTimeType.SelectedIndexChanged += new System.EventHandler(this.showBuffDebuffTimeType_SelectedIndexChanged);\n            // \n            // lblShowBuffTime\n            // \n            this.lblShowBuffTime.AutoSize = true;\n            this.lblShowBuffTime.Location = new System.Drawing.Point(12, 115);\n            this.lblShowBuffTime.Name = \"lblShowBuffTime\";\n            this.lblShowBuffTime.Size = new System.Drawing.Size(66, 15);\n            this.lblShowBuffTime.TabIndex = 11;\n            this.lblShowBuffTime.Text = \"Show time:\";\n            // \n            // useBlackBuffDebuffBg\n            // \n            this.useBlackBuffDebuffBg.AutoSize = true;\n            this.useBlackBuffDebuffBg.Location = new System.Drawing.Point(15, 87);\n            this.useBlackBuffDebuffBg.Name = \"useBlackBuffDebuffBg\";\n            this.useBlackBuffDebuffBg.Size = new System.Drawing.Size(143, 19);\n            this.useBlackBuffDebuffBg.TabIndex = 9;\n            this.useBlackBuffDebuffBg.Text = \"Use black background\";\n            this.useBlackBuffDebuffBg.UseVisualStyleBackColor = true;\n            this.useBlackBuffDebuffBg.CheckedChanged += new System.EventHandler(this.useBlackBuffDebuffBg_CheckedChanged);\n            // \n            // buffBarHeight\n            // \n            this.buffBarHeight.Location = new System.Drawing.Point(78, 159);\n            this.buffBarHeight.Name = \"buffBarHeight\";\n            this.buffBarHeight.Size = new System.Drawing.Size(36, 23);\n            this.buffBarHeight.TabIndex = 8;\n            this.buffBarHeight.TextChanged += new System.EventHandler(this.buffBarHeight_TextChanged);\n            // \n            // lblBuffBarHeight\n            // \n            this.lblBuffBarHeight.AutoSize = true;\n            this.lblBuffBarHeight.Location = new System.Drawing.Point(12, 162);\n            this.lblBuffBarHeight.Name = \"lblBuffBarHeight\";\n            this.lblBuffBarHeight.Size = new System.Drawing.Size(64, 15);\n            this.lblBuffBarHeight.TabIndex = 7;\n            this.lblBuffBarHeight.Text = \"Bar height:\";\n            // \n            // buffBarSort\n            // \n            this.buffBarSort.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.buffBarSort.FormattingEnabled = true;\n            this.buffBarSort.Items.AddRange(new object[] {\n            \"Alphabetical (A-Z)\",\n            \"Ascending by time\",\n            \"Descending by time\"});\n            this.buffBarSort.Location = new System.Drawing.Point(65, 223);\n            this.buffBarSort.Name = \"buffBarSort\";\n            this.buffBarSort.Size = new System.Drawing.Size(145, 23);\n            this.buffBarSort.TabIndex = 6;\n            this.buffBarSort.SelectedIndexChanged += new System.EventHandler(this.buffBarSort_SelectedIndexChanged);\n            // \n            // lblBuffSortBy\n            // \n            this.lblBuffSortBy.AutoSize = true;\n            this.lblBuffSortBy.Location = new System.Drawing.Point(12, 226);\n            this.lblBuffSortBy.Name = \"lblBuffSortBy\";\n            this.lblBuffSortBy.Size = new System.Drawing.Size(47, 15);\n            this.lblBuffSortBy.TabIndex = 5;\n            this.lblBuffSortBy.Text = \"Sort by:\";\n            // \n            // buffBarWidth\n            // \n            this.buffBarWidth.Location = new System.Drawing.Point(78, 187);\n            this.buffBarWidth.Name = \"buffBarWidth\";\n            this.buffBarWidth.Size = new System.Drawing.Size(36, 23);\n            this.buffBarWidth.TabIndex = 4;\n            this.buffBarWidth.TextChanged += new System.EventHandler(this.buffBarWidth_TextChanged);\n            // \n            // lblBuffBarWidth\n            // \n            this.lblBuffBarWidth.AutoSize = true;\n            this.lblBuffBarWidth.Location = new System.Drawing.Point(12, 190);\n            this.lblBuffBarWidth.Name = \"lblBuffBarWidth\";\n            this.lblBuffBarWidth.Size = new System.Drawing.Size(60, 15);\n            this.lblBuffBarWidth.TabIndex = 3;\n            this.lblBuffBarWidth.Text = \"Bar width:\";\n            // \n            // showBuffIcons\n            // \n            this.showBuffIcons.AutoSize = true;\n            this.showBuffIcons.Location = new System.Drawing.Point(15, 62);\n            this.showBuffIcons.Name = \"showBuffIcons\";\n            this.showBuffIcons.Size = new System.Drawing.Size(151, 19);\n            this.showBuffIcons.TabIndex = 1;\n            this.showBuffIcons.Text = \"Show buff/debuff icons\";\n            this.showBuffIcons.UseVisualStyleBackColor = true;\n            this.showBuffIcons.CheckedChanged += new System.EventHandler(this.showBuffIcons_CheckedChanged);\n            // \n            // showBuffDebuffGump\n            // \n            this.showBuffDebuffGump.AutoSize = true;\n            this.showBuffDebuffGump.Location = new System.Drawing.Point(15, 22);\n            this.showBuffDebuffGump.Name = \"showBuffDebuffGump\";\n            this.showBuffDebuffGump.Size = new System.Drawing.Size(155, 19);\n            this.showBuffDebuffGump.TabIndex = 0;\n            this.showBuffDebuffGump.Text = \"Show buff/debuff gump\";\n            this.showBuffDebuffGump.UseVisualStyleBackColor = true;\n            this.showBuffDebuffGump.CheckedChanged += new System.EventHandler(this.showBuffDebuffGump_CheckedChanged);\n            // \n            // buffDebuffOptions\n            // \n            this.buffDebuffOptions.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.buffDebuffOptions.Location = new System.Drawing.Point(26, 37);\n            this.buffDebuffOptions.Name = \"buffDebuffOptions\";\n            this.buffDebuffOptions.Size = new System.Drawing.Size(140, 30);\n            this.buffDebuffOptions.TabIndex = 131;\n            this.buffDebuffOptions.Text = \"Buff / Debuff Options\";\n            this.buffDebuffOptions.UseVisualStyleBackColor = true;\n            this.buffDebuffOptions.Click += new System.EventHandler(this.buffDebuffOptions_Click);\n            // \n            // showBuffDebuffOverhead\n            // \n            this.showBuffDebuffOverhead.AutoSize = true;\n            this.showBuffDebuffOverhead.Location = new System.Drawing.Point(14, 12);\n            this.showBuffDebuffOverhead.Name = \"showBuffDebuffOverhead\";\n            this.showBuffDebuffOverhead.Size = new System.Drawing.Size(172, 19);\n            this.showBuffDebuffOverhead.TabIndex = 130;\n            this.showBuffDebuffOverhead.Text = \"Show buff/debuff overhead\";\n            this.showBuffDebuffOverhead.UseVisualStyleBackColor = true;\n            this.showBuffDebuffOverhead.CheckedChanged += new System.EventHandler(this.showBuffDebuffOverhead_CheckedChanged);\n            // \n            // dressTab\n            // \n            this.dressTab.Controls.Add(this.groupBox6);\n            this.dressTab.Controls.Add(this.groupBox5);\n            this.dressTab.Location = new System.Drawing.Point(4, 24);\n            this.dressTab.Name = \"dressTab\";\n            this.dressTab.Size = new System.Drawing.Size(519, 342);\n            this.dressTab.TabIndex = 3;\n            this.dressTab.Text = \"Arm/Dress\";\n            // \n            // groupBox6\n            // \n            this.groupBox6.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.groupBox6.Controls.Add(this.clearDress);\n            this.groupBox6.Controls.Add(this.dressDelSel);\n            this.groupBox6.Controls.Add(this.undressBag);\n            this.groupBox6.Controls.Add(this.undressList);\n            this.groupBox6.Controls.Add(this.dressUseCur);\n            this.groupBox6.Controls.Add(this.targItem);\n            this.groupBox6.Controls.Add(this.dressItems);\n            this.groupBox6.Controls.Add(this.dressNow);\n            this.groupBox6.Location = new System.Drawing.Point(201, 3);\n            this.groupBox6.Name = \"groupBox6\";\n            this.groupBox6.Size = new System.Drawing.Size(311, 329);\n            this.groupBox6.TabIndex = 7;\n            this.groupBox6.TabStop = false;\n            this.groupBox6.Text = \"Arm/Dress Items\";\n            // \n            // clearDress\n            // \n            this.clearDress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.clearDress.Location = new System.Drawing.Point(209, 257);\n            this.clearDress.Name = \"clearDress\";\n            this.clearDress.Size = new System.Drawing.Size(96, 32);\n            this.clearDress.TabIndex = 13;\n            this.clearDress.Text = \"Clear List\";\n            this.clearDress.Click += new System.EventHandler(this.clearDress_Click);\n            // \n            // dressDelSel\n            // \n            this.dressDelSel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.dressDelSel.Location = new System.Drawing.Point(209, 170);\n            this.dressDelSel.Name = \"dressDelSel\";\n            this.dressDelSel.Size = new System.Drawing.Size(96, 32);\n            this.dressDelSel.TabIndex = 12;\n            this.dressDelSel.Text = \"Remove\";\n            this.dressDelSel.Click += new System.EventHandler(this.dressDelSel_Click);\n            // \n            // undressBag\n            // \n            this.undressBag.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.undressBag.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.undressBag.Location = new System.Drawing.Point(209, 208);\n            this.undressBag.Name = \"undressBag\";\n            this.undressBag.Size = new System.Drawing.Size(96, 40);\n            this.undressBag.TabIndex = 11;\n            this.undressBag.Text = \"Change Undress Bag\";\n            this.undressBag.Click += new System.EventHandler(this.undressBag_Click);\n            // \n            // undressList\n            // \n            this.undressList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.undressList.Location = new System.Drawing.Point(209, 56);\n            this.undressList.Name = \"undressList\";\n            this.undressList.Size = new System.Drawing.Size(96, 32);\n            this.undressList.TabIndex = 10;\n            this.undressList.Text = \"Undress\";\n            this.undressList.Click += new System.EventHandler(this.undressList_Click);\n            // \n            // dressUseCur\n            // \n            this.dressUseCur.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.dressUseCur.Location = new System.Drawing.Point(209, 132);\n            this.dressUseCur.Name = \"dressUseCur\";\n            this.dressUseCur.Size = new System.Drawing.Size(96, 32);\n            this.dressUseCur.TabIndex = 9;\n            this.dressUseCur.Text = \"Add Current\";\n            this.dressUseCur.Click += new System.EventHandler(this.dressUseCur_Click);\n            // \n            // targItem\n            // \n            this.targItem.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.targItem.Location = new System.Drawing.Point(209, 94);\n            this.targItem.Name = \"targItem\";\n            this.targItem.Size = new System.Drawing.Size(96, 32);\n            this.targItem.TabIndex = 7;\n            this.targItem.Text = \"Add (Target)\";\n            this.targItem.Click += new System.EventHandler(this.targItem_Click);\n            // \n            // dressItems\n            // \n            this.dressItems.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.dressItems.IntegralHeight = false;\n            this.dressItems.ItemHeight = 15;\n            this.dressItems.Location = new System.Drawing.Point(6, 18);\n            this.dressItems.Name = \"dressItems\";\n            this.dressItems.Size = new System.Drawing.Size(197, 305);\n            this.dressItems.TabIndex = 6;\n            this.dressItems.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dressItems_KeyDown);\n            this.dressItems.MouseDown += new System.Windows.Forms.MouseEventHandler(this.dressItems_MouseDown);\n            // \n            // dressNow\n            // \n            this.dressNow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.dressNow.Location = new System.Drawing.Point(209, 18);\n            this.dressNow.Name = \"dressNow\";\n            this.dressNow.Size = new System.Drawing.Size(96, 32);\n            this.dressNow.TabIndex = 6;\n            this.dressNow.Text = \"Dress\";\n            this.dressNow.Click += new System.EventHandler(this.dressNow_Click);\n            // \n            // groupBox5\n            // \n            this.groupBox5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.groupBox5.Controls.Add(this.removeDress);\n            this.groupBox5.Controls.Add(this.addDress);\n            this.groupBox5.Controls.Add(this.dressList);\n            this.groupBox5.Controls.Add(this.undressConflicts);\n            this.groupBox5.Location = new System.Drawing.Point(8, 3);\n            this.groupBox5.Name = \"groupBox5\";\n            this.groupBox5.Size = new System.Drawing.Size(187, 329);\n            this.groupBox5.TabIndex = 6;\n            this.groupBox5.TabStop = false;\n            this.groupBox5.Text = \"Arm/Dress Selection\";\n            // \n            // removeDress\n            // \n            this.removeDress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.removeDress.Location = new System.Drawing.Point(121, 274);\n            this.removeDress.Name = \"removeDress\";\n            this.removeDress.Size = new System.Drawing.Size(60, 25);\n            this.removeDress.TabIndex = 5;\n            this.removeDress.Text = \"Remove\";\n            this.removeDress.Click += new System.EventHandler(this.removeDress_Click);\n            // \n            // addDress\n            // \n            this.addDress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.addDress.Location = new System.Drawing.Point(6, 274);\n            this.addDress.Name = \"addDress\";\n            this.addDress.Size = new System.Drawing.Size(60, 25);\n            this.addDress.TabIndex = 4;\n            this.addDress.Text = \"Add...\";\n            this.addDress.Click += new System.EventHandler(this.addDress_Click);\n            // \n            // dressList\n            // \n            this.dressList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.dressList.IntegralHeight = false;\n            this.dressList.ItemHeight = 15;\n            this.dressList.Location = new System.Drawing.Point(6, 18);\n            this.dressList.Name = \"dressList\";\n            this.dressList.Size = new System.Drawing.Size(175, 250);\n            this.dressList.TabIndex = 3;\n            this.dressList.SelectedIndexChanged += new System.EventHandler(this.dressList_SelectedIndexChanged);\n            // \n            // undressConflicts\n            // \n            this.undressConflicts.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.undressConflicts.Location = new System.Drawing.Point(6, 305);\n            this.undressConflicts.Name = \"undressConflicts\";\n            this.undressConflicts.Size = new System.Drawing.Size(137, 18);\n            this.undressConflicts.TabIndex = 6;\n            this.undressConflicts.Text = \"Auto-move conflicts\";\n            this.undressConflicts.CheckedChanged += new System.EventHandler(this.undressConflicts_CheckedChanged);\n            // \n            // skillsTab\n            // \n            this.skillsTab.Controls.Add(this.captureMibs);\n            this.skillsTab.Controls.Add(this.dispDeltaOverhead);\n            this.skillsTab.Controls.Add(this.logSkillChanges);\n            this.skillsTab.Controls.Add(this.dispDelta);\n            this.skillsTab.Controls.Add(this.skillCopyAll);\n            this.skillsTab.Controls.Add(this.skillCopySel);\n            this.skillsTab.Controls.Add(this.baseTotal);\n            this.skillsTab.Controls.Add(this.label1);\n            this.skillsTab.Controls.Add(this.locks);\n            this.skillsTab.Controls.Add(this.setlocks);\n            this.skillsTab.Controls.Add(this.resetDelta);\n            this.skillsTab.Controls.Add(this.skillList);\n            this.skillsTab.Location = new System.Drawing.Point(4, 24);\n            this.skillsTab.Name = \"skillsTab\";\n            this.skillsTab.Size = new System.Drawing.Size(519, 342);\n            this.skillsTab.TabIndex = 2;\n            this.skillsTab.Text = \"Skills\";\n            // \n            // captureMibs\n            // \n            this.captureMibs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.captureMibs.Location = new System.Drawing.Point(356, 230);\n            this.captureMibs.Name = \"captureMibs\";\n            this.captureMibs.Size = new System.Drawing.Size(153, 19);\n            this.captureMibs.TabIndex = 70;\n            this.captureMibs.Text = \"Capture MIBs to file\";\n            this.captureMibs.UseVisualStyleBackColor = true;\n            this.captureMibs.CheckedChanged += new System.EventHandler(this.captureMibs_CheckedChanged);\n            // \n            // dispDeltaOverhead\n            // \n            this.dispDeltaOverhead.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.dispDeltaOverhead.AutoSize = true;\n            this.dispDeltaOverhead.Font = new System.Drawing.Font(\"Segoe UI\", 8.25F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.dispDeltaOverhead.Location = new System.Drawing.Point(441, 207);\n            this.dispDeltaOverhead.Name = \"dispDeltaOverhead\";\n            this.dispDeltaOverhead.Size = new System.Drawing.Size(71, 17);\n            this.dispDeltaOverhead.TabIndex = 14;\n            this.dispDeltaOverhead.Text = \"Overhead\";\n            this.dispDeltaOverhead.UseVisualStyleBackColor = true;\n            this.dispDeltaOverhead.CheckedChanged += new System.EventHandler(this.dispDeltaOverhead_CheckedChanged);\n            // \n            // logSkillChanges\n            // \n            this.logSkillChanges.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.logSkillChanges.Location = new System.Drawing.Point(356, 157);\n            this.logSkillChanges.Name = \"logSkillChanges\";\n            this.logSkillChanges.Size = new System.Drawing.Size(156, 19);\n            this.logSkillChanges.TabIndex = 13;\n            this.logSkillChanges.Text = \"Log skill changes\";\n            this.logSkillChanges.UseVisualStyleBackColor = true;\n            this.logSkillChanges.CheckedChanged += new System.EventHandler(this.logSkillChanges_CheckedChanged);\n            // \n            // dispDelta\n            // \n            this.dispDelta.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.dispDelta.Location = new System.Drawing.Point(356, 182);\n            this.dispDelta.Name = \"dispDelta\";\n            this.dispDelta.Size = new System.Drawing.Size(156, 19);\n            this.dispDelta.TabIndex = 11;\n            this.dispDelta.Text = \"Show skill/stat changes\";\n            this.dispDelta.CheckedChanged += new System.EventHandler(this.dispDelta_CheckedChanged);\n            // \n            // skillCopyAll\n            // \n            this.skillCopyAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.skillCopyAll.Location = new System.Drawing.Point(356, 119);\n            this.skillCopyAll.Name = \"skillCopyAll\";\n            this.skillCopyAll.Size = new System.Drawing.Size(156, 32);\n            this.skillCopyAll.TabIndex = 9;\n            this.skillCopyAll.Text = \"Copy All\";\n            this.skillCopyAll.Click += new System.EventHandler(this.skillCopyAll_Click);\n            // \n            // skillCopySel\n            // \n            this.skillCopySel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.skillCopySel.Location = new System.Drawing.Point(356, 81);\n            this.skillCopySel.Name = \"skillCopySel\";\n            this.skillCopySel.Size = new System.Drawing.Size(156, 32);\n            this.skillCopySel.TabIndex = 8;\n            this.skillCopySel.Text = \"Copy Selected\";\n            this.skillCopySel.Click += new System.EventHandler(this.skillCopySel_Click);\n            // \n            // baseTotal\n            // \n            this.baseTotal.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.baseTotal.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.baseTotal.Location = new System.Drawing.Point(428, 310);\n            this.baseTotal.Name = \"baseTotal\";\n            this.baseTotal.ReadOnly = true;\n            this.baseTotal.Size = new System.Drawing.Size(84, 23);\n            this.baseTotal.TabIndex = 7;\n            this.baseTotal.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            // \n            // label1\n            // \n            this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.label1.Location = new System.Drawing.Point(356, 309);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(75, 23);\n            this.label1.TabIndex = 6;\n            this.label1.Text = \"Base Total:\";\n            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // locks\n            // \n            this.locks.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.locks.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.locks.Items.AddRange(new object[] {\n            \"Up\",\n            \"Down\",\n            \"Locked\"});\n            this.locks.Location = new System.Drawing.Point(468, 49);\n            this.locks.Name = \"locks\";\n            this.locks.Size = new System.Drawing.Size(44, 23);\n            this.locks.TabIndex = 5;\n            // \n            // setlocks\n            // \n            this.setlocks.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.setlocks.Location = new System.Drawing.Point(356, 43);\n            this.setlocks.Name = \"setlocks\";\n            this.setlocks.Size = new System.Drawing.Size(106, 32);\n            this.setlocks.TabIndex = 4;\n            this.setlocks.Text = \"Set all locks:\";\n            this.setlocks.Click += new System.EventHandler(this.OnSetSkillLocks);\n            // \n            // resetDelta\n            // \n            this.resetDelta.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.resetDelta.Location = new System.Drawing.Point(356, 5);\n            this.resetDelta.Name = \"resetDelta\";\n            this.resetDelta.Size = new System.Drawing.Size(156, 32);\n            this.resetDelta.TabIndex = 3;\n            this.resetDelta.Text = \"Reset  +/-\";\n            this.resetDelta.Click += new System.EventHandler(this.OnResetSkillDelta);\n            // \n            // skillList\n            // \n            this.skillList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.skillList.AutoArrange = false;\n            this.skillList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {\n            this.skillHDRName,\n            this.skillHDRvalue,\n            this.skillHDRbase,\n            this.skillHDRdelta,\n            this.skillHDRcap,\n            this.skillHDRlock});\n            this.skillList.FullRowSelect = true;\n            this.skillList.HideSelection = false;\n            this.skillList.Location = new System.Drawing.Point(8, 5);\n            this.skillList.Name = \"skillList\";\n            this.skillList.Size = new System.Drawing.Size(342, 327);\n            this.skillList.TabIndex = 1;\n            this.skillList.UseCompatibleStateImageBehavior = false;\n            this.skillList.View = System.Windows.Forms.View.Details;\n            this.skillList.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.OnSkillColClick);\n            this.skillList.MouseDown += new System.Windows.Forms.MouseEventHandler(this.skillList_MouseDown);\n            // \n            // skillHDRName\n            // \n            this.skillHDRName.Text = \"Skill Name\";\n            this.skillHDRName.Width = 112;\n            // \n            // skillHDRvalue\n            // \n            this.skillHDRvalue.Text = \"Value\";\n            this.skillHDRvalue.Width = 46;\n            // \n            // skillHDRbase\n            // \n            this.skillHDRbase.Text = \"Base\";\n            this.skillHDRbase.Width = 43;\n            // \n            // skillHDRdelta\n            // \n            this.skillHDRdelta.Text = \"+/-\";\n            this.skillHDRdelta.Width = 40;\n            // \n            // skillHDRcap\n            // \n            this.skillHDRcap.Text = \"Cap\";\n            this.skillHDRcap.Width = 40;\n            // \n            // skillHDRlock\n            // \n            this.skillHDRlock.Text = \"Lock\";\n            this.skillHDRlock.Width = 40;\n            // \n            // agentsTab\n            // \n            this.agentsTab.Controls.Add(this.agentSetHotKey);\n            this.agentsTab.Controls.Add(this.agentB6);\n            this.agentsTab.Controls.Add(this.agentB5);\n            this.agentsTab.Controls.Add(this.agentList);\n            this.agentsTab.Controls.Add(this.agentGroup);\n            this.agentsTab.Controls.Add(this.agentB4);\n            this.agentsTab.Controls.Add(this.agentB1);\n            this.agentsTab.Controls.Add(this.agentB2);\n            this.agentsTab.Controls.Add(this.agentB3);\n            this.agentsTab.Location = new System.Drawing.Point(4, 24);\n            this.agentsTab.Name = \"agentsTab\";\n            this.agentsTab.Size = new System.Drawing.Size(519, 342);\n            this.agentsTab.TabIndex = 6;\n            this.agentsTab.Text = \"Agents\";\n            // \n            // agentSetHotKey\n            // \n            this.agentSetHotKey.Location = new System.Drawing.Point(8, 274);\n            this.agentSetHotKey.Name = \"agentSetHotKey\";\n            this.agentSetHotKey.Size = new System.Drawing.Size(130, 32);\n            this.agentSetHotKey.TabIndex = 7;\n            this.agentSetHotKey.Text = \"Set Hot Key\";\n            this.agentSetHotKey.Visible = false;\n            this.agentSetHotKey.Click += new System.EventHandler(this.agentSetHotKey_Click);\n            // \n            // agentB6\n            // \n            this.agentB6.Location = new System.Drawing.Point(8, 231);\n            this.agentB6.Name = \"agentB6\";\n            this.agentB6.Size = new System.Drawing.Size(130, 32);\n            this.agentB6.TabIndex = 6;\n            this.agentB6.Click += new System.EventHandler(this.agentB6_Click);\n            // \n            // agentB5\n            // \n            this.agentB5.Location = new System.Drawing.Point(8, 193);\n            this.agentB5.Name = \"agentB5\";\n            this.agentB5.Size = new System.Drawing.Size(130, 32);\n            this.agentB5.TabIndex = 5;\n            this.agentB5.Click += new System.EventHandler(this.agentB5_Click);\n            // \n            // agentList\n            // \n            this.agentList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.agentList.Location = new System.Drawing.Point(8, 14);\n            this.agentList.Name = \"agentList\";\n            this.agentList.Size = new System.Drawing.Size(130, 23);\n            this.agentList.TabIndex = 2;\n            this.agentList.SelectedIndexChanged += new System.EventHandler(this.agentList_SelectedIndexChanged);\n            this.agentList.MouseDown += new System.Windows.Forms.MouseEventHandler(this.agentList_MouseDown);\n            // \n            // agentGroup\n            // \n            this.agentGroup.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.agentGroup.Controls.Add(this.agentSubList);\n            this.agentGroup.Location = new System.Drawing.Point(144, 3);\n            this.agentGroup.Name = \"agentGroup\";\n            this.agentGroup.Size = new System.Drawing.Size(368, 329);\n            this.agentGroup.TabIndex = 1;\n            this.agentGroup.TabStop = false;\n            // \n            // agentSubList\n            // \n            this.agentSubList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.agentSubList.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.agentSubList.IntegralHeight = false;\n            this.agentSubList.ItemHeight = 15;\n            this.agentSubList.Location = new System.Drawing.Point(6, 22);\n            this.agentSubList.Name = \"agentSubList\";\n            this.agentSubList.Size = new System.Drawing.Size(356, 301);\n            this.agentSubList.TabIndex = 0;\n            this.agentSubList.MouseDown += new System.Windows.Forms.MouseEventHandler(this.agentSubList_MouseDown);\n            // \n            // agentB4\n            // \n            this.agentB4.Location = new System.Drawing.Point(8, 155);\n            this.agentB4.Name = \"agentB4\";\n            this.agentB4.Size = new System.Drawing.Size(130, 32);\n            this.agentB4.TabIndex = 4;\n            this.agentB4.Click += new System.EventHandler(this.agentB4_Click);\n            // \n            // agentB1\n            // \n            this.agentB1.Location = new System.Drawing.Point(8, 41);\n            this.agentB1.Name = \"agentB1\";\n            this.agentB1.Size = new System.Drawing.Size(130, 32);\n            this.agentB1.TabIndex = 1;\n            this.agentB1.Click += new System.EventHandler(this.agentB1_Click);\n            // \n            // agentB2\n            // \n            this.agentB2.Location = new System.Drawing.Point(8, 79);\n            this.agentB2.Name = \"agentB2\";\n            this.agentB2.Size = new System.Drawing.Size(130, 32);\n            this.agentB2.TabIndex = 2;\n            this.agentB2.Click += new System.EventHandler(this.agentB2_Click);\n            // \n            // agentB3\n            // \n            this.agentB3.Location = new System.Drawing.Point(8, 117);\n            this.agentB3.Name = \"agentB3\";\n            this.agentB3.Size = new System.Drawing.Size(130, 32);\n            this.agentB3.TabIndex = 3;\n            this.agentB3.Click += new System.EventHandler(this.agentB3_Click);\n            // \n            // filtersTab\n            // \n            this.filtersTab.BackColor = System.Drawing.SystemColors.Control;\n            this.filtersTab.Controls.Add(this.filterTabs);\n            this.filtersTab.Location = new System.Drawing.Point(4, 24);\n            this.filtersTab.Name = \"filtersTab\";\n            this.filtersTab.Size = new System.Drawing.Size(519, 342);\n            this.filtersTab.TabIndex = 15;\n            this.filtersTab.Text = \"Filters\";\n            // \n            // filterTabs\n            // \n            this.filterTabs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.filterTabs.Controls.Add(this.subFilterTab);\n            this.filterTabs.Controls.Add(this.subFilterText);\n            this.filterTabs.Controls.Add(this.subFilterSoundMusic);\n            this.filterTabs.Controls.Add(this.subFilterTargets);\n            this.filterTabs.Location = new System.Drawing.Point(6, 3);\n            this.filterTabs.Name = \"filterTabs\";\n            this.filterTabs.SelectedIndex = 0;\n            this.filterTabs.Size = new System.Drawing.Size(506, 333);\n            this.filterTabs.TabIndex = 1;\n            this.filterTabs.SelectedIndexChanged += new System.EventHandler(this.filterTabs_IndexChanged);\n            // \n            // subFilterTab\n            // \n            this.subFilterTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subFilterTab.Controls.Add(this.wyrmAnimationList);\n            this.subFilterTab.Controls.Add(this.filterWhiteWyrm);\n            this.subFilterTab.Controls.Add(this.daemonAnimationList);\n            this.subFilterTab.Controls.Add(this.filterDaemonGraphics);\n            this.subFilterTab.Controls.Add(this.drakeAnimationList);\n            this.subFilterTab.Controls.Add(this.filterDrakeGraphics);\n            this.subFilterTab.Controls.Add(this.dragonAnimationList);\n            this.subFilterTab.Controls.Add(this.filterDragonGraphics);\n            this.subFilterTab.Controls.Add(this.filters);\n            this.subFilterTab.Location = new System.Drawing.Point(4, 24);\n            this.subFilterTab.Name = \"subFilterTab\";\n            this.subFilterTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subFilterTab.Size = new System.Drawing.Size(498, 305);\n            this.subFilterTab.TabIndex = 0;\n            this.subFilterTab.Text = \"General\";\n            // \n            // wyrmAnimationList\n            // \n            this.wyrmAnimationList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.wyrmAnimationList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.wyrmAnimationList.DropDownWidth = 250;\n            this.wyrmAnimationList.FormattingEnabled = true;\n            this.wyrmAnimationList.Location = new System.Drawing.Point(313, 93);\n            this.wyrmAnimationList.Name = \"wyrmAnimationList\";\n            this.wyrmAnimationList.Size = new System.Drawing.Size(163, 23);\n            this.wyrmAnimationList.TabIndex = 129;\n            this.wyrmAnimationList.SelectedIndexChanged += new System.EventHandler(this.wyrmAnimationList_SelectedIndexChanged);\n            // \n            // filterWhiteWyrm\n            // \n            this.filterWhiteWyrm.AutoSize = true;\n            this.filterWhiteWyrm.Location = new System.Drawing.Point(209, 95);\n            this.filterWhiteWyrm.Name = \"filterWhiteWyrm\";\n            this.filterWhiteWyrm.Size = new System.Drawing.Size(90, 19);\n            this.filterWhiteWyrm.TabIndex = 128;\n            this.filterWhiteWyrm.Text = \"Filter wyrms\";\n            this.filterWhiteWyrm.UseVisualStyleBackColor = true;\n            this.filterWhiteWyrm.CheckedChanged += new System.EventHandler(this.filterWhiteWyrm_CheckedChanged);\n            // \n            // daemonAnimationList\n            // \n            this.daemonAnimationList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.daemonAnimationList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.daemonAnimationList.DropDownWidth = 250;\n            this.daemonAnimationList.FormattingEnabled = true;\n            this.daemonAnimationList.Location = new System.Drawing.Point(313, 64);\n            this.daemonAnimationList.Name = \"daemonAnimationList\";\n            this.daemonAnimationList.Size = new System.Drawing.Size(163, 23);\n            this.daemonAnimationList.TabIndex = 127;\n            this.daemonAnimationList.SelectedIndexChanged += new System.EventHandler(this.daemonAnimationList_SelectedIndexChanged);\n            // \n            // filterDaemonGraphics\n            // \n            this.filterDaemonGraphics.AutoSize = true;\n            this.filterDaemonGraphics.Location = new System.Drawing.Point(209, 66);\n            this.filterDaemonGraphics.Name = \"filterDaemonGraphics\";\n            this.filterDaemonGraphics.Size = new System.Drawing.Size(104, 19);\n            this.filterDaemonGraphics.TabIndex = 126;\n            this.filterDaemonGraphics.Text = \"Filter daemons\";\n            this.filterDaemonGraphics.UseVisualStyleBackColor = true;\n            this.filterDaemonGraphics.CheckedChanged += new System.EventHandler(this.filterDaemonGraphics_CheckedChanged);\n            // \n            // drakeAnimationList\n            // \n            this.drakeAnimationList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.drakeAnimationList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.drakeAnimationList.DropDownWidth = 250;\n            this.drakeAnimationList.FormattingEnabled = true;\n            this.drakeAnimationList.Location = new System.Drawing.Point(313, 35);\n            this.drakeAnimationList.Name = \"drakeAnimationList\";\n            this.drakeAnimationList.Size = new System.Drawing.Size(163, 23);\n            this.drakeAnimationList.TabIndex = 118;\n            this.drakeAnimationList.SelectedIndexChanged += new System.EventHandler(this.drakeAnimationList_SelectedIndexChanged);\n            // \n            // filterDrakeGraphics\n            // \n            this.filterDrakeGraphics.AutoSize = true;\n            this.filterDrakeGraphics.Location = new System.Drawing.Point(209, 37);\n            this.filterDrakeGraphics.Name = \"filterDrakeGraphics\";\n            this.filterDrakeGraphics.Size = new System.Drawing.Size(89, 19);\n            this.filterDrakeGraphics.TabIndex = 117;\n            this.filterDrakeGraphics.Text = \"Filter drakes\";\n            this.filterDrakeGraphics.UseVisualStyleBackColor = true;\n            this.filterDrakeGraphics.CheckedChanged += new System.EventHandler(this.filterDrakeGraphics_CheckedChanged);\n            // \n            // dragonAnimationList\n            // \n            this.dragonAnimationList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.dragonAnimationList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.dragonAnimationList.DropDownWidth = 250;\n            this.dragonAnimationList.FormattingEnabled = true;\n            this.dragonAnimationList.Location = new System.Drawing.Point(313, 6);\n            this.dragonAnimationList.Name = \"dragonAnimationList\";\n            this.dragonAnimationList.Size = new System.Drawing.Size(163, 23);\n            this.dragonAnimationList.TabIndex = 116;\n            this.dragonAnimationList.SelectedIndexChanged += new System.EventHandler(this.dragonAnimationList_SelectedIndexChanged);\n            // \n            // filterDragonGraphics\n            // \n            this.filterDragonGraphics.AutoSize = true;\n            this.filterDragonGraphics.Location = new System.Drawing.Point(209, 8);\n            this.filterDragonGraphics.Name = \"filterDragonGraphics\";\n            this.filterDragonGraphics.Size = new System.Drawing.Size(98, 19);\n            this.filterDragonGraphics.TabIndex = 115;\n            this.filterDragonGraphics.Text = \"Filter dragons\";\n            this.filterDragonGraphics.UseVisualStyleBackColor = true;\n            this.filterDragonGraphics.CheckedChanged += new System.EventHandler(this.filterDragonGraphics_CheckedChanged);\n            // \n            // filters\n            // \n            this.filters.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.filters.CheckOnClick = true;\n            this.filters.IntegralHeight = false;\n            this.filters.Location = new System.Drawing.Point(6, 6);\n            this.filters.Name = \"filters\";\n            this.filters.Size = new System.Drawing.Size(197, 261);\n            this.filters.TabIndex = 114;\n            this.filters.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.OnFilterCheck);\n            // \n            // subFilterText\n            // \n            this.subFilterText.BackColor = System.Drawing.SystemColors.Control;\n            this.subFilterText.Controls.Add(this.gbFilterText);\n            this.subFilterText.Controls.Add(this.gbFilterMessages);\n            this.subFilterText.Location = new System.Drawing.Point(4, 22);\n            this.subFilterText.Name = \"subFilterText\";\n            this.subFilterText.Size = new System.Drawing.Size(498, 307);\n            this.subFilterText.TabIndex = 4;\n            this.subFilterText.Text = \"Text && Messages  \";\n            // \n            // gbFilterText\n            // \n            this.gbFilterText.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.gbFilterText.Controls.Add(this.removeFilterText);\n            this.gbFilterText.Controls.Add(this.addFilterText);\n            this.gbFilterText.Controls.Add(this.textFilterList);\n            this.gbFilterText.Controls.Add(this.enableTextFilter);\n            this.gbFilterText.Location = new System.Drawing.Point(3, 3);\n            this.gbFilterText.Name = \"gbFilterText\";\n            this.gbFilterText.Size = new System.Drawing.Size(229, 241);\n            this.gbFilterText.TabIndex = 134;\n            this.gbFilterText.TabStop = false;\n            this.gbFilterText.Text = \"Text Filter\";\n            // \n            // removeFilterText\n            // \n            this.removeFilterText.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.removeFilterText.Location = new System.Drawing.Point(148, 206);\n            this.removeFilterText.Name = \"removeFilterText\";\n            this.removeFilterText.Size = new System.Drawing.Size(75, 29);\n            this.removeFilterText.TabIndex = 2;\n            this.removeFilterText.Text = \"Remove\";\n            this.removeFilterText.UseVisualStyleBackColor = true;\n            this.removeFilterText.Click += new System.EventHandler(this.removeFilterText_Click);\n            // \n            // addFilterText\n            // \n            this.addFilterText.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.addFilterText.Location = new System.Drawing.Point(67, 206);\n            this.addFilterText.Name = \"addFilterText\";\n            this.addFilterText.Size = new System.Drawing.Size(75, 29);\n            this.addFilterText.TabIndex = 1;\n            this.addFilterText.Text = \"Add\";\n            this.addFilterText.UseVisualStyleBackColor = true;\n            this.addFilterText.Click += new System.EventHandler(this.addFilterText_Click);\n            // \n            // textFilterList\n            // \n            this.textFilterList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.textFilterList.FormattingEnabled = true;\n            this.textFilterList.ItemHeight = 15;\n            this.textFilterList.Location = new System.Drawing.Point(6, 48);\n            this.textFilterList.Name = \"textFilterList\";\n            this.textFilterList.Size = new System.Drawing.Size(217, 64);\n            this.textFilterList.TabIndex = 0;\n            // \n            // enableTextFilter\n            // \n            this.enableTextFilter.AutoSize = true;\n            this.enableTextFilter.Location = new System.Drawing.Point(6, 22);\n            this.enableTextFilter.Name = \"enableTextFilter\";\n            this.enableTextFilter.Size = new System.Drawing.Size(111, 19);\n            this.enableTextFilter.TabIndex = 3;\n            this.enableTextFilter.Text = \"Enable text filter\";\n            this.enableTextFilter.UseVisualStyleBackColor = true;\n            this.enableTextFilter.CheckedChanged += new System.EventHandler(this.enableTextFilter_CheckedChanged);\n            // \n            // gbFilterMessages\n            // \n            this.gbFilterMessages.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.gbFilterMessages.Controls.Add(this.filterOverheadMessages);\n            this.gbFilterMessages.Controls.Add(this.lblFilterDelaySeconds);\n            this.gbFilterMessages.Controls.Add(this.lblFilterDelay);\n            this.gbFilterMessages.Controls.Add(this.filterDelaySeconds);\n            this.gbFilterMessages.Controls.Add(this.filterRazorMessages);\n            this.gbFilterMessages.Controls.Add(this.filterSystemMessages);\n            this.gbFilterMessages.Controls.Add(this.filterSnoop);\n            this.gbFilterMessages.Location = new System.Drawing.Point(238, 3);\n            this.gbFilterMessages.Name = \"gbFilterMessages\";\n            this.gbFilterMessages.Size = new System.Drawing.Size(257, 241);\n            this.gbFilterMessages.TabIndex = 133;\n            this.gbFilterMessages.TabStop = false;\n            this.gbFilterMessages.Text = \"Filter Messages\";\n            // \n            // filterOverheadMessages\n            // \n            this.filterOverheadMessages.Location = new System.Drawing.Point(6, 100);\n            this.filterOverheadMessages.Name = \"filterOverheadMessages\";\n            this.filterOverheadMessages.Size = new System.Drawing.Size(220, 20);\n            this.filterOverheadMessages.TabIndex = 139;\n            this.filterOverheadMessages.Text = \"Filter repeating overhead messages\";\n            this.filterOverheadMessages.CheckedChanged += new System.EventHandler(this.filterOverheadMessages_CheckedChanged);\n            // \n            // lblFilterDelaySeconds\n            // \n            this.lblFilterDelaySeconds.Location = new System.Drawing.Point(143, 130);\n            this.lblFilterDelaySeconds.Name = \"lblFilterDelaySeconds\";\n            this.lblFilterDelaySeconds.Size = new System.Drawing.Size(59, 18);\n            this.lblFilterDelaySeconds.TabIndex = 138;\n            this.lblFilterDelaySeconds.Text = \"seconds\";\n            // \n            // lblFilterDelay\n            // \n            this.lblFilterDelay.AutoSize = true;\n            this.lblFilterDelay.Location = new System.Drawing.Point(27, 130);\n            this.lblFilterDelay.Name = \"lblFilterDelay\";\n            this.lblFilterDelay.Size = new System.Drawing.Size(68, 15);\n            this.lblFilterDelay.TabIndex = 137;\n            this.lblFilterDelay.Text = \"Filter Delay:\";\n            // \n            // filterDelaySeconds\n            // \n            this.filterDelaySeconds.Location = new System.Drawing.Point(101, 127);\n            this.filterDelaySeconds.Name = \"filterDelaySeconds\";\n            this.filterDelaySeconds.Size = new System.Drawing.Size(36, 23);\n            this.filterDelaySeconds.TabIndex = 136;\n            this.filterDelaySeconds.Text = \"3.5\";\n            this.filterDelaySeconds.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.filterDelaySeconds.TextChanged += new System.EventHandler(this.filterDelaySeconds_TextChanged);\n            // \n            // filterRazorMessages\n            // \n            this.filterRazorMessages.Location = new System.Drawing.Point(6, 74);\n            this.filterRazorMessages.Name = \"filterRazorMessages\";\n            this.filterRazorMessages.Size = new System.Drawing.Size(220, 20);\n            this.filterRazorMessages.TabIndex = 135;\n            this.filterRazorMessages.Text = \"Filter repeating Razor messages\";\n            this.filterRazorMessages.CheckedChanged += new System.EventHandler(this.filterRazorMessages_CheckedChanged);\n            // \n            // filterSystemMessages\n            // \n            this.filterSystemMessages.Location = new System.Drawing.Point(6, 48);\n            this.filterSystemMessages.Name = \"filterSystemMessages\";\n            this.filterSystemMessages.Size = new System.Drawing.Size(220, 20);\n            this.filterSystemMessages.TabIndex = 134;\n            this.filterSystemMessages.Text = \"Filter repeating system messages\";\n            this.filterSystemMessages.CheckedChanged += new System.EventHandler(this.filterSystemMessages_CheckedChanged);\n            // \n            // filterSnoop\n            // \n            this.filterSnoop.Location = new System.Drawing.Point(6, 22);\n            this.filterSnoop.Name = \"filterSnoop\";\n            this.filterSnoop.Size = new System.Drawing.Size(220, 20);\n            this.filterSnoop.TabIndex = 133;\n            this.filterSnoop.Text = \"Filter snooping messages\";\n            this.filterSnoop.CheckedChanged += new System.EventHandler(this.filterSnoop_CheckedChanged);\n            // \n            // subFilterSoundMusic\n            // \n            this.subFilterSoundMusic.BackColor = System.Drawing.SystemColors.Control;\n            this.subFilterSoundMusic.Controls.Add(this.playableMusicList);\n            this.subFilterSoundMusic.Controls.Add(this.playMusic);\n            this.subFilterSoundMusic.Controls.Add(this.showPlayingMusic);\n            this.subFilterSoundMusic.Controls.Add(this.showPlayingSoundInfo);\n            this.subFilterSoundMusic.Controls.Add(this.showFilteredSound);\n            this.subFilterSoundMusic.Controls.Add(this.playInClient);\n            this.subFilterSoundMusic.Controls.Add(this.playSound);\n            this.subFilterSoundMusic.Controls.Add(this.soundFilterEnabled);\n            this.subFilterSoundMusic.Controls.Add(this.soundFilterList);\n            this.subFilterSoundMusic.Location = new System.Drawing.Point(4, 22);\n            this.subFilterSoundMusic.Name = \"subFilterSoundMusic\";\n            this.subFilterSoundMusic.Size = new System.Drawing.Size(498, 307);\n            this.subFilterSoundMusic.TabIndex = 3;\n            this.subFilterSoundMusic.Text = \"Sound & Music  \";\n            // \n            // playableMusicList\n            // \n            this.playableMusicList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.playableMusicList.FormattingEnabled = true;\n            this.playableMusicList.Location = new System.Drawing.Point(215, 151);\n            this.playableMusicList.Name = \"playableMusicList\";\n            this.playableMusicList.Size = new System.Drawing.Size(145, 23);\n            this.playableMusicList.TabIndex = 8;\n            // \n            // playMusic\n            // \n            this.playMusic.Location = new System.Drawing.Point(215, 180);\n            this.playMusic.Name = \"playMusic\";\n            this.playMusic.Size = new System.Drawing.Size(132, 23);\n            this.playMusic.TabIndex = 7;\n            this.playMusic.Text = \"Play Music In Client\";\n            this.playMusic.UseVisualStyleBackColor = true;\n            this.playMusic.Click += new System.EventHandler(this.playMusic_Click);\n            // \n            // showPlayingMusic\n            // \n            this.showPlayingMusic.AutoSize = true;\n            this.showPlayingMusic.Location = new System.Drawing.Point(215, 215);\n            this.showPlayingMusic.Name = \"showPlayingMusic\";\n            this.showPlayingMusic.Size = new System.Drawing.Size(156, 19);\n            this.showPlayingMusic.TabIndex = 6;\n            this.showPlayingMusic.Text = \"Show playing music info\";\n            this.showPlayingMusic.UseVisualStyleBackColor = true;\n            this.showPlayingMusic.CheckedChanged += new System.EventHandler(this.showPlayingMusic_CheckedChanged);\n            // \n            // showPlayingSoundInfo\n            // \n            this.showPlayingSoundInfo.AutoSize = true;\n            this.showPlayingSoundInfo.Location = new System.Drawing.Point(215, 106);\n            this.showPlayingSoundInfo.Name = \"showPlayingSoundInfo\";\n            this.showPlayingSoundInfo.Size = new System.Drawing.Size(181, 19);\n            this.showPlayingSoundInfo.TabIndex = 5;\n            this.showPlayingSoundInfo.Text = \"Show non-filtered sound info\";\n            this.showPlayingSoundInfo.UseVisualStyleBackColor = true;\n            this.showPlayingSoundInfo.CheckedChanged += new System.EventHandler(this.showPlayingSoundInfo_CheckedChanged);\n            // \n            // showFilteredSound\n            // \n            this.showFilteredSound.AutoSize = true;\n            this.showFilteredSound.Location = new System.Drawing.Point(215, 81);\n            this.showFilteredSound.Name = \"showFilteredSound\";\n            this.showFilteredSound.Size = new System.Drawing.Size(155, 19);\n            this.showFilteredSound.TabIndex = 4;\n            this.showFilteredSound.Text = \"Show filtered sound info\";\n            this.showFilteredSound.UseVisualStyleBackColor = true;\n            this.showFilteredSound.CheckedChanged += new System.EventHandler(this.showFilteredSound_CheckedChanged);\n            // \n            // playInClient\n            // \n            this.playInClient.AutoSize = true;\n            this.playInClient.Location = new System.Drawing.Point(348, 42);\n            this.playInClient.Name = \"playInClient\";\n            this.playInClient.Size = new System.Drawing.Size(93, 19);\n            this.playInClient.TabIndex = 3;\n            this.playInClient.Text = \"Play in client\";\n            this.playInClient.UseVisualStyleBackColor = true;\n            // \n            // playSound\n            // \n            this.playSound.Location = new System.Drawing.Point(215, 39);\n            this.playSound.Name = \"playSound\";\n            this.playSound.Size = new System.Drawing.Size(127, 23);\n            this.playSound.TabIndex = 2;\n            this.playSound.Text = \"Play Selected Sound\";\n            this.playSound.UseVisualStyleBackColor = true;\n            this.playSound.Click += new System.EventHandler(this.playSound_Click);\n            // \n            // soundFilterEnabled\n            // \n            this.soundFilterEnabled.AutoSize = true;\n            this.soundFilterEnabled.Location = new System.Drawing.Point(215, 14);\n            this.soundFilterEnabled.Name = \"soundFilterEnabled\";\n            this.soundFilterEnabled.Size = new System.Drawing.Size(127, 19);\n            this.soundFilterEnabled.TabIndex = 1;\n            this.soundFilterEnabled.Text = \"Enable Sound Filter\";\n            this.soundFilterEnabled.UseVisualStyleBackColor = true;\n            this.soundFilterEnabled.CheckedChanged += new System.EventHandler(this.soundFilterEnabled_CheckedChanged);\n            // \n            // soundFilterList\n            // \n            this.soundFilterList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.soundFilterList.FormattingEnabled = true;\n            this.soundFilterList.Location = new System.Drawing.Point(8, 14);\n            this.soundFilterList.Name = \"soundFilterList\";\n            this.soundFilterList.Size = new System.Drawing.Size(201, 130);\n            this.soundFilterList.TabIndex = 0;\n            this.soundFilterList.SelectedIndexChanged += new System.EventHandler(this.soundFilterList_SelectedIndexChanged);\n            // \n            // subFilterTargets\n            // \n            this.subFilterTargets.BackColor = System.Drawing.SystemColors.Control;\n            this.subFilterTargets.Controls.Add(this.lblTargetFilter);\n            this.subFilterTargets.Controls.Add(this.targetFilterClear);\n            this.subFilterTargets.Controls.Add(this.targetFilterRemove);\n            this.subFilterTargets.Controls.Add(this.targetFilterAdd);\n            this.subFilterTargets.Controls.Add(this.targetFilter);\n            this.subFilterTargets.Controls.Add(this.targetFilterEnabled);\n            this.subFilterTargets.Location = new System.Drawing.Point(4, 22);\n            this.subFilterTargets.Name = \"subFilterTargets\";\n            this.subFilterTargets.Padding = new System.Windows.Forms.Padding(3);\n            this.subFilterTargets.Size = new System.Drawing.Size(498, 307);\n            this.subFilterTargets.TabIndex = 1;\n            this.subFilterTargets.Text = \"Target Filter\";\n            // \n            // lblTargetFilter\n            // \n            this.lblTargetFilter.Location = new System.Drawing.Point(6, 84);\n            this.lblTargetFilter.Name = \"lblTargetFilter\";\n            this.lblTargetFilter.Size = new System.Drawing.Size(217, 52);\n            this.lblTargetFilter.TabIndex = 18;\n            this.lblTargetFilter.Text = \"Targets added to this list will be ignored by Razor completely when using any tar\" +\n    \"get hotkeys.\";\n            // \n            // targetFilterClear\n            // \n            this.targetFilterClear.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.targetFilterClear.Location = new System.Drawing.Point(415, 203);\n            this.targetFilterClear.Name = \"targetFilterClear\";\n            this.targetFilterClear.Size = new System.Drawing.Size(77, 29);\n            this.targetFilterClear.TabIndex = 17;\n            this.targetFilterClear.Text = \"Clear List\";\n            this.targetFilterClear.UseVisualStyleBackColor = true;\n            this.targetFilterClear.Click += new System.EventHandler(this.TargetFilterClear_Click);\n            // \n            // targetFilterRemove\n            // \n            this.targetFilterRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.targetFilterRemove.Location = new System.Drawing.Point(335, 203);\n            this.targetFilterRemove.Name = \"targetFilterRemove\";\n            this.targetFilterRemove.Size = new System.Drawing.Size(74, 29);\n            this.targetFilterRemove.TabIndex = 16;\n            this.targetFilterRemove.Text = \"Remove\";\n            this.targetFilterRemove.UseVisualStyleBackColor = true;\n            this.targetFilterRemove.Click += new System.EventHandler(this.TargetFilterRemove_Click);\n            // \n            // targetFilterAdd\n            // \n            this.targetFilterAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.targetFilterAdd.Location = new System.Drawing.Point(247, 203);\n            this.targetFilterAdd.Name = \"targetFilterAdd\";\n            this.targetFilterAdd.Size = new System.Drawing.Size(82, 29);\n            this.targetFilterAdd.TabIndex = 15;\n            this.targetFilterAdd.Text = \"Add (Target)\";\n            this.targetFilterAdd.UseVisualStyleBackColor = true;\n            this.targetFilterAdd.Click += new System.EventHandler(this.TargetFilterAdd_Click);\n            // \n            // targetFilter\n            // \n            this.targetFilter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.targetFilter.FormattingEnabled = true;\n            this.targetFilter.ItemHeight = 15;\n            this.targetFilter.Location = new System.Drawing.Point(247, 6);\n            this.targetFilter.Name = \"targetFilter\";\n            this.targetFilter.Size = new System.Drawing.Size(245, 124);\n            this.targetFilter.TabIndex = 14;\n            // \n            // targetFilterEnabled\n            // \n            this.targetFilterEnabled.AutoSize = true;\n            this.targetFilterEnabled.Location = new System.Drawing.Point(6, 6);\n            this.targetFilterEnabled.Name = \"targetFilterEnabled\";\n            this.targetFilterEnabled.Size = new System.Drawing.Size(132, 19);\n            this.targetFilterEnabled.TabIndex = 13;\n            this.targetFilterEnabled.Text = \"Target Filter Enabled\";\n            this.targetFilterEnabled.UseVisualStyleBackColor = true;\n            this.targetFilterEnabled.CheckedChanged += new System.EventHandler(this.TargetFilterEnabled_CheckedChanged);\n            // \n            // hotkeysTab\n            // \n            this.hotkeysTab.Controls.Add(this.filterHotkeys);\n            this.hotkeysTab.Controls.Add(this.label22);\n            this.hotkeysTab.Controls.Add(this.hkStatus);\n            this.hotkeysTab.Controls.Add(this.hotkeyTree);\n            this.hotkeysTab.Controls.Add(this.dohotkey);\n            this.hotkeysTab.Controls.Add(this.groupBox8);\n            this.hotkeysTab.Location = new System.Drawing.Point(4, 24);\n            this.hotkeysTab.Name = \"hotkeysTab\";\n            this.hotkeysTab.Size = new System.Drawing.Size(519, 342);\n            this.hotkeysTab.TabIndex = 4;\n            this.hotkeysTab.Text = \"Hot Keys\";\n            // \n            // filterHotkeys\n            // \n            this.filterHotkeys.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.filterHotkeys.Location = new System.Drawing.Point(50, 8);\n            this.filterHotkeys.Name = \"filterHotkeys\";\n            this.filterHotkeys.Size = new System.Drawing.Size(281, 23);\n            this.filterHotkeys.TabIndex = 9;\n            this.filterHotkeys.TextChanged += new System.EventHandler(this.filterHotkeys_TextChanged);\n            // \n            // label22\n            // \n            this.label22.AutoSize = true;\n            this.label22.Location = new System.Drawing.Point(8, 11);\n            this.label22.Name = \"label22\";\n            this.label22.Size = new System.Drawing.Size(36, 15);\n            this.label22.TabIndex = 8;\n            this.label22.Text = \"Filter:\";\n            // \n            // hkStatus\n            // \n            this.hkStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.hkStatus.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.hkStatus.Location = new System.Drawing.Point(337, 226);\n            this.hkStatus.Name = \"hkStatus\";\n            this.hkStatus.Size = new System.Drawing.Size(175, 64);\n            this.hkStatus.TabIndex = 7;\n            this.hkStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // hotkeyTree\n            // \n            this.hotkeyTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.hotkeyTree.HideSelection = false;\n            this.hotkeyTree.Location = new System.Drawing.Point(8, 37);\n            this.hotkeyTree.Name = \"hotkeyTree\";\n            this.hotkeyTree.Size = new System.Drawing.Size(323, 295);\n            this.hotkeyTree.Sorted = true;\n            this.hotkeyTree.TabIndex = 6;\n            this.hotkeyTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.hotkeyTree_AfterSelect);\n            // \n            // dohotkey\n            // \n            this.dohotkey.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.dohotkey.Location = new System.Drawing.Point(337, 170);\n            this.dohotkey.Name = \"dohotkey\";\n            this.dohotkey.Size = new System.Drawing.Size(175, 29);\n            this.dohotkey.TabIndex = 5;\n            this.dohotkey.Text = \"Execute Selected Hot Key\";\n            this.dohotkey.Click += new System.EventHandler(this.dohotkey_Click);\n            // \n            // groupBox8\n            // \n            this.groupBox8.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.groupBox8.Controls.Add(this.hkCommand);\n            this.groupBox8.Controls.Add(this.hkCmdLabel);\n            this.groupBox8.Controls.Add(this.chkAlt);\n            this.groupBox8.Controls.Add(this.chkPass);\n            this.groupBox8.Controls.Add(this.label2);\n            this.groupBox8.Controls.Add(this.unsetHK);\n            this.groupBox8.Controls.Add(this.setHK);\n            this.groupBox8.Controls.Add(this.hkKey);\n            this.groupBox8.Controls.Add(this.chkCtrl);\n            this.groupBox8.Controls.Add(this.chkShift);\n            this.groupBox8.Location = new System.Drawing.Point(337, 8);\n            this.groupBox8.Name = \"groupBox8\";\n            this.groupBox8.Size = new System.Drawing.Size(175, 156);\n            this.groupBox8.TabIndex = 4;\n            this.groupBox8.TabStop = false;\n            this.groupBox8.Text = \"Hot Key\";\n            // \n            // hkCommand\n            // \n            this.hkCommand.Location = new System.Drawing.Point(73, 73);\n            this.hkCommand.Name = \"hkCommand\";\n            this.hkCommand.Size = new System.Drawing.Size(96, 23);\n            this.hkCommand.TabIndex = 11;\n            // \n            // hkCmdLabel\n            // \n            this.hkCmdLabel.Location = new System.Drawing.Point(8, 76);\n            this.hkCmdLabel.Name = \"hkCmdLabel\";\n            this.hkCmdLabel.Size = new System.Drawing.Size(68, 20);\n            this.hkCmdLabel.TabIndex = 10;\n            this.hkCmdLabel.Text = \"Command\";\n            // \n            // chkAlt\n            // \n            this.chkAlt.Location = new System.Drawing.Point(58, 20);\n            this.chkAlt.Name = \"chkAlt\";\n            this.chkAlt.Size = new System.Drawing.Size(49, 16);\n            this.chkAlt.TabIndex = 2;\n            this.chkAlt.Text = \"Alt\";\n            // \n            // chkPass\n            // \n            this.chkPass.Location = new System.Drawing.Point(11, 102);\n            this.chkPass.Name = \"chkPass\";\n            this.chkPass.Size = new System.Drawing.Size(113, 16);\n            this.chkPass.TabIndex = 9;\n            this.chkPass.Text = \"Pass to UO\";\n            // \n            // label2\n            // \n            this.label2.Location = new System.Drawing.Point(8, 44);\n            this.label2.Name = \"label2\";\n            this.label2.Size = new System.Drawing.Size(28, 20);\n            this.label2.TabIndex = 8;\n            this.label2.Text = \"Key:\";\n            // \n            // unsetHK\n            // \n            this.unsetHK.Location = new System.Drawing.Point(11, 124);\n            this.unsetHK.Name = \"unsetHK\";\n            this.unsetHK.Size = new System.Drawing.Size(56, 26);\n            this.unsetHK.TabIndex = 6;\n            this.unsetHK.Text = \"Unset\";\n            this.unsetHK.Click += new System.EventHandler(this.unsetHK_Click);\n            // \n            // setHK\n            // \n            this.setHK.Location = new System.Drawing.Point(113, 124);\n            this.setHK.Name = \"setHK\";\n            this.setHK.Size = new System.Drawing.Size(56, 26);\n            this.setHK.TabIndex = 5;\n            this.setHK.Text = \"Set\";\n            this.setHK.Click += new System.EventHandler(this.setHK_Click);\n            // \n            // hkKey\n            // \n            this.hkKey.Location = new System.Drawing.Point(36, 40);\n            this.hkKey.Name = \"hkKey\";\n            this.hkKey.ReadOnly = true;\n            this.hkKey.Size = new System.Drawing.Size(133, 23);\n            this.hkKey.TabIndex = 4;\n            this.hkKey.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.hkKey.KeyUp += new System.Windows.Forms.KeyEventHandler(this.key_KeyUp);\n            this.hkKey.MouseDown += new System.Windows.Forms.MouseEventHandler(this.key_MouseDown);\n            this.hkKey.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.key_MouseWheel);\n            // \n            // chkCtrl\n            // \n            this.chkCtrl.Location = new System.Drawing.Point(8, 20);\n            this.chkCtrl.Name = \"chkCtrl\";\n            this.chkCtrl.Size = new System.Drawing.Size(56, 16);\n            this.chkCtrl.TabIndex = 1;\n            this.chkCtrl.Text = \"Ctrl\";\n            // \n            // chkShift\n            // \n            this.chkShift.Location = new System.Drawing.Point(113, 20);\n            this.chkShift.Name = \"chkShift\";\n            this.chkShift.Size = new System.Drawing.Size(56, 16);\n            this.chkShift.TabIndex = 3;\n            this.chkShift.Text = \"Shift\";\n            // \n            // macrosTab\n            // \n            this.macrosTab.Controls.Add(this.tabControl2);\n            this.macrosTab.Location = new System.Drawing.Point(4, 44);\n            this.macrosTab.Name = \"macrosTab\";\n            this.macrosTab.Size = new System.Drawing.Size(519, 322);\n            this.macrosTab.TabIndex = 7;\n            this.macrosTab.Text = \"Macros\";\n            // \n            // tabControl2\n            // \n            this.tabControl2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.tabControl2.Controls.Add(this.subMacrosTab);\n            this.tabControl2.Controls.Add(this.subMacrosOptionsTab);\n            this.tabControl2.Location = new System.Drawing.Point(6, 3);\n            this.tabControl2.Name = \"tabControl2\";\n            this.tabControl2.SelectedIndex = 0;\n            this.tabControl2.Size = new System.Drawing.Size(510, 314);\n            this.tabControl2.TabIndex = 13;\n            // \n            // subMacrosTab\n            // \n            this.subMacrosTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subMacrosTab.Controls.Add(this.macroActGroup);\n            this.subMacrosTab.Controls.Add(this.filterMacros);\n            this.subMacrosTab.Controls.Add(this.filterLabel);\n            this.subMacrosTab.Controls.Add(this.macroTree);\n            this.subMacrosTab.Controls.Add(this.delMacro);\n            this.subMacrosTab.Controls.Add(this.newMacro);\n            this.subMacrosTab.Location = new System.Drawing.Point(4, 24);\n            this.subMacrosTab.Name = \"subMacrosTab\";\n            this.subMacrosTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subMacrosTab.Size = new System.Drawing.Size(502, 286);\n            this.subMacrosTab.TabIndex = 0;\n            this.subMacrosTab.Text = \"Macros\";\n            // \n            // macroActGroup\n            // \n            this.macroActGroup.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.macroActGroup.Controls.Add(this.setMacroHotKey);\n            this.macroActGroup.Controls.Add(this.playMacro);\n            this.macroActGroup.Controls.Add(this.waitDisp);\n            this.macroActGroup.Controls.Add(this.loopMacro);\n            this.macroActGroup.Controls.Add(this.recMacro);\n            this.macroActGroup.Controls.Add(this.actionList);\n            this.macroActGroup.Location = new System.Drawing.Point(200, 3);\n            this.macroActGroup.Name = \"macroActGroup\";\n            this.macroActGroup.Size = new System.Drawing.Size(296, 240);\n            this.macroActGroup.TabIndex = 18;\n            this.macroActGroup.TabStop = false;\n            this.macroActGroup.Text = \"Actions\";\n            this.macroActGroup.Visible = false;\n            // \n            // setMacroHotKey\n            // \n            this.setMacroHotKey.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.setMacroHotKey.Location = new System.Drawing.Point(230, 95);\n            this.setMacroHotKey.Name = \"setMacroHotKey\";\n            this.setMacroHotKey.Size = new System.Drawing.Size(60, 33);\n            this.setMacroHotKey.TabIndex = 7;\n            this.setMacroHotKey.Text = \"Set HK\";\n            this.setMacroHotKey.Click += new System.EventHandler(this.SetMacroHotKey_Click);\n            // \n            // playMacro\n            // \n            this.playMacro.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.playMacro.Location = new System.Drawing.Point(230, 17);\n            this.playMacro.Name = \"playMacro\";\n            this.playMacro.Size = new System.Drawing.Size(60, 33);\n            this.playMacro.TabIndex = 6;\n            this.playMacro.Text = \"Play\";\n            this.playMacro.Click += new System.EventHandler(this.playMacro_Click);\n            // \n            // waitDisp\n            // \n            this.waitDisp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.waitDisp.Location = new System.Drawing.Point(230, 132);\n            this.waitDisp.Name = \"waitDisp\";\n            this.waitDisp.Size = new System.Drawing.Size(60, 89);\n            this.waitDisp.TabIndex = 5;\n            this.waitDisp.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // loopMacro\n            // \n            this.loopMacro.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.loopMacro.Location = new System.Drawing.Point(233, 210);\n            this.loopMacro.Name = \"loopMacro\";\n            this.loopMacro.Size = new System.Drawing.Size(57, 24);\n            this.loopMacro.TabIndex = 4;\n            this.loopMacro.Text = \"Loop\";\n            this.loopMacro.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            this.loopMacro.CheckedChanged += new System.EventHandler(this.loopMacro_CheckedChanged);\n            // \n            // recMacro\n            // \n            this.recMacro.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.recMacro.Location = new System.Drawing.Point(230, 56);\n            this.recMacro.Name = \"recMacro\";\n            this.recMacro.Size = new System.Drawing.Size(60, 33);\n            this.recMacro.TabIndex = 3;\n            this.recMacro.Text = \"Record\";\n            this.recMacro.Click += new System.EventHandler(this.recMacro_Click);\n            // \n            // actionList\n            // \n            this.actionList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.actionList.BackColor = System.Drawing.SystemColors.Window;\n            this.actionList.HorizontalScrollbar = true;\n            this.actionList.IntegralHeight = false;\n            this.actionList.ItemHeight = 15;\n            this.actionList.Location = new System.Drawing.Point(6, 17);\n            this.actionList.Name = \"actionList\";\n            this.actionList.Size = new System.Drawing.Size(218, 217);\n            this.actionList.TabIndex = 0;\n            this.actionList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.actionList_KeyDown);\n            this.actionList.MouseDown += new System.Windows.Forms.MouseEventHandler(this.actionList_MouseDown);\n            // \n            // filterMacros\n            // \n            this.filterMacros.Location = new System.Drawing.Point(47, 7);\n            this.filterMacros.Name = \"filterMacros\";\n            this.filterMacros.Size = new System.Drawing.Size(147, 23);\n            this.filterMacros.TabIndex = 17;\n            this.filterMacros.TextChanged += new System.EventHandler(this.filterMacros_TextChanged);\n            // \n            // filterLabel\n            // \n            this.filterLabel.AutoSize = true;\n            this.filterLabel.Location = new System.Drawing.Point(5, 10);\n            this.filterLabel.Name = \"filterLabel\";\n            this.filterLabel.Size = new System.Drawing.Size(36, 15);\n            this.filterLabel.TabIndex = 16;\n            this.filterLabel.Text = \"Filter:\";\n            // \n            // macroTree\n            // \n            this.macroTree.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.macroTree.FullRowSelect = true;\n            this.macroTree.HideSelection = false;\n            this.macroTree.Location = new System.Drawing.Point(6, 36);\n            this.macroTree.Name = \"macroTree\";\n            this.macroTree.Size = new System.Drawing.Size(188, 171);\n            this.macroTree.Sorted = true;\n            this.macroTree.TabIndex = 15;\n            this.macroTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.macroTree_AfterSelect);\n            this.macroTree.MouseDown += new System.Windows.Forms.MouseEventHandler(this.macroTree_MouseDown);\n            // \n            // delMacro\n            // \n            this.delMacro.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.delMacro.Location = new System.Drawing.Point(120, 213);\n            this.delMacro.Name = \"delMacro\";\n            this.delMacro.Size = new System.Drawing.Size(74, 30);\n            this.delMacro.TabIndex = 14;\n            this.delMacro.Text = \"Remove\";\n            this.delMacro.Click += new System.EventHandler(this.delMacro_Click);\n            // \n            // newMacro\n            // \n            this.newMacro.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.newMacro.Location = new System.Drawing.Point(8, 213);\n            this.newMacro.Name = \"newMacro\";\n            this.newMacro.Size = new System.Drawing.Size(74, 30);\n            this.newMacro.TabIndex = 13;\n            this.newMacro.Text = \"New...\";\n            this.newMacro.Click += new System.EventHandler(this.newMacro_Click);\n            // \n            // subMacrosOptionsTab\n            // \n            this.subMacrosOptionsTab.BackColor = System.Drawing.SystemColors.Control;\n            this.subMacrosOptionsTab.Controls.Add(this.disableMacroPlayFinish);\n            this.subMacrosOptionsTab.Controls.Add(this.macroActionDelay);\n            this.subMacrosOptionsTab.Controls.Add(this.rangeCheckDoubleClick);\n            this.subMacrosOptionsTab.Controls.Add(this.rangeCheckTargetByType);\n            this.subMacrosOptionsTab.Controls.Add(this.nextMacroAction);\n            this.subMacrosOptionsTab.Controls.Add(this.stepThroughMacro);\n            this.subMacrosOptionsTab.Controls.Add(this.targetByTypeDifferent);\n            this.subMacrosOptionsTab.Controls.Add(this.macroVariableGroup);\n            this.subMacrosOptionsTab.Location = new System.Drawing.Point(4, 22);\n            this.subMacrosOptionsTab.Name = \"subMacrosOptionsTab\";\n            this.subMacrosOptionsTab.Padding = new System.Windows.Forms.Padding(3);\n            this.subMacrosOptionsTab.Size = new System.Drawing.Size(502, 288);\n            this.subMacrosOptionsTab.TabIndex = 1;\n            this.subMacrosOptionsTab.Text = \"Options\";\n            // \n            // disableMacroPlayFinish\n            // \n            this.disableMacroPlayFinish.AutoSize = true;\n            this.disableMacroPlayFinish.Location = new System.Drawing.Point(272, 183);\n            this.disableMacroPlayFinish.Name = \"disableMacroPlayFinish\";\n            this.disableMacroPlayFinish.Size = new System.Drawing.Size(204, 19);\n            this.disableMacroPlayFinish.TabIndex = 17;\n            this.disableMacroPlayFinish.Text = \"Disable Playing/Finished Message\";\n            this.disableMacroPlayFinish.UseVisualStyleBackColor = true;\n            this.disableMacroPlayFinish.CheckedChanged += new System.EventHandler(this.disableMacroPlayFinish_CheckedChanged);\n            // \n            // macroActionDelay\n            // \n            this.macroActionDelay.AutoSize = true;\n            this.macroActionDelay.Location = new System.Drawing.Point(272, 158);\n            this.macroActionDelay.Name = \"macroActionDelay\";\n            this.macroActionDelay.Size = new System.Drawing.Size(207, 19);\n            this.macroActionDelay.TabIndex = 16;\n            this.macroActionDelay.Text = \"Default macro action delay (50ms)\";\n            this.macroActionDelay.UseVisualStyleBackColor = true;\n            this.macroActionDelay.CheckedChanged += new System.EventHandler(this.macroActionDelay_CheckedChanged);\n            // \n            // rangeCheckDoubleClick\n            // \n            this.rangeCheckDoubleClick.AutoSize = true;\n            this.rangeCheckDoubleClick.Location = new System.Drawing.Point(272, 78);\n            this.rangeCheckDoubleClick.Name = \"rangeCheckDoubleClick\";\n            this.rangeCheckDoubleClick.Size = new System.Drawing.Size(207, 19);\n            this.rangeCheckDoubleClick.TabIndex = 15;\n            this.rangeCheckDoubleClick.Text = \"Range check on \\'DoubleClickType\\'\";\n            this.rangeCheckDoubleClick.UseVisualStyleBackColor = true;\n            this.rangeCheckDoubleClick.CheckedChanged += new System.EventHandler(this.rangeCheckDoubleClick_CheckedChanged);\n            // \n            // rangeCheckTargetByType\n            // \n            this.rangeCheckTargetByType.AutoSize = true;\n            this.rangeCheckTargetByType.Location = new System.Drawing.Point(272, 53);\n            this.rangeCheckTargetByType.Name = \"rangeCheckTargetByType\";\n            this.rangeCheckTargetByType.Size = new System.Drawing.Size(188, 19);\n            this.rangeCheckTargetByType.TabIndex = 14;\n            this.rangeCheckTargetByType.Text = \"Range check on \\'TargetByType\\'\";\n            this.rangeCheckTargetByType.UseVisualStyleBackColor = true;\n            this.rangeCheckTargetByType.CheckedChanged += new System.EventHandler(this.rangeCheckTargetByType_CheckedChanged);\n            // \n            // nextMacroAction\n            // \n            this.nextMacroAction.Enabled = false;\n            this.nextMacroAction.Location = new System.Drawing.Point(412, 115);\n            this.nextMacroAction.Name = \"nextMacroAction\";\n            this.nextMacroAction.Size = new System.Drawing.Size(60, 23);\n            this.nextMacroAction.TabIndex = 13;\n            this.nextMacroAction.Text = \"Next\";\n            this.nextMacroAction.UseVisualStyleBackColor = true;\n            this.nextMacroAction.Click += new System.EventHandler(this.nextMacroAction_Click);\n            // \n            // stepThroughMacro\n            // \n            this.stepThroughMacro.AutoSize = true;\n            this.stepThroughMacro.Location = new System.Drawing.Point(272, 118);\n            this.stepThroughMacro.Name = \"stepThroughMacro\";\n            this.stepThroughMacro.Size = new System.Drawing.Size(134, 19);\n            this.stepThroughMacro.TabIndex = 12;\n            this.stepThroughMacro.Text = \"Step Through Macro\";\n            this.stepThroughMacro.UseVisualStyleBackColor = true;\n            this.stepThroughMacro.CheckedChanged += new System.EventHandler(this.stepThroughMacro_CheckedChanged);\n            // \n            // targetByTypeDifferent\n            // \n            this.targetByTypeDifferent.AutoSize = true;\n            this.targetByTypeDifferent.Location = new System.Drawing.Point(272, 28);\n            this.targetByTypeDifferent.Name = \"targetByTypeDifferent\";\n            this.targetByTypeDifferent.Size = new System.Drawing.Size(181, 19);\n            this.targetByTypeDifferent.TabIndex = 11;\n            this.targetByTypeDifferent.Text = \"Force different \\'TargetByType\\'\";\n            this.targetByTypeDifferent.UseVisualStyleBackColor = true;\n            this.targetByTypeDifferent.CheckedChanged += new System.EventHandler(this.targetByTypeDifferent_CheckedChanged);\n            // \n            // macroVariableGroup\n            // \n            this.macroVariableGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.macroVariableGroup.Controls.Add(this.macroVariableTypeList);\n            this.macroVariableGroup.Controls.Add(this.retargetMacroVariable);\n            this.macroVariableGroup.Controls.Add(this.insertMacroVariable);\n            this.macroVariableGroup.Controls.Add(this.removeMacroVariable);\n            this.macroVariableGroup.Controls.Add(this.addMacroVariable);\n            this.macroVariableGroup.Controls.Add(this.macroVariables);\n            this.macroVariableGroup.Location = new System.Drawing.Point(6, 6);\n            this.macroVariableGroup.Name = \"macroVariableGroup\";\n            this.macroVariableGroup.Size = new System.Drawing.Size(240, 271);\n            this.macroVariableGroup.TabIndex = 6;\n            this.macroVariableGroup.TabStop = false;\n            this.macroVariableGroup.Text = \"Macro Variables:\";\n            // \n            // macroVariableTypeList\n            // \n            this.macroVariableTypeList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.macroVariableTypeList.FormattingEnabled = true;\n            this.macroVariableTypeList.Items.AddRange(new object[] {\n            \"Absolute Target\",\n            \"DoubleClick Target\",\n            \"Set Macro Variable Action\"});\n            this.macroVariableTypeList.Location = new System.Drawing.Point(79, 22);\n            this.macroVariableTypeList.Name = \"macroVariableTypeList\";\n            this.macroVariableTypeList.Size = new System.Drawing.Size(153, 23);\n            this.macroVariableTypeList.TabIndex = 6;\n            this.macroVariableTypeList.SelectedIndexChanged += new System.EventHandler(this.macroVariableTypeList_SelectedIndexChanged);\n            // \n            // retargetMacroVariable\n            // \n            this.retargetMacroVariable.Location = new System.Drawing.Point(6, 84);\n            this.retargetMacroVariable.Name = \"retargetMacroVariable\";\n            this.retargetMacroVariable.Size = new System.Drawing.Size(67, 25);\n            this.retargetMacroVariable.TabIndex = 5;\n            this.retargetMacroVariable.Text = \"Retarget\";\n            this.retargetMacroVariable.UseVisualStyleBackColor = true;\n            this.retargetMacroVariable.Click += new System.EventHandler(this.retargetMacroVariable_Click);\n            // \n            // insertMacroVariable\n            // \n            this.insertMacroVariable.Location = new System.Drawing.Point(6, 22);\n            this.insertMacroVariable.Name = \"insertMacroVariable\";\n            this.insertMacroVariable.Size = new System.Drawing.Size(67, 25);\n            this.insertMacroVariable.TabIndex = 4;\n            this.insertMacroVariable.Text = \"Insert as...\";\n            this.insertMacroVariable.UseVisualStyleBackColor = true;\n            this.insertMacroVariable.Click += new System.EventHandler(this.insertMacroVariable_Click);\n            // \n            // removeMacroVariable\n            // \n            this.removeMacroVariable.Location = new System.Drawing.Point(6, 115);\n            this.removeMacroVariable.Name = \"removeMacroVariable\";\n            this.removeMacroVariable.Size = new System.Drawing.Size(67, 25);\n            this.removeMacroVariable.TabIndex = 3;\n            this.removeMacroVariable.Text = \"Remove\";\n            this.removeMacroVariable.UseVisualStyleBackColor = true;\n            this.removeMacroVariable.Click += new System.EventHandler(this.removeMacroVariable_Click);\n            // \n            // addMacroVariable\n            // \n            this.addMacroVariable.Location = new System.Drawing.Point(6, 53);\n            this.addMacroVariable.Name = \"addMacroVariable\";\n            this.addMacroVariable.Size = new System.Drawing.Size(67, 25);\n            this.addMacroVariable.TabIndex = 2;\n            this.addMacroVariable.Text = \"Add\";\n            this.addMacroVariable.UseVisualStyleBackColor = true;\n            this.addMacroVariable.Click += new System.EventHandler(this.addMacroVariable_Click);\n            // \n            // macroVariables\n            // \n            this.macroVariables.FormattingEnabled = true;\n            this.macroVariables.ItemHeight = 15;\n            this.macroVariables.Location = new System.Drawing.Point(79, 53);\n            this.macroVariables.Name = \"macroVariables\";\n            this.macroVariables.Size = new System.Drawing.Size(153, 199);\n            this.macroVariables.TabIndex = 1;\n            // \n            // scriptsTab\n            // \n            this.scriptsTab.BackColor = System.Drawing.SystemColors.Control;\n            this.scriptsTab.Controls.Add(this.subTabScripts);\n            this.scriptsTab.Location = new System.Drawing.Point(4, 44);\n            this.scriptsTab.Name = \"scriptsTab\";\n            this.scriptsTab.Size = new System.Drawing.Size(519, 322);\n            this.scriptsTab.TabIndex = 13;\n            this.scriptsTab.Text = \"Scripts\";\n            // \n            // subTabScripts\n            // \n            this.subTabScripts.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.subTabScripts.Controls.Add(this.subScripts);\n            this.subTabScripts.Controls.Add(this.subScriptOptions);\n            this.subTabScripts.Location = new System.Drawing.Point(6, 3);\n            this.subTabScripts.Name = \"subTabScripts\";\n            this.subTabScripts.SelectedIndex = 0;\n            this.subTabScripts.Size = new System.Drawing.Size(506, 313);\n            this.subTabScripts.TabIndex = 14;\n            // \n            // subScripts\n            // \n            this.subScripts.BackColor = System.Drawing.SystemColors.Control;\n            this.subScripts.Controls.Add(this.scriptHotkey);\n            this.subScripts.Controls.Add(this.scriptSplitContainer);\n            this.subScripts.Controls.Add(this.scriptGuide);\n            this.subScripts.Controls.Add(this.saveScript);\n            this.subScripts.Controls.Add(this.newScript);\n            this.subScripts.Controls.Add(this.setScriptHotkey);\n            this.subScripts.Controls.Add(this.recordScript);\n            this.subScripts.Controls.Add(this.playScript);\n            this.subScripts.Location = new System.Drawing.Point(4, 24);\n            this.subScripts.Name = \"subScripts\";\n            this.subScripts.Padding = new System.Windows.Forms.Padding(3);\n            this.subScripts.Size = new System.Drawing.Size(498, 285);\n            this.subScripts.TabIndex = 0;\n            this.subScripts.Text = \"Scripts\";\n            // \n            // scriptHotkey\n            // \n            this.scriptHotkey.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.scriptHotkey.ForeColor = System.Drawing.SystemColors.ControlText;\n            this.scriptHotkey.Location = new System.Drawing.Point(432, 168);\n            this.scriptHotkey.Name = \"scriptHotkey\";\n            this.scriptHotkey.Size = new System.Drawing.Size(60, 35);\n            this.scriptHotkey.TabIndex = 29;\n            this.scriptHotkey.Text = \"Not Set\";\n            this.scriptHotkey.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // scriptSplitContainer\n            // \n            this.scriptSplitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.scriptSplitContainer.BackColor = System.Drawing.SystemColors.Control;\n            this.scriptSplitContainer.Location = new System.Drawing.Point(7, 7);\n            this.scriptSplitContainer.Name = \"scriptSplitContainer\";\n            // \n            // scriptSplitContainer.Panel1\n            // \n            this.scriptSplitContainer.Panel1.Controls.Add(this.scriptTree);\n            this.scriptSplitContainer.Panel1.Controls.Add(this.scriptFilter);\n            // \n            // scriptSplitContainer.Panel2\n            // \n            this.scriptSplitContainer.Panel2.Controls.Add(this.scriptDocMap);\n            this.scriptSplitContainer.Panel2.Controls.Add(this.scriptEditor);\n            this.scriptSplitContainer.Size = new System.Drawing.Size(419, 262);\n            this.scriptSplitContainer.SplitterDistance = 110;\n            this.scriptSplitContainer.SplitterWidth = 10;\n            this.scriptSplitContainer.TabIndex = 28;\n            // \n            // scriptTree\n            // \n            this.scriptTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.scriptTree.Location = new System.Drawing.Point(0, 31);\n            this.scriptTree.Name = \"scriptTree\";\n            this.scriptTree.Size = new System.Drawing.Size(110, 231);\n            this.scriptTree.Sorted = true;\n            this.scriptTree.TabIndex = 29;\n            this.scriptTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.scriptTree_AfterSelect);\n            this.scriptTree.MouseDown += new System.Windows.Forms.MouseEventHandler(this.scriptTree_MouseDown);\n            // \n            // scriptFilter\n            // \n            this.scriptFilter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.scriptFilter.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.scriptFilter.Location = new System.Drawing.Point(0, 0);\n            this.scriptFilter.Name = \"scriptFilter\";\n            this.scriptFilter.Size = new System.Drawing.Size(110, 25);\n            this.scriptFilter.TabIndex = 28;\n            this.scriptFilter.TextChanged += new System.EventHandler(this.scriptFilter_TextChanged);\n            // \n            // scriptDocMap\n            // \n            this.scriptDocMap.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.scriptDocMap.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(38)))), ((int)(((byte)(37)))), ((int)(((byte)(56)))));\n            this.scriptDocMap.ForeColor = System.Drawing.Color.Maroon;\n            this.scriptDocMap.Location = new System.Drawing.Point(176, -4);\n            this.scriptDocMap.Name = \"scriptDocMap\";\n            this.scriptDocMap.Size = new System.Drawing.Size(120, 266);\n            this.scriptDocMap.TabIndex = 22;\n            this.scriptDocMap.Target = null;\n            // \n            // scriptEditor\n            // \n            this.scriptEditor.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.scriptEditor.AutoCompleteBracketsList = new char[] {\n        '(',\n        ')',\n        '{',\n        '}',\n        '[',\n        ']',\n        '\\\"',\n        '\\\"',\n        '\\'',\n        '\\''};\n            this.scriptEditor.AutoScrollMinSize = new System.Drawing.Size(25, 15);\n            this.scriptEditor.BackBrush = null;\n            this.scriptEditor.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(38)))), ((int)(((byte)(37)))), ((int)(((byte)(56)))));\n            this.scriptEditor.CaretColor = System.Drawing.Color.FromArgb(((int)(((byte)(150)))), ((int)(((byte)(150)))), ((int)(((byte)(150)))));\n            this.scriptEditor.CharHeight = 15;\n            this.scriptEditor.CharWidth = 7;\n            this.scriptEditor.Cursor = System.Windows.Forms.Cursors.IBeam;\n            this.scriptEditor.DisabledColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))), ((int)(((byte)(180)))));\n            this.scriptEditor.Font = new System.Drawing.Font(\"Consolas\", 9.75F);\n            this.scriptEditor.ForeColor = System.Drawing.Color.White;\n            this.scriptEditor.IsReplaceMode = false;\n            this.scriptEditor.LeftBracket = '(';\n            this.scriptEditor.LeftBracket2 = '[';\n            this.scriptEditor.LineNumberColor = System.Drawing.Color.FromArgb(((int)(((byte)(43)))), ((int)(((byte)(144)))), ((int)(((byte)(175)))));\n            this.scriptEditor.Location = new System.Drawing.Point(-4, 0);\n            this.scriptEditor.Name = \"scriptEditor\";\n            this.scriptEditor.Paddings = new System.Windows.Forms.Padding(0);\n            this.scriptEditor.RightBracket = ')';\n            this.scriptEditor.RightBracket2 = ']';\n            this.scriptEditor.SelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255)))));\n            this.scriptEditor.ServiceColors = ((FastColoredTextBoxNS.ServiceColors)(resources.GetObject(\"scriptEditor.ServiceColors\")));\n            this.scriptEditor.ShowCaretWhenInactive = false;\n            this.scriptEditor.Size = new System.Drawing.Size(174, 262);\n            this.scriptEditor.TabIndex = 21;\n            this.scriptEditor.Zoom = 100;\n            this.scriptEditor.KeyDown += new System.Windows.Forms.KeyEventHandler(this.scriptEditor_KeyDown);\n            this.scriptEditor.LostFocus += new System.EventHandler(this.scriptEditor_LostFocus);\n            this.scriptEditor.MouseDown += new System.Windows.Forms.MouseEventHandler(this.scriptEditor_MouseDown);\n            // \n            // scriptGuide\n            // \n            this.scriptGuide.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.scriptGuide.AutoSize = true;\n            this.scriptGuide.Location = new System.Drawing.Point(432, 243);\n            this.scriptGuide.Name = \"scriptGuide\";\n            this.scriptGuide.Size = new System.Drawing.Size(60, 26);\n            this.scriptGuide.TabIndex = 26;\n            this.scriptGuide.Text = \"Help\";\n            this.scriptGuide.UseVisualStyleBackColor = true;\n            this.scriptGuide.Click += new System.EventHandler(this.scriptGuide_Click);\n            // \n            // saveScript\n            // \n            this.saveScript.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.saveScript.AutoSize = true;\n            this.saveScript.Location = new System.Drawing.Point(432, 83);\n            this.saveScript.Name = \"saveScript\";\n            this.saveScript.Size = new System.Drawing.Size(60, 32);\n            this.saveScript.TabIndex = 22;\n            this.saveScript.Text = \"Save\";\n            this.saveScript.UseVisualStyleBackColor = true;\n            this.saveScript.Click += new System.EventHandler(this.saveScript_Click);\n            // \n            // newScript\n            // \n            this.newScript.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.newScript.AutoSize = true;\n            this.newScript.Location = new System.Drawing.Point(432, 211);\n            this.newScript.Name = \"newScript\";\n            this.newScript.Size = new System.Drawing.Size(60, 26);\n            this.newScript.TabIndex = 18;\n            this.newScript.Text = \"New\";\n            this.newScript.UseVisualStyleBackColor = true;\n            this.newScript.Click += new System.EventHandler(this.newScript_Click);\n            // \n            // setScriptHotkey\n            // \n            this.setScriptHotkey.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.setScriptHotkey.AutoSize = true;\n            this.setScriptHotkey.Location = new System.Drawing.Point(432, 133);\n            this.setScriptHotkey.Name = \"setScriptHotkey\";\n            this.setScriptHotkey.Size = new System.Drawing.Size(60, 32);\n            this.setScriptHotkey.TabIndex = 16;\n            this.setScriptHotkey.Text = \"Set HK\";\n            this.setScriptHotkey.UseVisualStyleBackColor = true;\n            this.setScriptHotkey.Click += new System.EventHandler(this.setScriptHotkey_Click);\n            // \n            // recordScript\n            // \n            this.recordScript.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.recordScript.AutoSize = true;\n            this.recordScript.Location = new System.Drawing.Point(432, 45);\n            this.recordScript.Name = \"recordScript\";\n            this.recordScript.Size = new System.Drawing.Size(60, 32);\n            this.recordScript.TabIndex = 15;\n            this.recordScript.Text = \"Record\";\n            this.recordScript.UseVisualStyleBackColor = true;\n            this.recordScript.Click += new System.EventHandler(this.recordScript_Click);\n            // \n            // playScript\n            // \n            this.playScript.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.playScript.AutoSize = true;\n            this.playScript.Location = new System.Drawing.Point(432, 7);\n            this.playScript.Name = \"playScript\";\n            this.playScript.Size = new System.Drawing.Size(60, 32);\n            this.playScript.TabIndex = 14;\n            this.playScript.Text = \"Play\";\n            this.playScript.UseVisualStyleBackColor = true;\n            this.playScript.Click += new System.EventHandler(this.playScript_Click);\n            // \n            // subScriptOptions\n            // \n            this.subScriptOptions.BackColor = System.Drawing.SystemColors.Control;\n            this.subScriptOptions.Controls.Add(this.disableScriptStopwatch);\n            this.subScriptOptions.Controls.Add(this.enableHighlight);\n            this.subScriptOptions.Controls.Add(this.defaultScriptDelay);\n            this.subScriptOptions.Controls.Add(this.disableScriptTooltips);\n            this.subScriptOptions.Controls.Add(this.scriptDisablePlayFinish);\n            this.subScriptOptions.Controls.Add(this.autoSaveScriptPlay);\n            this.subScriptOptions.Controls.Add(this.autoSaveScript);\n            this.subScriptOptions.Controls.Add(this.scriptVariablesBox);\n            this.subScriptOptions.Location = new System.Drawing.Point(4, 22);\n            this.subScriptOptions.Name = \"subScriptOptions\";\n            this.subScriptOptions.Padding = new System.Windows.Forms.Padding(3);\n            this.subScriptOptions.Size = new System.Drawing.Size(498, 287);\n            this.subScriptOptions.TabIndex = 1;\n            this.subScriptOptions.Text = \"Options\";\n            // \n            // disableScriptStopwatch\n            // \n            this.disableScriptStopwatch.AutoSize = true;\n            this.disableScriptStopwatch.Location = new System.Drawing.Point(281, 115);\n            this.disableScriptStopwatch.Name = \"disableScriptStopwatch\";\n            this.disableScriptStopwatch.Size = new System.Drawing.Size(185, 19);\n            this.disableScriptStopwatch.TabIndex = 23;\n            this.disableScriptStopwatch.Text = \"Disable execution time output\";\n            this.disableScriptStopwatch.UseVisualStyleBackColor = true;\n            this.disableScriptStopwatch.CheckedChanged += new System.EventHandler(this.disableScriptStopwatch_CheckedChanged);\n            // \n            // enableHighlight\n            // \n            this.enableHighlight.AutoSize = true;\n            this.enableHighlight.Location = new System.Drawing.Point(252, 190);\n            this.enableHighlight.Name = \"enableHighlight\";\n            this.enableHighlight.Size = new System.Drawing.Size(171, 19);\n            this.enableHighlight.TabIndex = 22;\n            this.enableHighlight.Text = \"Enable highlighting per line\";\n            this.enableHighlight.UseVisualStyleBackColor = true;\n            this.enableHighlight.CheckedChanged += new System.EventHandler(this.enableHighlight_CheckedChanged);\n            // \n            // defaultScriptDelay\n            // \n            this.defaultScriptDelay.AutoSize = true;\n            this.defaultScriptDelay.Location = new System.Drawing.Point(252, 165);\n            this.defaultScriptDelay.Name = \"defaultScriptDelay\";\n            this.defaultScriptDelay.Size = new System.Drawing.Size(202, 19);\n            this.defaultScriptDelay.TabIndex = 21;\n            this.defaultScriptDelay.Text = \"Default script action delay (25ms)\";\n            this.defaultScriptDelay.UseVisualStyleBackColor = true;\n            this.defaultScriptDelay.CheckedChanged += new System.EventHandler(this.defaultScriptDelay_CheckedChanged);\n            // \n            // disableScriptTooltips\n            // \n            this.disableScriptTooltips.AutoSize = true;\n            this.disableScriptTooltips.Location = new System.Drawing.Point(252, 140);\n            this.disableScriptTooltips.Name = \"disableScriptTooltips\";\n            this.disableScriptTooltips.Size = new System.Drawing.Size(107, 19);\n            this.disableScriptTooltips.TabIndex = 20;\n            this.disableScriptTooltips.Text = \"Disable tooltips\";\n            this.disableScriptTooltips.UseVisualStyleBackColor = true;\n            this.disableScriptTooltips.CheckedChanged += new System.EventHandler(this.disableScriptTooltips_CheckedChanged);\n            // \n            // scriptDisablePlayFinish\n            // \n            this.scriptDisablePlayFinish.AutoSize = true;\n            this.scriptDisablePlayFinish.Location = new System.Drawing.Point(252, 90);\n            this.scriptDisablePlayFinish.Name = \"scriptDisablePlayFinish\";\n            this.scriptDisablePlayFinish.Size = new System.Drawing.Size(204, 19);\n            this.scriptDisablePlayFinish.TabIndex = 19;\n            this.scriptDisablePlayFinish.Text = \"Disable Playing/Finished Message\";\n            this.scriptDisablePlayFinish.UseVisualStyleBackColor = true;\n            this.scriptDisablePlayFinish.CheckedChanged += new System.EventHandler(this.disableScriptPlayFinish_CheckedChanged);\n            // \n            // autoSaveScriptPlay\n            // \n            this.autoSaveScriptPlay.AutoSize = true;\n            this.autoSaveScriptPlay.Location = new System.Drawing.Point(252, 53);\n            this.autoSaveScriptPlay.Name = \"autoSaveScriptPlay\";\n            this.autoSaveScriptPlay.Size = new System.Drawing.Size(193, 19);\n            this.autoSaveScriptPlay.TabIndex = 9;\n            this.autoSaveScriptPlay.Text = \"Auto-save when you click \\'Play\\'\";\n            this.autoSaveScriptPlay.UseVisualStyleBackColor = true;\n            this.autoSaveScriptPlay.CheckedChanged += new System.EventHandler(this.autoSaveScriptPlay_CheckedChanged);\n            // \n            // autoSaveScript\n            // \n            this.autoSaveScript.AutoSize = true;\n            this.autoSaveScript.Location = new System.Drawing.Point(252, 28);\n            this.autoSaveScript.Name = \"autoSaveScript\";\n            this.autoSaveScript.Size = new System.Drawing.Size(239, 19);\n            this.autoSaveScript.TabIndex = 8;\n            this.autoSaveScript.Text = \"Auto-save when script editor loses focus\";\n            this.autoSaveScript.UseVisualStyleBackColor = true;\n            this.autoSaveScript.CheckedChanged += new System.EventHandler(this.autoSaveScript_CheckedChanged);\n            // \n            // scriptVariablesBox\n            // \n            this.scriptVariablesBox.Controls.Add(this.changeScriptVariable);\n            this.scriptVariablesBox.Controls.Add(this.removeScriptVariable);\n            this.scriptVariablesBox.Controls.Add(this.addScriptVariable);\n            this.scriptVariablesBox.Controls.Add(this.scriptVariables);\n            this.scriptVariablesBox.Location = new System.Drawing.Point(6, 6);\n            this.scriptVariablesBox.Name = \"scriptVariablesBox\";\n            this.scriptVariablesBox.Size = new System.Drawing.Size(240, 269);\n            this.scriptVariablesBox.TabIndex = 7;\n            this.scriptVariablesBox.TabStop = false;\n            this.scriptVariablesBox.Text = \"Script Variables:\";\n            // \n            // changeScriptVariable\n            // \n            this.changeScriptVariable.Location = new System.Drawing.Point(6, 53);\n            this.changeScriptVariable.Name = \"changeScriptVariable\";\n            this.changeScriptVariable.Size = new System.Drawing.Size(67, 25);\n            this.changeScriptVariable.TabIndex = 5;\n            this.changeScriptVariable.Text = \"Retarget\";\n            this.changeScriptVariable.UseVisualStyleBackColor = true;\n            this.changeScriptVariable.Click += new System.EventHandler(this.changeScriptVariable_Click);\n            // \n            // removeScriptVariable\n            // \n            this.removeScriptVariable.Location = new System.Drawing.Point(6, 84);\n            this.removeScriptVariable.Name = \"removeScriptVariable\";\n            this.removeScriptVariable.Size = new System.Drawing.Size(67, 25);\n            this.removeScriptVariable.TabIndex = 3;\n            this.removeScriptVariable.Text = \"Remove\";\n            this.removeScriptVariable.UseVisualStyleBackColor = true;\n            this.removeScriptVariable.Click += new System.EventHandler(this.removeScriptVariable_Click);\n            // \n            // addScriptVariable\n            // \n            this.addScriptVariable.Location = new System.Drawing.Point(6, 22);\n            this.addScriptVariable.Name = \"addScriptVariable\";\n            this.addScriptVariable.Size = new System.Drawing.Size(67, 25);\n            this.addScriptVariable.TabIndex = 2;\n            this.addScriptVariable.Text = \"Add\";\n            this.addScriptVariable.UseVisualStyleBackColor = true;\n            this.addScriptVariable.Click += new System.EventHandler(this.addScriptVariable_Click);\n            // \n            // scriptVariables\n            // \n            this.scriptVariables.FormattingEnabled = true;\n            this.scriptVariables.ItemHeight = 15;\n            this.scriptVariables.Location = new System.Drawing.Point(79, 22);\n            this.scriptVariables.Name = \"scriptVariables\";\n            this.scriptVariables.Size = new System.Drawing.Size(153, 229);\n            this.scriptVariables.TabIndex = 1;\n            // \n            // friendsTab\n            // \n            this.friendsTab.BackColor = System.Drawing.SystemColors.Control;\n            this.friendsTab.Controls.Add(this.showPartyFriendOverhead);\n            this.friendsTab.Controls.Add(this.highlightFriend);\n            this.friendsTab.Controls.Add(this.autoAcceptParty);\n            this.friendsTab.Controls.Add(this.nextPrevIgnoresFriends);\n            this.friendsTab.Controls.Add(this.autoFriend);\n            this.friendsTab.Controls.Add(this.friendsGroupBox);\n            this.friendsTab.Location = new System.Drawing.Point(4, 44);\n            this.friendsTab.Name = \"friendsTab\";\n            this.friendsTab.Size = new System.Drawing.Size(519, 322);\n            this.friendsTab.TabIndex = 14;\n            this.friendsTab.Text = \"Friends\";\n            // \n            // showPartyFriendOverhead\n            // \n            this.showPartyFriendOverhead.Location = new System.Drawing.Point(283, 40);\n            this.showPartyFriendOverhead.Name = \"showPartyFriendOverhead\";\n            this.showPartyFriendOverhead.Size = new System.Drawing.Size(217, 20);\n            this.showPartyFriendOverhead.TabIndex = 144;\n            this.showPartyFriendOverhead.Text = \"Show [Party-Friend] overhead\";\n            this.showPartyFriendOverhead.CheckedChanged += new System.EventHandler(this.showPartyFriendOverhead_CheckedChanged);\n            // \n            // highlightFriend\n            // \n            this.highlightFriend.Location = new System.Drawing.Point(270, 117);\n            this.highlightFriend.Name = \"highlightFriend\";\n            this.highlightFriend.Size = new System.Drawing.Size(184, 23);\n            this.highlightFriend.TabIndex = 143;\n            this.highlightFriend.Text = \"Next/Prev highlights \\'Friends\\'\";\n            this.highlightFriend.UseVisualStyleBackColor = true;\n            this.highlightFriend.CheckedChanged += new System.EventHandler(this.highlightFriend_CheckedChanged);\n            // \n            // autoAcceptParty\n            // \n            this.autoAcceptParty.Location = new System.Drawing.Point(270, 91);\n            this.autoAcceptParty.Name = \"autoAcceptParty\";\n            this.autoAcceptParty.Size = new System.Drawing.Size(230, 20);\n            this.autoAcceptParty.TabIndex = 138;\n            this.autoAcceptParty.Text = \"Auto-accept party invites from friends\";\n            this.autoAcceptParty.CheckedChanged += new System.EventHandler(this.autoAcceptParty_CheckedChanged);\n            // \n            // nextPrevIgnoresFriends\n            // \n            this.nextPrevIgnoresFriends.AutoSize = true;\n            this.nextPrevIgnoresFriends.Location = new System.Drawing.Point(270, 66);\n            this.nextPrevIgnoresFriends.Name = \"nextPrevIgnoresFriends\";\n            this.nextPrevIgnoresFriends.Size = new System.Drawing.Size(203, 19);\n            this.nextPrevIgnoresFriends.TabIndex = 137;\n            this.nextPrevIgnoresFriends.Text = \"Next/Prev Target ignores \\'Friends\\'\";\n            this.nextPrevIgnoresFriends.UseVisualStyleBackColor = true;\n            this.nextPrevIgnoresFriends.CheckedChanged += new System.EventHandler(this.nextPrevIgnoresFriends_CheckedChanged);\n            // \n            // autoFriend\n            // \n            this.autoFriend.Location = new System.Drawing.Point(270, 14);\n            this.autoFriend.Name = \"autoFriend\";\n            this.autoFriend.Size = new System.Drawing.Size(217, 20);\n            this.autoFriend.TabIndex = 136;\n            this.autoFriend.Text = \"Treat party members as \\'Friends\\'\";\n            this.autoFriend.CheckedChanged += new System.EventHandler(this.autoFriend_CheckedChanged);\n            // \n            // friendsGroupBox\n            // \n            this.friendsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.friendsGroupBox.Controls.Add(this.showFriendOverhead);\n            this.friendsGroupBox.Controls.Add(this.setFriendsFormatHue);\n            this.friendsGroupBox.Controls.Add(this.friendOverheadFormat);\n            this.friendsGroupBox.Controls.Add(this.friendFormat);\n            this.friendsGroupBox.Controls.Add(this.friendsGroupRemove);\n            this.friendsGroupBox.Controls.Add(this.friendsGroupAdd);\n            this.friendsGroupBox.Controls.Add(this.friendClearList);\n            this.friendsGroupBox.Controls.Add(this.friendRemoveSelected);\n            this.friendsGroupBox.Controls.Add(this.friendAddTarget);\n            this.friendsGroupBox.Controls.Add(this.friendsList);\n            this.friendsGroupBox.Controls.Add(this.friendsGroup);\n            this.friendsGroupBox.Controls.Add(this.friendsListEnabled);\n            this.friendsGroupBox.Location = new System.Drawing.Point(6, 3);\n            this.friendsGroupBox.Name = \"friendsGroupBox\";\n            this.friendsGroupBox.Size = new System.Drawing.Size(258, 313);\n            this.friendsGroupBox.TabIndex = 135;\n            this.friendsGroupBox.TabStop = false;\n            this.friendsGroupBox.Text = \"Friends Groups && Lists\";\n            // \n            // showFriendOverhead\n            // \n            this.showFriendOverhead.Location = new System.Drawing.Point(6, 52);\n            this.showFriendOverhead.Name = \"showFriendOverhead\";\n            this.showFriendOverhead.Size = new System.Drawing.Size(184, 23);\n            this.showFriendOverhead.TabIndex = 146;\n            this.showFriendOverhead.Text = \"Show overhead tag\";\n            this.showFriendOverhead.UseVisualStyleBackColor = true;\n            this.showFriendOverhead.CheckedChanged += new System.EventHandler(this.showFriendOverhead_CheckedChanged);\n            // \n            // setFriendsFormatHue\n            // \n            this.setFriendsFormatHue.Location = new System.Drawing.Point(163, 78);\n            this.setFriendsFormatHue.Name = \"setFriendsFormatHue\";\n            this.setFriendsFormatHue.Size = new System.Drawing.Size(59, 23);\n            this.setFriendsFormatHue.TabIndex = 145;\n            this.setFriendsFormatHue.Text = \"Set Hue\";\n            this.setFriendsFormatHue.UseVisualStyleBackColor = true;\n            this.setFriendsFormatHue.Click += new System.EventHandler(this.setFriendsFormatHue_Click);\n            // \n            // friendOverheadFormat\n            // \n            this.friendOverheadFormat.Location = new System.Drawing.Point(55, 78);\n            this.friendOverheadFormat.Name = \"friendOverheadFormat\";\n            this.friendOverheadFormat.Size = new System.Drawing.Size(102, 23);\n            this.friendOverheadFormat.TabIndex = 143;\n            this.friendOverheadFormat.Text = \"[Friend]\";\n            this.friendOverheadFormat.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.friendOverheadFormat.TextChanged += new System.EventHandler(this.friendOverheadFormat_TextChanged);\n            // \n            // friendFormat\n            // \n            this.friendFormat.Location = new System.Drawing.Point(6, 78);\n            this.friendFormat.Name = \"friendFormat\";\n            this.friendFormat.Size = new System.Drawing.Size(151, 23);\n            this.friendFormat.TabIndex = 144;\n            this.friendFormat.Text = \"Format:\";\n            this.friendFormat.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // friendsGroupRemove\n            // \n            this.friendsGroupRemove.Location = new System.Drawing.Point(157, 21);\n            this.friendsGroupRemove.Name = \"friendsGroupRemove\";\n            this.friendsGroupRemove.Size = new System.Drawing.Size(21, 25);\n            this.friendsGroupRemove.TabIndex = 11;\n            this.friendsGroupRemove.Text = \"-\";\n            this.friendsGroupRemove.UseVisualStyleBackColor = true;\n            this.friendsGroupRemove.Click += new System.EventHandler(this.friendsGroupRemove_Click);\n            // \n            // friendsGroupAdd\n            // \n            this.friendsGroupAdd.Location = new System.Drawing.Point(130, 21);\n            this.friendsGroupAdd.Name = \"friendsGroupAdd\";\n            this.friendsGroupAdd.Size = new System.Drawing.Size(21, 25);\n            this.friendsGroupAdd.TabIndex = 10;\n            this.friendsGroupAdd.Text = \"+\";\n            this.friendsGroupAdd.UseVisualStyleBackColor = true;\n            this.friendsGroupAdd.Click += new System.EventHandler(this.friendsGroupAdd_Click);\n            // \n            // friendClearList\n            // \n            this.friendClearList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.friendClearList.Location = new System.Drawing.Point(174, 274);\n            this.friendClearList.Name = \"friendClearList\";\n            this.friendClearList.Size = new System.Drawing.Size(79, 33);\n            this.friendClearList.TabIndex = 8;\n            this.friendClearList.Text = \"Clear List\";\n            this.friendClearList.UseVisualStyleBackColor = true;\n            this.friendClearList.Click += new System.EventHandler(this.friendClearList_Click);\n            // \n            // friendRemoveSelected\n            // \n            this.friendRemoveSelected.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.friendRemoveSelected.Location = new System.Drawing.Point(94, 274);\n            this.friendRemoveSelected.Name = \"friendRemoveSelected\";\n            this.friendRemoveSelected.Size = new System.Drawing.Size(74, 33);\n            this.friendRemoveSelected.TabIndex = 7;\n            this.friendRemoveSelected.Text = \"Remove\";\n            this.friendRemoveSelected.UseVisualStyleBackColor = true;\n            this.friendRemoveSelected.Click += new System.EventHandler(this.friendRemoveSelected_Click);\n            // \n            // friendAddTarget\n            // \n            this.friendAddTarget.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.friendAddTarget.Location = new System.Drawing.Point(6, 274);\n            this.friendAddTarget.Name = \"friendAddTarget\";\n            this.friendAddTarget.Size = new System.Drawing.Size(82, 33);\n            this.friendAddTarget.TabIndex = 5;\n            this.friendAddTarget.Text = \"Add (Target)\";\n            this.friendAddTarget.UseVisualStyleBackColor = true;\n            this.friendAddTarget.Click += new System.EventHandler(this.FriendAddTarget_Click);\n            // \n            // friendsList\n            // \n            this.friendsList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.friendsList.FormattingEnabled = true;\n            this.friendsList.ItemHeight = 15;\n            this.friendsList.Location = new System.Drawing.Point(5, 114);\n            this.friendsList.Name = \"friendsList\";\n            this.friendsList.Size = new System.Drawing.Size(247, 154);\n            this.friendsList.TabIndex = 4;\n            this.friendsList.KeyDown += new System.Windows.Forms.KeyEventHandler(this.friendsList_KeyDown);\n            this.friendsList.MouseDown += new System.Windows.Forms.MouseEventHandler(this.friendsList_MouseDown);\n            // \n            // friendsGroup\n            // \n            this.friendsGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.friendsGroup.FormattingEnabled = true;\n            this.friendsGroup.Location = new System.Drawing.Point(6, 22);\n            this.friendsGroup.Name = \"friendsGroup\";\n            this.friendsGroup.Size = new System.Drawing.Size(118, 23);\n            this.friendsGroup.TabIndex = 3;\n            this.friendsGroup.SelectedIndexChanged += new System.EventHandler(this.friendsGroup_SelectedIndexChanged);\n            // \n            // friendsListEnabled\n            // \n            this.friendsListEnabled.Location = new System.Drawing.Point(184, 23);\n            this.friendsListEnabled.Name = \"friendsListEnabled\";\n            this.friendsListEnabled.Size = new System.Drawing.Size(69, 20);\n            this.friendsListEnabled.TabIndex = 9;\n            this.friendsListEnabled.Text = \"Enabled\";\n            this.friendsListEnabled.UseVisualStyleBackColor = true;\n            this.friendsListEnabled.CheckedChanged += new System.EventHandler(this.friendsListEnabled_CheckedChanged);\n            // \n            // screenshotTab\n            // \n            this.screenshotTab.Controls.Add(this.openScreenshotFolder);\n            this.screenshotTab.Controls.Add(this.captureOwnDeathDelay);\n            this.screenshotTab.Controls.Add(this.lblOwnDeathMs);\n            this.screenshotTab.Controls.Add(this.captureOwnDeath);\n            this.screenshotTab.Controls.Add(this.captureOthersDeathDelay);\n            this.screenshotTab.Controls.Add(this.lblCaptureOthersDeathMs);\n            this.screenshotTab.Controls.Add(this.imgFmt);\n            this.screenshotTab.Controls.Add(this.label12);\n            this.screenshotTab.Controls.Add(this.capNow);\n            this.screenshotTab.Controls.Add(this.screenPath);\n            this.screenshotTab.Controls.Add(this.radioUO);\n            this.screenshotTab.Controls.Add(this.radioFull);\n            this.screenshotTab.Controls.Add(this.captureOthersDeath);\n            this.screenshotTab.Controls.Add(this.setScnPath);\n            this.screenshotTab.Controls.Add(this.screensList);\n            this.screenshotTab.Controls.Add(this.screenPrev);\n            this.screenshotTab.Controls.Add(this.dispTime);\n            this.screenshotTab.Location = new System.Drawing.Point(4, 44);\n            this.screenshotTab.Name = \"screenshotTab\";\n            this.screenshotTab.Size = new System.Drawing.Size(519, 322);\n            this.screenshotTab.TabIndex = 8;\n            this.screenshotTab.Text = \"Screen Shots\";\n            // \n            // openScreenshotFolder\n            // \n            this.openScreenshotFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.openScreenshotFolder.Location = new System.Drawing.Point(266, 201);\n            this.openScreenshotFolder.Name = \"openScreenshotFolder\";\n            this.openScreenshotFolder.Size = new System.Drawing.Size(155, 23);\n            this.openScreenshotFolder.TabIndex = 62;\n            this.openScreenshotFolder.Text = \"Open Screen Shot Folder\";\n            this.openScreenshotFolder.UseVisualStyleBackColor = true;\n            this.openScreenshotFolder.Click += new System.EventHandler(this.openScreenshotFolder_Click);\n            // \n            // captureOwnDeathDelay\n            // \n            this.captureOwnDeathDelay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.captureOwnDeathDelay.Location = new System.Drawing.Point(419, 263);\n            this.captureOwnDeathDelay.Name = \"captureOwnDeathDelay\";\n            this.captureOwnDeathDelay.Size = new System.Drawing.Size(32, 23);\n            this.captureOwnDeathDelay.TabIndex = 61;\n            this.captureOwnDeathDelay.Text = \"0.5\";\n            this.captureOwnDeathDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.captureOwnDeathDelay.TextChanged += new System.EventHandler(this.CaptureOwnDeathDelay_TextChanged);\n            // \n            // lblOwnDeathMs\n            // \n            this.lblOwnDeathMs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.lblOwnDeathMs.Location = new System.Drawing.Point(453, 267);\n            this.lblOwnDeathMs.Name = \"lblOwnDeathMs\";\n            this.lblOwnDeathMs.Size = new System.Drawing.Size(26, 18);\n            this.lblOwnDeathMs.TabIndex = 60;\n            this.lblOwnDeathMs.Text = \"s\";\n            // \n            // captureOwnDeath\n            // \n            this.captureOwnDeath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.captureOwnDeath.Location = new System.Drawing.Point(235, 266);\n            this.captureOwnDeath.Name = \"captureOwnDeath\";\n            this.captureOwnDeath.Size = new System.Drawing.Size(158, 20);\n            this.captureOwnDeath.TabIndex = 59;\n            this.captureOwnDeath.Text = \"Capture your own death\";\n            this.captureOwnDeath.CheckedChanged += new System.EventHandler(this.CaptureOwnDeath_CheckedChanged);\n            // \n            // captureOthersDeathDelay\n            // \n            this.captureOthersDeathDelay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.captureOthersDeathDelay.Location = new System.Drawing.Point(419, 239);\n            this.captureOthersDeathDelay.Name = \"captureOthersDeathDelay\";\n            this.captureOthersDeathDelay.Size = new System.Drawing.Size(32, 23);\n            this.captureOthersDeathDelay.TabIndex = 58;\n            this.captureOthersDeathDelay.Text = \"0.5\";\n            this.captureOthersDeathDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;\n            this.captureOthersDeathDelay.TextChanged += new System.EventHandler(this.CaptureOthersDeathDelay_TextChanged);\n            // \n            // lblCaptureOthersDeathMs\n            // \n            this.lblCaptureOthersDeathMs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.lblCaptureOthersDeathMs.Location = new System.Drawing.Point(453, 242);\n            this.lblCaptureOthersDeathMs.Name = \"lblCaptureOthersDeathMs\";\n            this.lblCaptureOthersDeathMs.Size = new System.Drawing.Size(26, 18);\n            this.lblCaptureOthersDeathMs.TabIndex = 57;\n            this.lblCaptureOthersDeathMs.Text = \"s\";\n            // \n            // imgFmt\n            // \n            this.imgFmt.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.imgFmt.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.imgFmt.Items.AddRange(new object[] {\n            \"jpg\",\n            \"png\",\n            \"bmp\",\n            \"gif\",\n            \"tif\",\n            \"wmf\",\n            \"exif\",\n            \"emf\"});\n            this.imgFmt.Location = new System.Drawing.Point(103, 237);\n            this.imgFmt.Name = \"imgFmt\";\n            this.imgFmt.Size = new System.Drawing.Size(98, 23);\n            this.imgFmt.TabIndex = 11;\n            this.imgFmt.SelectedIndexChanged += new System.EventHandler(this.imgFmt_SelectedIndexChanged);\n            // \n            // label12\n            // \n            this.label12.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.label12.Location = new System.Drawing.Point(6, 237);\n            this.label12.Name = \"label12\";\n            this.label12.Size = new System.Drawing.Size(92, 20);\n            this.label12.TabIndex = 10;\n            this.label12.Text = \"Image Format:\";\n            this.label12.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // capNow\n            // \n            this.capNow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));\n            this.capNow.Location = new System.Drawing.Point(266, 173);\n            this.capNow.Name = \"capNow\";\n            this.capNow.Size = new System.Drawing.Size(155, 22);\n            this.capNow.TabIndex = 8;\n            this.capNow.Text = \"Take Screen Shot Now\";\n            this.capNow.Click += new System.EventHandler(this.capNow_Click);\n            // \n            // screenPath\n            // \n            this.screenPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.screenPath.Location = new System.Drawing.Point(8, 12);\n            this.screenPath.Name = \"screenPath\";\n            this.screenPath.Size = new System.Drawing.Size(463, 23);\n            this.screenPath.TabIndex = 7;\n            this.screenPath.TextChanged += new System.EventHandler(this.screenPath_TextChanged);\n            // \n            // radioUO\n            // \n            this.radioUO.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.radioUO.Location = new System.Drawing.Point(13, 260);\n            this.radioUO.Name = \"radioUO\";\n            this.radioUO.Size = new System.Drawing.Size(75, 26);\n            this.radioUO.TabIndex = 6;\n            this.radioUO.Text = \"UO Only\";\n            this.radioUO.CheckedChanged += new System.EventHandler(this.radioUO_CheckedChanged);\n            // \n            // radioFull\n            // \n            this.radioFull.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.radioFull.Location = new System.Drawing.Point(103, 260);\n            this.radioFull.Name = \"radioFull\";\n            this.radioFull.Size = new System.Drawing.Size(88, 26);\n            this.radioFull.TabIndex = 5;\n            this.radioFull.Text = \"Full Screen\";\n            this.radioFull.CheckedChanged += new System.EventHandler(this.radioFull_CheckedChanged);\n            // \n            // captureOthersDeath\n            // \n            this.captureOthersDeath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.captureOthersDeath.Location = new System.Drawing.Point(235, 240);\n            this.captureOthersDeath.Name = \"captureOthersDeath\";\n            this.captureOthersDeath.Size = new System.Drawing.Size(216, 20);\n            this.captureOthersDeath.TabIndex = 4;\n            this.captureOthersDeath.Text = \"Capture death of other players\";\n            this.captureOthersDeath.CheckedChanged += new System.EventHandler(this.CaptureOthersDeath_CheckedChanged);\n            // \n            // setScnPath\n            // \n            this.setScnPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.setScnPath.Location = new System.Drawing.Point(477, 12);\n            this.setScnPath.Name = \"setScnPath\";\n            this.setScnPath.Size = new System.Drawing.Size(35, 23);\n            this.setScnPath.TabIndex = 3;\n            this.setScnPath.Text = \"...\";\n            this.setScnPath.Click += new System.EventHandler(this.setScnPath_Click);\n            // \n            // screensList\n            // \n            this.screensList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.screensList.IntegralHeight = false;\n            this.screensList.ItemHeight = 15;\n            this.screensList.Location = new System.Drawing.Point(8, 41);\n            this.screensList.Name = \"screensList\";\n            this.screensList.Size = new System.Drawing.Size(252, 190);\n            this.screensList.Sorted = true;\n            this.screensList.TabIndex = 1;\n            this.screensList.SelectedIndexChanged += new System.EventHandler(this.screensList_SelectedIndexChanged);\n            this.screensList.MouseDown += new System.Windows.Forms.MouseEventHandler(this.screensList_MouseDown);\n            // \n            // screenPrev\n            // \n            this.screenPrev.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.screenPrev.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;\n            this.screenPrev.Location = new System.Drawing.Point(266, 41);\n            this.screenPrev.Name = \"screenPrev\";\n            this.screenPrev.Size = new System.Drawing.Size(246, 126);\n            this.screenPrev.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.screenPrev.TabIndex = 0;\n            this.screenPrev.TabStop = false;\n            this.screenPrev.Click += new System.EventHandler(this.screenPrev_Click);\n            // \n            // dispTime\n            // \n            this.dispTime.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));\n            this.dispTime.Location = new System.Drawing.Point(13, 289);\n            this.dispTime.Name = \"dispTime\";\n            this.dispTime.Size = new System.Drawing.Size(206, 20);\n            this.dispTime.TabIndex = 9;\n            this.dispTime.Text = \"Include Timestamp on images\";\n            this.dispTime.CheckedChanged += new System.EventHandler(this.dispTime_CheckedChanged);\n            // \n            // advancedTab\n            // \n            this.advancedTab.BackColor = System.Drawing.SystemColors.Control;\n            this.advancedTab.Controls.Add(this.subAdvancedTab);\n            this.advancedTab.Location = new System.Drawing.Point(4, 44);\n            this.advancedTab.Name = \"advancedTab\";\n            this.advancedTab.Size = new System.Drawing.Size(519, 322);\n            this.advancedTab.TabIndex = 12;\n            this.advancedTab.Text = \"Advanced\";\n            // \n            // subAdvancedTab\n            // \n            this.subAdvancedTab.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.subAdvancedTab.Controls.Add(this.advancedInfoTab);\n            this.subAdvancedTab.Controls.Add(this.advancedStaffDeco);\n            this.subAdvancedTab.Controls.Add(this.advancedStaffDoors);\n            this.subAdvancedTab.Location = new System.Drawing.Point(6, 3);\n            this.subAdvancedTab.Name = \"subAdvancedTab\";\n            this.subAdvancedTab.SelectedIndex = 0;\n            this.subAdvancedTab.Size = new System.Drawing.Size(506, 313);\n            this.subAdvancedTab.TabIndex = 0;\n            this.subAdvancedTab.SelectedIndexChanged += new System.EventHandler(this.subAdvancedTab_SelectedIndexChanged);\n            // \n            // advancedInfoTab\n            // \n            this.advancedInfoTab.BackColor = System.Drawing.SystemColors.Control;\n            this.advancedInfoTab.Controls.Add(this.fontDecrease);\n            this.advancedInfoTab.Controls.Add(this.fontIncrease);\n            this.advancedInfoTab.Controls.Add(this.groupBox16);\n            this.advancedInfoTab.Controls.Add(this.enableUOAAPI);\n            this.advancedInfoTab.Controls.Add(this.disableSmartCPU);\n            this.advancedInfoTab.Controls.Add(this.negotiate);\n            this.advancedInfoTab.Controls.Add(this.openRazorDataDir);\n            this.advancedInfoTab.Controls.Add(this.msglvl);\n            this.advancedInfoTab.Controls.Add(this.label17);\n            this.advancedInfoTab.Controls.Add(this.logPackets);\n            this.advancedInfoTab.Controls.Add(this.statusBox);\n            this.advancedInfoTab.Controls.Add(this.features);\n            this.advancedInfoTab.Location = new System.Drawing.Point(4, 24);\n            this.advancedInfoTab.Name = \"advancedInfoTab\";\n            this.advancedInfoTab.Padding = new System.Windows.Forms.Padding(3);\n            this.advancedInfoTab.Size = new System.Drawing.Size(498, 285);\n            this.advancedInfoTab.TabIndex = 0;\n            this.advancedInfoTab.Text = \"Information\";\n            // \n            // fontDecrease\n            // \n            this.fontDecrease.Location = new System.Drawing.Point(237, 136);\n            this.fontDecrease.Name = \"fontDecrease\";\n            this.fontDecrease.Size = new System.Drawing.Size(36, 23);\n            this.fontDecrease.TabIndex = 94;\n            this.fontDecrease.Text = \"-\";\n            this.fontDecrease.UseVisualStyleBackColor = true;\n            this.fontDecrease.Click += new System.EventHandler(this.fontDecrease_Click);\n            // \n            // fontIncrease\n            // \n            this.fontIncrease.Location = new System.Drawing.Point(279, 136);\n            this.fontIncrease.Name = \"fontIncrease\";\n            this.fontIncrease.Size = new System.Drawing.Size(36, 23);\n            this.fontIncrease.TabIndex = 93;\n            this.fontIncrease.Text = \"+\";\n            this.fontIncrease.UseVisualStyleBackColor = true;\n            this.fontIncrease.Click += new System.EventHandler(this.fontIncrease_Click);\n            // \n            // groupBox16\n            // \n            this.groupBox16.Controls.Add(this.lastBackup);\n            this.groupBox16.Controls.Add(this.openBackupFolder);\n            this.groupBox16.Controls.Add(this.setBackupFolder);\n            this.groupBox16.Controls.Add(this.createBackup);\n            this.groupBox16.Location = new System.Drawing.Point(6, 182);\n            this.groupBox16.Name = \"groupBox16\";\n            this.groupBox16.Size = new System.Drawing.Size(225, 99);\n            this.groupBox16.TabIndex = 92;\n            this.groupBox16.TabStop = false;\n            this.groupBox16.Text = \"Backup\";\n            // \n            // lastBackup\n            // \n            this.lastBackup.Location = new System.Drawing.Point(100, 55);\n            this.lastBackup.Name = \"lastBackup\";\n            this.lastBackup.Size = new System.Drawing.Size(119, 37);\n            this.lastBackup.TabIndex = 82;\n            this.lastBackup.Text = \"Last Backup: 01/01/2019 5:54PM\";\n            this.lastBackup.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // openBackupFolder\n            // \n            this.openBackupFolder.Location = new System.Drawing.Point(6, 55);\n            this.openBackupFolder.Name = \"openBackupFolder\";\n            this.openBackupFolder.Size = new System.Drawing.Size(88, 30);\n            this.openBackupFolder.TabIndex = 81;\n            this.openBackupFolder.Text = \"Open Folder\";\n            this.openBackupFolder.UseVisualStyleBackColor = true;\n            this.openBackupFolder.Click += new System.EventHandler(this.openBackupFolder_Click);\n            // \n            // setBackupFolder\n            // \n            this.setBackupFolder.Location = new System.Drawing.Point(134, 22);\n            this.setBackupFolder.Name = \"setBackupFolder\";\n            this.setBackupFolder.Size = new System.Drawing.Size(85, 30);\n            this.setBackupFolder.TabIndex = 80;\n            this.setBackupFolder.Text = \"Set Folder\";\n            this.setBackupFolder.UseVisualStyleBackColor = true;\n            this.setBackupFolder.Click += new System.EventHandler(this.setBackupFolder_Click);\n            // \n            // createBackup\n            // \n            this.createBackup.Location = new System.Drawing.Point(6, 22);\n            this.createBackup.Name = \"createBackup\";\n            this.createBackup.Size = new System.Drawing.Size(122, 30);\n            this.createBackup.TabIndex = 79;\n            this.createBackup.Text = \"Create Backup\";\n            this.createBackup.UseVisualStyleBackColor = true;\n            this.createBackup.Click += new System.EventHandler(this.createBackup_Click);\n            // \n            // enableUOAAPI\n            // \n            this.enableUOAAPI.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.enableUOAAPI.Checked = true;\n            this.enableUOAAPI.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.enableUOAAPI.Location = new System.Drawing.Point(240, 82);\n            this.enableUOAAPI.Name = \"enableUOAAPI\";\n            this.enableUOAAPI.Size = new System.Drawing.Size(146, 19);\n            this.enableUOAAPI.TabIndex = 91;\n            this.enableUOAAPI.Text = \"Enable UOA API\";\n            this.enableUOAAPI.CheckedChanged += new System.EventHandler(this.enableUOAAPI_CheckedChanged);\n            // \n            // disableSmartCPU\n            // \n            this.disableSmartCPU.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.disableSmartCPU.Location = new System.Drawing.Point(373, 136);\n            this.disableSmartCPU.Name = \"disableSmartCPU\";\n            this.disableSmartCPU.Size = new System.Drawing.Size(119, 22);\n            this.disableSmartCPU.TabIndex = 90;\n            this.disableSmartCPU.Text = \"Disable SmartCPU\";\n            this.disableSmartCPU.UseVisualStyleBackColor = true;\n            // \n            // negotiate\n            // \n            this.negotiate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.negotiate.Location = new System.Drawing.Point(240, 56);\n            this.negotiate.Name = \"negotiate\";\n            this.negotiate.Size = new System.Drawing.Size(197, 20);\n            this.negotiate.TabIndex = 89;\n            this.negotiate.Text = \"Negotiate features with server\";\n            this.negotiate.CheckedChanged += new System.EventHandler(this.negotiate_CheckedChanged);\n            // \n            // openRazorDataDir\n            // \n            this.openRazorDataDir.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.openRazorDataDir.Location = new System.Drawing.Point(392, 6);\n            this.openRazorDataDir.Name = \"openRazorDataDir\";\n            this.openRazorDataDir.Size = new System.Drawing.Size(100, 44);\n            this.openRazorDataDir.TabIndex = 88;\n            this.openRazorDataDir.Text = \"Open Data Directory\";\n            this.openRazorDataDir.UseVisualStyleBackColor = true;\n            this.openRazorDataDir.Click += new System.EventHandler(this.openRazorDataDir_Click);\n            // \n            // msglvl\n            // \n            this.msglvl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.msglvl.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.msglvl.Items.AddRange(new object[] {\n            \"Show All\",\n            \"Warnings & Errors\",\n            \"Errors Only\",\n            \"None\"});\n            this.msglvl.Location = new System.Drawing.Point(331, 107);\n            this.msglvl.Name = \"msglvl\";\n            this.msglvl.Size = new System.Drawing.Size(161, 23);\n            this.msglvl.TabIndex = 87;\n            // \n            // label17\n            // \n            this.label17.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.label17.Location = new System.Drawing.Point(237, 108);\n            this.label17.Name = \"label17\";\n            this.label17.Size = new System.Drawing.Size(99, 18);\n            this.label17.TabIndex = 86;\n            this.label17.Text = \"Razor messages:\";\n            this.label17.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\n            // \n            // logPackets\n            // \n            this.logPackets.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.logPackets.Location = new System.Drawing.Point(240, 27);\n            this.logPackets.Name = \"logPackets\";\n            this.logPackets.Size = new System.Drawing.Size(146, 23);\n            this.logPackets.TabIndex = 85;\n            this.logPackets.Text = \"Enable packet logging\";\n            this.logPackets.CheckedChanged += new System.EventHandler(this.logPackets_CheckedChanged);\n            // \n            // statusBox\n            // \n            this.statusBox.BackColor = System.Drawing.SystemColors.Control;\n            this.statusBox.BorderStyle = System.Windows.Forms.BorderStyle.None;\n            this.statusBox.Font = new System.Drawing.Font(\"Consolas\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.statusBox.HideSelection = false;\n            this.statusBox.Location = new System.Drawing.Point(6, 6);\n            this.statusBox.Multiline = true;\n            this.statusBox.Name = \"statusBox\";\n            this.statusBox.ReadOnly = true;\n            this.statusBox.Size = new System.Drawing.Size(225, 170);\n            this.statusBox.TabIndex = 84;\n            // \n            // features\n            // \n            this.features.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.features.Cursor = System.Windows.Forms.Cursors.No;\n            this.features.Location = new System.Drawing.Point(237, 164);\n            this.features.Multiline = true;\n            this.features.Name = \"features\";\n            this.features.ReadOnly = true;\n            this.features.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;\n            this.features.Size = new System.Drawing.Size(255, 85);\n            this.features.TabIndex = 83;\n            this.features.Visible = false;\n            // \n            // advancedStaffDeco\n            // \n            this.advancedStaffDeco.BackColor = System.Drawing.SystemColors.Control;\n            this.advancedStaffDeco.Controls.Add(this.itemAppendM);\n            this.advancedStaffDeco.Controls.Add(this.itemCopyToClipboard);\n            this.advancedStaffDeco.Controls.Add(this.itemSearch);\n            this.advancedStaffDeco.Controls.Add(this.itemMovable);\n            this.advancedStaffDeco.Controls.Add(this.itemRandomNumber);\n            this.advancedStaffDeco.Controls.Add(this.itemRandom);\n            this.advancedStaffDeco.Controls.Add(this.itemTileCount);\n            this.advancedStaffDeco.Controls.Add(this.itemTile);\n            this.advancedStaffDeco.Controls.Add(this.itemAdd);\n            this.advancedStaffDeco.Controls.Add(this.itemTree);\n            this.advancedStaffDeco.Controls.Add(this.artViewer);\n            this.advancedStaffDeco.Location = new System.Drawing.Point(4, 22);\n            this.advancedStaffDeco.Name = \"advancedStaffDeco\";\n            this.advancedStaffDeco.Padding = new System.Windows.Forms.Padding(3);\n            this.advancedStaffDeco.Size = new System.Drawing.Size(498, 287);\n            this.advancedStaffDeco.TabIndex = 1;\n            this.advancedStaffDeco.Text = \"Decoration\";\n            // \n            // itemAppendM\n            // \n            this.itemAppendM.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemAppendM.AutoSize = true;\n            this.itemAppendM.Location = new System.Drawing.Point(293, 215);\n            this.itemAppendM.Name = \"itemAppendM\";\n            this.itemAppendM.Size = new System.Drawing.Size(178, 19);\n            this.itemAppendM.TabIndex = 11;\n            this.itemAppendM.Text = \"Append [m to the command\";\n            this.itemAppendM.UseVisualStyleBackColor = true;\n            // \n            // itemCopyToClipboard\n            // \n            this.itemCopyToClipboard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemCopyToClipboard.AutoSize = true;\n            this.itemCopyToClipboard.Location = new System.Drawing.Point(293, 190);\n            this.itemCopyToClipboard.Name = \"itemCopyToClipboard\";\n            this.itemCopyToClipboard.Size = new System.Drawing.Size(199, 19);\n            this.itemCopyToClipboard.TabIndex = 10;\n            this.itemCopyToClipboard.Text = \"Copy command to the clipboard\";\n            this.itemCopyToClipboard.UseVisualStyleBackColor = true;\n            // \n            // itemSearch\n            // \n            this.itemSearch.AcceptsReturn = true;\n            this.itemSearch.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemSearch.Location = new System.Drawing.Point(6, 6);\n            this.itemSearch.Name = \"itemSearch\";\n            this.itemSearch.Size = new System.Drawing.Size(209, 23);\n            this.itemSearch.TabIndex = 9;\n            this.itemSearch.KeyDown += new System.Windows.Forms.KeyEventHandler(this.itemSearch_KeyDown);\n            this.itemSearch.LostFocus += new System.EventHandler(this.itemSearch_LostFocus);\n            // \n            // itemMovable\n            // \n            this.itemMovable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemMovable.AutoSize = true;\n            this.itemMovable.Location = new System.Drawing.Point(221, 109);\n            this.itemMovable.Name = \"itemMovable\";\n            this.itemMovable.Size = new System.Drawing.Size(72, 19);\n            this.itemMovable.TabIndex = 8;\n            this.itemMovable.Text = \"Movable\";\n            this.itemMovable.UseVisualStyleBackColor = true;\n            // \n            // itemRandomNumber\n            // \n            this.itemRandomNumber.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemRandomNumber.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.itemRandomNumber.Location = new System.Drawing.Point(220, 159);\n            this.itemRandomNumber.Name = \"itemRandomNumber\";\n            this.itemRandomNumber.Size = new System.Drawing.Size(75, 25);\n            this.itemRandomNumber.TabIndex = 7;\n            // \n            // itemRandom\n            // \n            this.itemRandom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemRandom.AutoSize = true;\n            this.itemRandom.Location = new System.Drawing.Point(220, 134);\n            this.itemRandom.Name = \"itemRandom\";\n            this.itemRandom.Size = new System.Drawing.Size(71, 19);\n            this.itemRandom.TabIndex = 6;\n            this.itemRandom.Text = \"Random\";\n            this.itemRandom.UseVisualStyleBackColor = true;\n            // \n            // itemTileCount\n            // \n            this.itemTileCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemTileCount.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.itemTileCount.Location = new System.Drawing.Point(221, 78);\n            this.itemTileCount.Name = \"itemTileCount\";\n            this.itemTileCount.Size = new System.Drawing.Size(75, 25);\n            this.itemTileCount.TabIndex = 4;\n            // \n            // itemTile\n            // \n            this.itemTile.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemTile.Location = new System.Drawing.Point(221, 42);\n            this.itemTile.Name = \"itemTile\";\n            this.itemTile.Size = new System.Drawing.Size(75, 30);\n            this.itemTile.TabIndex = 3;\n            this.itemTile.Text = \"Tile\";\n            this.itemTile.UseVisualStyleBackColor = true;\n            this.itemTile.Click += new System.EventHandler(this.itemTile_Click);\n            // \n            // itemAdd\n            // \n            this.itemAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemAdd.Location = new System.Drawing.Point(221, 6);\n            this.itemAdd.Name = \"itemAdd\";\n            this.itemAdd.Size = new System.Drawing.Size(75, 30);\n            this.itemAdd.TabIndex = 2;\n            this.itemAdd.Text = \"Add\";\n            this.itemAdd.UseVisualStyleBackColor = true;\n            this.itemAdd.Click += new System.EventHandler(this.itemAdd_Click);\n            this.itemAdd.MouseDown += new System.Windows.Forms.MouseEventHandler(this.itemAdd_MouseDown);\n            // \n            // itemTree\n            // \n            this.itemTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.itemTree.Location = new System.Drawing.Point(6, 35);\n            this.itemTree.Name = \"itemTree\";\n            this.itemTree.Size = new System.Drawing.Size(209, 246);\n            this.itemTree.TabIndex = 1;\n            this.itemTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.itemTree_AfterSelect);\n            this.itemTree.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.itemTree_MouseDoubleClick);\n            // \n            // advancedStaffDoors\n            // \n            this.advancedStaffDoors.BackColor = System.Drawing.SystemColors.Control;\n            this.advancedStaffDoors.Controls.Add(this.doorViewer);\n            this.advancedStaffDoors.Controls.Add(this.doorTree);\n            this.advancedStaffDoors.Controls.Add(this.doorSouthCW);\n            this.advancedStaffDoors.Controls.Add(this.doorSouthCCW);\n            this.advancedStaffDoors.Controls.Add(this.doorEastCW);\n            this.advancedStaffDoors.Controls.Add(this.doorEastCCW);\n            this.advancedStaffDoors.Controls.Add(this.doorNorthCCW);\n            this.advancedStaffDoors.Controls.Add(this.doorNorthCW);\n            this.advancedStaffDoors.Controls.Add(this.doorWestCCW);\n            this.advancedStaffDoors.Controls.Add(this.doorWestCW);\n            this.advancedStaffDoors.Location = new System.Drawing.Point(4, 22);\n            this.advancedStaffDoors.Name = \"advancedStaffDoors\";\n            this.advancedStaffDoors.Size = new System.Drawing.Size(498, 287);\n            this.advancedStaffDoors.TabIndex = 2;\n            this.advancedStaffDoors.Text = \"Doors\";\n            // \n            // doorTree\n            // \n            this.doorTree.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Left)));\n            this.doorTree.Location = new System.Drawing.Point(3, 3);\n            this.doorTree.Name = \"doorTree\";\n            this.doorTree.Size = new System.Drawing.Size(168, 281);\n            this.doorTree.TabIndex = 32;\n            this.doorTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.doorTree_AfterSelect);\n            // \n            // doorSouthCW\n            // \n            this.doorSouthCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorSouthCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorSouthCW.Image\")));\n            this.doorSouthCW.Location = new System.Drawing.Point(420, 84);\n            this.doorSouthCW.Name = \"doorSouthCW\";\n            this.doorSouthCW.Size = new System.Drawing.Size(75, 75);\n            this.doorSouthCW.TabIndex = 31;\n            this.doorSouthCW.UseVisualStyleBackColor = true;\n            this.doorSouthCW.Click += new System.EventHandler(this.doorSouthCW_Click);\n            this.doorSouthCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // doorSouthCCW\n            // \n            this.doorSouthCCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorSouthCCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorSouthCCW.Image\")));\n            this.doorSouthCCW.Location = new System.Drawing.Point(339, 84);\n            this.doorSouthCCW.Name = \"doorSouthCCW\";\n            this.doorSouthCCW.Size = new System.Drawing.Size(75, 75);\n            this.doorSouthCCW.TabIndex = 30;\n            this.doorSouthCCW.UseVisualStyleBackColor = true;\n            this.doorSouthCCW.Click += new System.EventHandler(this.doorSouthCCW_Click);\n            this.doorSouthCCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // doorEastCW\n            // \n            this.doorEastCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorEastCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorEastCW.Image\")));\n            this.doorEastCW.Location = new System.Drawing.Point(258, 84);\n            this.doorEastCW.Name = \"doorEastCW\";\n            this.doorEastCW.Size = new System.Drawing.Size(75, 75);\n            this.doorEastCW.TabIndex = 29;\n            this.doorEastCW.UseVisualStyleBackColor = true;\n            this.doorEastCW.Click += new System.EventHandler(this.doorEastCW_Click);\n            this.doorEastCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // doorEastCCW\n            // \n            this.doorEastCCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorEastCCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorEastCCW.Image\")));\n            this.doorEastCCW.Location = new System.Drawing.Point(177, 84);\n            this.doorEastCCW.Name = \"doorEastCCW\";\n            this.doorEastCCW.Size = new System.Drawing.Size(75, 75);\n            this.doorEastCCW.TabIndex = 28;\n            this.doorEastCCW.UseVisualStyleBackColor = true;\n            this.doorEastCCW.Click += new System.EventHandler(this.doorEastCCW_Click);\n            this.doorEastCCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // doorNorthCCW\n            // \n            this.doorNorthCCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorNorthCCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorNorthCCW.Image\")));\n            this.doorNorthCCW.Location = new System.Drawing.Point(420, 3);\n            this.doorNorthCCW.Name = \"doorNorthCCW\";\n            this.doorNorthCCW.Size = new System.Drawing.Size(75, 75);\n            this.doorNorthCCW.TabIndex = 27;\n            this.doorNorthCCW.UseVisualStyleBackColor = true;\n            this.doorNorthCCW.Click += new System.EventHandler(this.doorNorthCCW_Click);\n            this.doorNorthCCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // doorNorthCW\n            // \n            this.doorNorthCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorNorthCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorNorthCW.Image\")));\n            this.doorNorthCW.Location = new System.Drawing.Point(339, 3);\n            this.doorNorthCW.Name = \"doorNorthCW\";\n            this.doorNorthCW.Size = new System.Drawing.Size(75, 75);\n            this.doorNorthCW.TabIndex = 26;\n            this.doorNorthCW.UseVisualStyleBackColor = true;\n            this.doorNorthCW.Click += new System.EventHandler(this.doorNorthCW_Click);\n            this.doorNorthCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // doorWestCCW\n            // \n            this.doorWestCCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorWestCCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorWestCCW.Image\")));\n            this.doorWestCCW.Location = new System.Drawing.Point(258, 3);\n            this.doorWestCCW.Name = \"doorWestCCW\";\n            this.doorWestCCW.Size = new System.Drawing.Size(75, 75);\n            this.doorWestCCW.TabIndex = 25;\n            this.doorWestCCW.UseVisualStyleBackColor = true;\n            this.doorWestCCW.Click += new System.EventHandler(this.doorWestCCW_Click);\n            this.doorWestCCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // doorWestCW\n            // \n            this.doorWestCW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorWestCW.Image = ((System.Drawing.Image)(resources.GetObject(\"doorWestCW.Image\")));\n            this.doorWestCW.Location = new System.Drawing.Point(177, 3);\n            this.doorWestCW.Name = \"doorWestCW\";\n            this.doorWestCW.Size = new System.Drawing.Size(75, 75);\n            this.doorWestCW.TabIndex = 24;\n            this.doorWestCW.UseVisualStyleBackColor = true;\n            this.doorWestCW.Click += new System.EventHandler(this.doorWestCW_Click);\n            this.doorWestCW.MouseEnter += new System.EventHandler(this.DoorFacingEnter);\n            // \n            // aboutTab\n            // \n            this.aboutTab.Controls.Add(this.linkGitHub);\n            this.aboutTab.Controls.Add(this.lblCredits3);\n            this.aboutTab.Controls.Add(this.linkHelp);\n            this.aboutTab.Controls.Add(this.lblCredits2);\n            this.aboutTab.Controls.Add(this.label20);\n            this.aboutTab.Controls.Add(this.lblCredits1);\n            this.aboutTab.Controls.Add(this.aboutSubInfo);\n            this.aboutTab.Controls.Add(this.linkMain);\n            this.aboutTab.Controls.Add(this.label21);\n            this.aboutTab.Controls.Add(this.aboutVer);\n            this.aboutTab.Location = new System.Drawing.Point(4, 44);\n            this.aboutTab.Name = \"aboutTab\";\n            this.aboutTab.Size = new System.Drawing.Size(519, 322);\n            this.aboutTab.TabIndex = 9;\n            this.aboutTab.Text = \"About\";\n            // \n            // linkGitHub\n            // \n            this.linkGitHub.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.linkGitHub.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.linkGitHub.Location = new System.Drawing.Point(9, 157);\n            this.linkGitHub.Name = \"linkGitHub\";\n            this.linkGitHub.Size = new System.Drawing.Size(506, 20);\n            this.linkGitHub.TabIndex = 25;\n            this.linkGitHub.TabStop = true;\n            this.linkGitHub.Text = \"https://github.com/markdwags/Razor\";\n            this.linkGitHub.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            this.linkGitHub.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkGitHub_LinkClicked);\n            // \n            // lblCredits3\n            // \n            this.lblCredits3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.lblCredits3.Font = new System.Drawing.Font(\"Segoe UI Semibold\", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.lblCredits3.Location = new System.Drawing.Point(8, 259);\n            this.lblCredits3.Name = \"lblCredits3\";\n            this.lblCredits3.Size = new System.Drawing.Size(503, 20);\n            this.lblCredits3.TabIndex = 24;\n            this.lblCredits3.Text = \"Cross-platform implementation by DarkLotus\";\n            this.lblCredits3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // linkHelp\n            // \n            this.linkHelp.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.linkHelp.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.linkHelp.Location = new System.Drawing.Point(434, 10);\n            this.linkHelp.Name = \"linkHelp\";\n            this.linkHelp.Size = new System.Drawing.Size(78, 20);\n            this.linkHelp.TabIndex = 23;\n            this.linkHelp.TabStop = true;\n            this.linkHelp.Text = \"Need Help?\";\n            this.linkHelp.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            this.linkHelp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkHelp_LinkClicked);\n            // \n            // lblCredits2\n            // \n            this.lblCredits2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.lblCredits2.Font = new System.Drawing.Font(\"Segoe UI Semibold\", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.lblCredits2.Location = new System.Drawing.Point(9, 239);\n            this.lblCredits2.Name = \"lblCredits2\";\n            this.lblCredits2.Size = new System.Drawing.Size(503, 20);\n            this.lblCredits2.TabIndex = 22;\n            this.lblCredits2.Text = \"Major design changes including ClassicUO integration by Jaedan\";\n            this.lblCredits2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // label20\n            // \n            this.label20.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.label20.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.label20.Location = new System.Drawing.Point(12, 120);\n            this.label20.Name = \"label20\";\n            this.label20.Size = new System.Drawing.Size(499, 17);\n            this.label20.TabIndex = 21;\n            this.label20.Text = \"For feedback, support and the latest releases please visit:\\r\\n\";\n            this.label20.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // lblCredits1\n            // \n            this.lblCredits1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.lblCredits1.Font = new System.Drawing.Font(\"Segoe UI Semibold\", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.lblCredits1.Location = new System.Drawing.Point(6, 219);\n            this.lblCredits1.Name = \"lblCredits1\";\n            this.lblCredits1.Size = new System.Drawing.Size(506, 20);\n            this.lblCredits1.TabIndex = 19;\n            this.lblCredits1.Text = \"Razor was designed by Zippy, modified and maintained by Quick\";\n            this.lblCredits1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // aboutSubInfo\n            // \n            this.aboutSubInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.aboutSubInfo.Font = new System.Drawing.Font(\"Segoe UI\", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.aboutSubInfo.Location = new System.Drawing.Point(6, 75);\n            this.aboutSubInfo.Name = \"aboutSubInfo\";\n            this.aboutSubInfo.Size = new System.Drawing.Size(506, 19);\n            this.aboutSubInfo.TabIndex = 17;\n            this.aboutSubInfo.Text = \"Community Edition\";\n            this.aboutSubInfo.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // linkMain\n            // \n            this.linkMain.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.linkMain.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.linkMain.Location = new System.Drawing.Point(9, 137);\n            this.linkMain.Name = \"linkMain\";\n            this.linkMain.Size = new System.Drawing.Size(506, 20);\n            this.linkMain.TabIndex = 16;\n            this.linkMain.TabStop = true;\n            this.linkMain.Text = \"https://www.razorce.com\";\n            this.linkMain.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            this.linkMain.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked);\n            // \n            // label21\n            // \n            this.label21.AutoSize = true;\n            this.label21.Font = new System.Drawing.Font(\"Segoe UI Semibold\", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.label21.Location = new System.Drawing.Point(52, 98);\n            this.label21.Name = \"label21\";\n            this.label21.Size = new System.Drawing.Size(0, 15);\n            this.label21.TabIndex = 15;\n            this.label21.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // aboutVer\n            // \n            this.aboutVer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));\n            this.aboutVer.Font = new System.Drawing.Font(\"Segoe UI\", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.aboutVer.Location = new System.Drawing.Point(6, 40);\n            this.aboutVer.Name = \"aboutVer\";\n            this.aboutVer.Size = new System.Drawing.Size(506, 35);\n            this.aboutVer.TabIndex = 14;\n            this.aboutVer.Text = \"Razor v{0}\";\n            this.aboutVer.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;\n            // \n            // cooldownGumpBox\n            // \n            this.cooldownGumpBox.Controls.Add(this.cooldownHeight);\n            this.cooldownGumpBox.Controls.Add(this.lblCooldownHeight);\n            this.cooldownGumpBox.Controls.Add(this.cooldownWidth);\n            this.cooldownGumpBox.Controls.Add(this.lblCooldownWidth);\n            this.cooldownGumpBox.Location = new System.Drawing.Point(14, 124);\n            this.cooldownGumpBox.Name = \"cooldownGumpBox\";\n            this.cooldownGumpBox.Size = new System.Drawing.Size(232, 151);\n            this.cooldownGumpBox.TabIndex = 133;\n            this.cooldownGumpBox.TabStop = false;\n            this.cooldownGumpBox.Text = \"Cooldowns:\";\n            // \n            // cooldownHeight\n            // \n            this.cooldownHeight.Location = new System.Drawing.Point(75, 26);\n            this.cooldownHeight.Name = \"cooldownHeight\";\n            this.cooldownHeight.Size = new System.Drawing.Size(36, 23);\n            this.cooldownHeight.TabIndex = 12;\n            this.cooldownHeight.TextChanged += new System.EventHandler(this.cooldownHeight_TextChanged);\n            // \n            // lblCooldownHeight\n            // \n            this.lblCooldownHeight.AutoSize = true;\n            this.lblCooldownHeight.Location = new System.Drawing.Point(9, 29);\n            this.lblCooldownHeight.Name = \"lblCooldownHeight\";\n            this.lblCooldownHeight.Size = new System.Drawing.Size(64, 15);\n            this.lblCooldownHeight.TabIndex = 11;\n            this.lblCooldownHeight.Text = \"Bar height:\";\n            // \n            // cooldownWidth\n            // \n            this.cooldownWidth.Location = new System.Drawing.Point(75, 54);\n            this.cooldownWidth.Name = \"cooldownWidth\";\n            this.cooldownWidth.Size = new System.Drawing.Size(36, 23);\n            this.cooldownWidth.TabIndex = 10;\n            this.cooldownWidth.TextChanged += new System.EventHandler(this.cooldownWidth_TextChanged);\n            // \n            // lblCooldownWidth\n            // \n            this.lblCooldownWidth.AutoSize = true;\n            this.lblCooldownWidth.Location = new System.Drawing.Point(9, 57);\n            this.lblCooldownWidth.Name = \"lblCooldownWidth\";\n            this.lblCooldownWidth.Size = new System.Drawing.Size(60, 15);\n            this.lblCooldownWidth.TabIndex = 9;\n            this.lblCooldownWidth.Text = \"Bar width:\";\n            // \n            // artViewer\n            // \n            this.artViewer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));\n            this.artViewer.Animate = false;\n            this.artViewer.Art = Assistant.UI.Art.Items;\n            this.artViewer.ArtIndex = 0;\n            this.artViewer.Hue = 0;\n            this.artViewer.Location = new System.Drawing.Point(302, 6);\n            this.artViewer.Name = \"artViewer\";\n            this.artViewer.ResizeTallItems = false;\n            this.artViewer.RoomView = true;\n            this.artViewer.ShowHexID = true;\n            this.artViewer.ShowID = true;\n            this.artViewer.Size = new System.Drawing.Size(190, 178);\n            this.artViewer.TabIndex = 0;\n            // \n            // doorViewer\n            // \n            this.doorViewer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) \n            | System.Windows.Forms.AnchorStyles.Right)));\n            this.doorViewer.Animate = false;\n            this.doorViewer.Art = Assistant.UI.Art.Items;\n            this.doorViewer.ArtIndex = 0;\n            this.doorViewer.Hue = 0;\n            this.doorViewer.Location = new System.Drawing.Point(177, 165);\n            this.doorViewer.MaximumSize = new System.Drawing.Size(318, 318);\n            this.doorViewer.Name = \"doorViewer\";\n            this.doorViewer.ResizeTallItems = false;\n            this.doorViewer.RoomView = true;\n            this.doorViewer.ShowHexID = true;\n            this.doorViewer.ShowID = true;\n            this.doorViewer.Size = new System.Drawing.Size(318, 119);\n            this.doorViewer.TabIndex = 33;\n            // \n            // MainForm\n            // \n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\n            this.ClientSize = new System.Drawing.Size(530, 372);\n            this.Controls.Add(this.tabs);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.MinimumSize = new System.Drawing.Size(546, 411);\n            this.Name = \"MainForm\";\n            this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;\n            this.Text = \"Razor v{0}\";\n            this.Activated += new System.EventHandler(this.MainForm_Activated);\n            this.Closing += new System.ComponentModel.CancelEventHandler(this.MainForm_Closing);\n            this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);\n            this.Load += new System.EventHandler(this.MainForm_StartLoad);\n            this.ResizeEnd += new System.EventHandler(this.MainForm_ResizeEnd);\n            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.MainForm_KeyDown);\n            this.Move += new System.EventHandler(this.MainForm_Move);\n            this.Resize += new System.EventHandler(this.MainForm_Resize);\n            this.tabs.ResumeLayout(false);\n            this.generalTab.ResumeLayout(false);\n            this.subGeneralTab.ResumeLayout(false);\n            this.subGenTab.ResumeLayout(false);\n            this.groupBox15.ResumeLayout(false);\n            ((System.ComponentModel.ISupportInitialize)(this.opacity)).EndInit();\n            this.groupBox4.ResumeLayout(false);\n            this.groupBox4.PerformLayout();\n            this.moreOptTab.ResumeLayout(false);\n            this.optionsTabCtrl.ResumeLayout(false);\n            this.subOptionsSpeechTab.ResumeLayout(false);\n            this.subOptionsSpeechTab.PerformLayout();\n            this.subOptionsTargetTab.ResumeLayout(false);\n            this.subOptionsTargetTab.PerformLayout();\n            this.groupSmartTarget.ResumeLayout(false);\n            this.groupSmartTarget.PerformLayout();\n            this.subOptionsMiscTab.ResumeLayout(false);\n            this.subOptionsMiscTab.PerformLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.lightLevelBar)).EndInit();\n            this.displayTab.ResumeLayout(false);\n            this.displayCountersTabCtrl.ResumeLayout(false);\n            this.subDisplayTab.ResumeLayout(false);\n            this.subDisplayTab.PerformLayout();\n            this.groupBox11.ResumeLayout(false);\n            this.groupBox11.PerformLayout();\n            this.groupBox3.ResumeLayout(false);\n            this.groupBox3.PerformLayout();\n            this.subCountersTab.ResumeLayout(false);\n            this.subCountersTab.PerformLayout();\n            this.groupBox2.ResumeLayout(false);\n            this.subBandageTimerTab.ResumeLayout(false);\n            this.subBandageTimerTab.PerformLayout();\n            this.subOverheadTab.ResumeLayout(false);\n            this.subOverheadTab.PerformLayout();\n            this.subWaypoints.ResumeLayout(false);\n            this.subWaypoints.PerformLayout();\n            this.subBuffsDebuffs.ResumeLayout(false);\n            this.subBuffsDebuffs.PerformLayout();\n            this.buffBarGroupBox.ResumeLayout(false);\n            this.buffBarGroupBox.PerformLayout();\n            this.dressTab.ResumeLayout(false);\n            this.groupBox6.ResumeLayout(false);\n            this.groupBox5.ResumeLayout(false);\n            this.skillsTab.ResumeLayout(false);\n            this.skillsTab.PerformLayout();\n            this.agentsTab.ResumeLayout(false);\n            this.agentGroup.ResumeLayout(false);\n            this.filtersTab.ResumeLayout(false);\n            this.filterTabs.ResumeLayout(false);\n            this.subFilterTab.ResumeLayout(false);\n            this.subFilterTab.PerformLayout();\n            this.subFilterText.ResumeLayout(false);\n            this.gbFilterText.ResumeLayout(false);\n            this.gbFilterText.PerformLayout();\n            this.gbFilterMessages.ResumeLayout(false);\n            this.gbFilterMessages.PerformLayout();\n            this.subFilterSoundMusic.ResumeLayout(false);\n            this.subFilterSoundMusic.PerformLayout();\n            this.subFilterTargets.ResumeLayout(false);\n            this.subFilterTargets.PerformLayout();\n            this.hotkeysTab.ResumeLayout(false);\n            this.hotkeysTab.PerformLayout();\n            this.groupBox8.ResumeLayout(false);\n            this.groupBox8.PerformLayout();\n            this.macrosTab.ResumeLayout(false);\n            this.tabControl2.ResumeLayout(false);\n            this.subMacrosTab.ResumeLayout(false);\n            this.subMacrosTab.PerformLayout();\n            this.macroActGroup.ResumeLayout(false);\n            this.subMacrosOptionsTab.ResumeLayout(false);\n            this.subMacrosOptionsTab.PerformLayout();\n            this.macroVariableGroup.ResumeLayout(false);\n            this.scriptsTab.ResumeLayout(false);\n            this.subTabScripts.ResumeLayout(false);\n            this.subScripts.ResumeLayout(false);\n            this.subScripts.PerformLayout();\n            this.scriptSplitContainer.Panel1.ResumeLayout(false);\n            this.scriptSplitContainer.Panel1.PerformLayout();\n            this.scriptSplitContainer.Panel2.ResumeLayout(false);\n            ((System.ComponentModel.ISupportInitialize)(this.scriptSplitContainer)).EndInit();\n            this.scriptSplitContainer.ResumeLayout(false);\n            ((System.ComponentModel.ISupportInitialize)(this.scriptEditor)).EndInit();\n            this.subScriptOptions.ResumeLayout(false);\n            this.subScriptOptions.PerformLayout();\n            this.scriptVariablesBox.ResumeLayout(false);\n            this.friendsTab.ResumeLayout(false);\n            this.friendsTab.PerformLayout();\n            this.friendsGroupBox.ResumeLayout(false);\n            this.friendsGroupBox.PerformLayout();\n            this.screenshotTab.ResumeLayout(false);\n            this.screenshotTab.PerformLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.screenPrev)).EndInit();\n            this.advancedTab.ResumeLayout(false);\n            this.subAdvancedTab.ResumeLayout(false);\n            this.advancedInfoTab.ResumeLayout(false);\n            this.advancedInfoTab.PerformLayout();\n            this.groupBox16.ResumeLayout(false);\n            this.advancedStaffDeco.ResumeLayout(false);\n            this.advancedStaffDeco.PerformLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.itemRandomNumber)).EndInit();\n            ((System.ComponentModel.ISupportInitialize)(this.itemTileCount)).EndInit();\n            this.advancedStaffDoors.ResumeLayout(false);\n            this.aboutTab.ResumeLayout(false);\n            this.aboutTab.PerformLayout();\n            this.cooldownGumpBox.ResumeLayout(false);\n            this.cooldownGumpBox.PerformLayout();\n            this.ResumeLayout(false);\n\n        }\n\n        private System.Windows.Forms.CheckBox disableScriptStopwatch;\n\n        private System.Windows.Forms.CheckBox enableHighlight;\n\n        private System.Windows.Forms.CheckBox defaultScriptDelay;\n\n        private System.Windows.Forms.TabPage subBuffsDebuffs;\n\n        #endregion\n\n        private TabPage scriptsTab;\n        private TabControl subTabScripts;\n        private TabPage subScripts;\n        private Button saveScript;\n        private Button newScript;\n        private Button setScriptHotkey;\n        private Button recordScript;\n        private Button playScript;\n        private System.Windows.Forms.TabPage subScriptOptions;\n        private GroupBox scriptVariablesBox;\n        private Button changeScriptVariable;\n        private Button removeScriptVariable;\n        private Button addScriptVariable;\n        private ListBox scriptVariables;\n        private CheckBox autoSaveScript;\n        private CheckBox autoSaveScriptPlay;\n        private CheckBox scriptDisablePlayFinish;\n        private TabPage friendsTab;\n        private CheckBox highlightFriend;\n        private CheckBox autoAcceptParty;\n        private CheckBox nextPrevIgnoresFriends;\n        private CheckBox autoFriend;\n        private GroupBox friendsGroupBox;\n        private Button friendsGroupRemove;\n        private Button friendsGroupAdd;\n        private Button friendClearList;\n        private Button friendRemoveSelected;\n        private Button friendAddTarget;\n        private ListBox friendsList;\n        private ComboBox friendsGroup;\n        private CheckBox friendsListEnabled;\n        private CheckBox showFriendOverhead;\n        private Button setFriendsFormatHue;\n        private TextBox friendOverheadFormat;\n        private Label friendFormat;\n        private Button scriptGuide;\n        private CheckBox showPartyFriendOverhead;\n        private TabPage subWaypoints;\n        private System.Windows.Forms.CheckBox waypointOnDeath;\n        private Label lblWaypointTiles;\n        private TextBox hideWaypointDist;\n        private System.Windows.Forms.CheckBox hideWaypointWithin;\n        private TextBox txtWaypointDistanceSec;\n        private Label lblWaypointSeconds;\n        private System.Windows.Forms.CheckBox showWaypointDistance;\n        private System.Windows.Forms.CheckBox showWaypointOverhead;\n        private Button btnRemoveSelectedWaypoint;\n        private Button btnHideWaypoint;\n        private Button btnUseCurrentLoc;\n        private TextBox txtWaypointName;\n        private Label lblWaypointY;\n        private Label lblWaypointX;\n        private TextBox txtWaypointX;\n        private TextBox txtWaypointY;\n        private Label lblWaypoint;\n        private Button btnAddWaypoint;\n        private System.Windows.Forms.ListBox waypointList;\n        private TabPage filtersTab;\n        private TabControl filterTabs;\n        private TabPage subFilterTab;\n        private ComboBox daemonAnimationList;\n        private CheckBox filterDaemonGraphics;\n        private ComboBox drakeAnimationList;\n        private CheckBox filterDrakeGraphics;\n        private ComboBox dragonAnimationList;\n        private CheckBox filterDragonGraphics;\n        private CheckedListBox filters;\n        private TabPage subFilterTargets;\n        private Label lblTargetFilter;\n        private Button targetFilterClear;\n        private Button targetFilterRemove;\n        private Button targetFilterAdd;\n        private ListBox targetFilter;\n        private CheckBox targetFilterEnabled;\n        private TabPage subOverheadTab;\n        private CheckBox showOverheadMessages;\n        private Button cliLocSearch;\n        private TextBox cliLocTextSearch;\n        private Label lblOhSearch;\n        private ListView cliLocSearchView;\n        private ColumnHeader cliLocSearchNumber;\n        private ColumnHeader cliLocSearchText;\n        private Label label13;\n        private TextBox overheadFormat;\n        private Button setOverheadMessage;\n        private System.Windows.Forms.ListView cliLocOverheadView;\n        private ColumnHeader cliLocOriginal;\n        private ColumnHeader cliLocOverheadMessage;\n        private System.Windows.Forms.Button editOverheadMessage;\n        private System.Windows.Forms.Button setColorHue;\n        private System.Windows.Forms.Button removeOverheadMessage;\n        private Label label14;\n        private System.Windows.Forms.RadioButton unicodeStyle;\n        private System.Windows.Forms.RadioButton asciiStyle;\n        private CheckBox overrideSpellFormat;\n        private CheckBox reequipHandsPotion;\n        private Button agentSetHotKey;\n        private TabPage subFilterText;\n        private GroupBox gbFilterText;\n        private Button removeFilterText;\n        private Button addFilterText;\n        private ListBox textFilterList;\n        private GroupBox gbFilterMessages;\n        private CheckBox filterOverheadMessages;\n        private Label lblFilterDelaySeconds;\n        private Label lblFilterDelay;\n        private TextBox filterDelaySeconds;\n        private CheckBox filterRazorMessages;\n        private CheckBox filterSystemMessages;\n        private CheckBox filterSnoop;\n        private CheckBox enableTextFilter;\n        private System.Windows.Forms.CheckBox disableScriptTooltips;\n        private SplitContainer scriptSplitContainer;\n        private TreeView scriptTree;\n        private TextBox scriptFilter;\n        private FastColoredTextBoxNS.FastColoredTextBox scriptEditor;\n        private Label scriptHotkey;\n        private Button openScreenshotFolder;\n        private CheckBox buyAgentIgnoreGold;\n        private CheckBox nextPrevAbcOrder;\n        private ComboBox wyrmAnimationList;\n        private CheckBox filterWhiteWyrm;\n        private TextBox hkCommand;\n        private Label hkCmdLabel;\n        private ColumnHeader cliLocSound;\n        private System.Windows.Forms.Button setSound;\n        private TabControl subAdvancedTab;\n        private TabPage advancedInfoTab;\n        private Button fontDecrease;\n        private Button fontIncrease;\n        private GroupBox groupBox16;\n        private Label lastBackup;\n        private Button openBackupFolder;\n        private Button setBackupFolder;\n        private Button createBackup;\n        private CheckBox enableUOAAPI;\n        private Button disableSmartCPU;\n        private CheckBox negotiate;\n        private Button openRazorDataDir;\n        private ComboBox msglvl;\n        private Label label17;\n        private CheckBox logPackets;\n        private TextBox statusBox;\n        private TextBox features;\n        private TabPage advancedStaffDeco;\n        private UI.ArtViewer artViewer;\n        private TreeView itemTree;\n        private NumericUpDown itemRandomNumber;\n        private CheckBox itemRandom;\n        private NumericUpDown itemTileCount;\n        private Button itemTile;\n        private Button itemAdd;\n        private CheckBox itemMovable;\n        private TabPage advancedStaffDoors;\n        private Button doorSouthCW;\n        private Button doorSouthCCW;\n        private Button doorEastCW;\n        private Button doorEastCCW;\n        private Button doorNorthCCW;\n        private Button doorNorthCW;\n        private Button doorWestCCW;\n        private Button doorWestCW;\n        private TreeView doorTree;\n        private UI.ArtViewer doorViewer;\n        private TextBox itemSearch;\n        private CheckBox itemCopyToClipboard;\n        private CheckBox itemAppendM;\n        private FastColoredTextBoxNS.DocumentMap scriptDocMap;\n        private System.Windows.Forms.CheckBox playEmoteSound;\n        private GroupBox buffBarGroupBox;\n        private ComboBox buffBarSort;\n        private Label lblBuffSortBy;\n        private TextBox buffBarWidth;\n        private Label lblBuffBarWidth;\n        private CheckBox showBuffIcons;\n        private CheckBox showBuffDebuffGump;\n        private TextBox buffBarHeight;\n        private Label lblBuffBarHeight;\n        private CheckBox useBlackBuffDebuffBg;\n        private ComboBox showBuffDebuffTimeType;\n        private Label lblShowBuffTime;\n        private GroupBox cooldownGumpBox;\n        private TextBox cooldownHeight;\n        private Label lblCooldownHeight;\n        private TextBox cooldownWidth;\n        private Label lblCooldownWidth;\n    }\n}\n"
  },
  {
    "path": "Razor/UI/Razor.cs",
    "content": "﻿#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Drawing;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing System.Windows.Forms;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing Assistant.Filters;\r\nusing Assistant.Macros;\r\nusing System.Diagnostics;\r\nusing System.Xml;\r\nusing Assistant.Boat;\r\nusing Assistant.Agents;\r\nusing Assistant.Core;\r\nusing Assistant.Scripts;\r\nusing Assistant.Scripts.Engine;\r\nusing Assistant.UI;\r\nusing Ultima;\r\nusing Art = Assistant.UI.Art;\r\nusing ContainerLabels = Assistant.UI.ContainerLabels;\r\nusing Exception = System.Exception;\r\n\r\nnamespace Assistant\r\n{\r\n    public partial class MainForm\r\n    {\r\n        protected override void WndProc(ref Message msg)\r\n        {\r\n            if (msg.Msg == Client.WM_UONETEVENT)\r\n                msg.Result =\r\n                    (IntPtr) (Client.Instance.OnMessage(this, (uint) msg.WParam.ToInt32(), msg.LParam.ToInt32())\r\n                        ? 1\r\n                        : 0);\r\n            else if (msg.Msg == Client.WM_COPYDATA)\r\n                msg.Result = (IntPtr) (Client.Instance.OnCopyData(msg.WParam, msg.LParam) ? 1 : 0);\r\n            else if (Config.GetBool(\"EnableUOAAPI\") && msg.Msg >= (int) UOAssist.UOAMessage.First &&\r\n                     msg.Msg <= (int) UOAssist.UOAMessage.Last)\r\n                msg.Result = (IntPtr) UOAssist.OnUOAMessage(this, msg.Msg, msg.WParam.ToInt32(), msg.LParam.ToInt32());\r\n            else\r\n                base.WndProc(ref msg);\r\n        }\r\n\r\n        private void DisableCloseButton()\r\n        {\r\n            Platform.DisableCloseButton(this.Handle);\r\n            m_CanClose = false;\r\n        }\r\n\r\n        private void MainForm_StartLoad(object sender, System.EventArgs e)\r\n        {\r\n            Hide();\r\n            new StatsTimer(this).Start();\r\n            Language.LoadControlNames(this);\r\n\r\n            FriendsManager.SetControls(friendsGroup, friendsList);\r\n            DressList.SetControls(dressList, dressItems);\r\n            TargetFilterManager.SetControls(targetFilter);\r\n            SoundMusicManager.SetControls(soundFilterList, playableMusicList);\r\n            ScriptManager.SetControls(scriptEditor, scriptTree, scriptVariables);\r\n            WaypointManager.SetControls(waypointList);\r\n            OverheadManager.SetControls(cliLocOverheadView);\r\n            TextFilterManager.SetControls(textFilterList);\r\n            ScriptManager.SetEditor(scriptEditor);\r\n\r\n            scriptDocMap.Target = scriptEditor;\r\n\r\n            bool st = Config.GetBool(\"Systray\");\r\n            taskbar.Checked = this.ShowInTaskbar = !st;\r\n            systray.Checked = m_NotifyIcon.Visible = st;\r\n\r\n            UpdateTitle();\r\n\r\n            Engine.ActiveWindow = this;\r\n\r\n            DisableCloseButton();\r\n\r\n            if (!Client.Instance.InstallHooks(this.Handle))\r\n            {\r\n                m_CanClose = true;\r\n                SplashScreen.End();\r\n                this.Close();\r\n                System.Diagnostics.Process.GetCurrentProcess().Kill();\r\n            }\r\n        }\r\n\r\n        public void MainForm_EndLoad()\r\n        {\r\n            Ultima.Multis.PostHSFormat = Engine.UsePostHSChanges;\r\n\r\n            PacketsTable.AdjustPacketSizeByVersion(Engine.ClientVersion);\r\n\r\n            SplashScreen.Message = LocString.Welcome;\r\n            InitConfig();\r\n            Show();\r\n            BringToFront();\r\n            tabs_IndexChanged(this, null); // load first tab\r\n            ScriptManager.SetEditor(scriptEditor);\r\n\r\n            m_ProfileConfirmLoad = false;\r\n            Config.SetupProfilesList(profiles, Config.CurrentProfile.Name);\r\n            m_ProfileConfirmLoad = true;\r\n\r\n            showWelcome.Checked = Config.GetAppSetting<int>(\"ShowWelcome\") == 1;\r\n\r\n            m_Tip.Active = true;\r\n            m_Tip.SetToolTip(titleStr, Language.GetString(LocString.TitleBarTip));\r\n\r\n            SplashScreen.End();\r\n        }\r\n\r\n        private bool m_Initializing = false;\r\n\r\n        public void InitConfig()\r\n        {\r\n            m_Initializing = true;\r\n\r\n            opacity.SafeAction(s =>\r\n            {\r\n                s.Value = Config.GetInt(\"Opacity\");\r\n                s.AutoSize = false;\r\n            });\r\n\r\n            this.SafeAction(s =>\r\n            {\r\n                s.Opacity = ((float) opacity.Value) / 100.0;\r\n                s.TopMost = s.alwaysTop.Checked = Config.GetBool(\"AlwaysOnTop\");\r\n                s.Location = new System.Drawing.Point(Config.GetInt(\"WindowX\"), Config.GetInt(\"WindowY\"));\r\n                s.TopLevel = true;\r\n                if (!IsOnScreen(s))\r\n                {\r\n                    s.Location = new System.Drawing.Point(400, 400);\r\n                }\r\n            });\r\n\r\n            opacityLabel.SafeAction(s => { s.Text = Language.Format(LocString.OpacityA1, opacity.Value); });\r\n\r\n            spellUnequip.SafeAction(s => { });\r\n\r\n            spellUnequip.SafeAction(s => { s.Checked = Config.GetBool(\"SpellUnequip\"); });\r\n\r\n            ltRange.SafeAction(s =>\r\n            {\r\n                s.Enabled = rangeCheckLT.Checked = Config.GetBool(\"RangeCheckLT\");\r\n                s.Text = Config.GetInt(\"LTRange\").ToString();\r\n            });\r\n\r\n            counters.SafeAction(s =>\r\n            {\r\n                s.BeginUpdate();\r\n\r\n                if (Config.GetBool(\"SortCounters\"))\r\n                {\r\n                    s.Sorting = SortOrder.None;\r\n                    s.ListViewItemSorter = CounterLVIComparer.Instance;\r\n                    s.Sort();\r\n                }\r\n                else\r\n                {\r\n                    s.ListViewItemSorter = null;\r\n                    s.Sorting = SortOrder.Ascending;\r\n                }\r\n\r\n                s.EndUpdate();\r\n                s.Refresh();\r\n            });\r\n\r\n            incomingMob.SafeAction(s => { s.Checked = Config.GetBool(\"ShowMobNames\"); });\r\n\r\n            incomingCorpse.SafeAction(s => { s.Checked = Config.GetBool(\"ShowCorpseNames\"); });\r\n\r\n            checkNewConts.SafeAction(s => { s.Checked = Config.GetBool(\"AutoSearch\"); });\r\n\r\n\r\n            excludePouches.SafeAction(s =>\r\n            {\r\n                s.Checked = Config.GetBool(\"NoSearchPouches\");\r\n                s.Enabled = checkNewConts.Checked;\r\n            });\r\n\r\n            warnNum.SafeAction(s =>\r\n            {\r\n                warnNum.Enabled = warnCount.Checked = Config.GetBool(\"CounterWarn\");\r\n                warnNum.Text = Config.GetInt(\"CounterWarnAmount\").ToString();\r\n            });\r\n\r\n            QueueActions.SafeAction(s => { s.Checked = Config.GetBool(\"QueueActions\"); });\r\n\r\n            queueTargets.SafeAction(s => { s.Checked = Config.GetBool(\"QueueTargets\"); });\r\n\r\n            chkForceSpeechHue.SafeAction(s => { s.Checked = setSpeechHue.Enabled = Config.GetBool(\"ForceSpeechHue\"); });\r\n\r\n            chkForceSpellHue.SafeAction(s =>\r\n            {\r\n                chkForceSpellHue.Checked = setBeneHue.Enabled =\r\n                    setNeuHue.Enabled = setHarmHue.Enabled = Config.GetBool(\"ForceSpellHue\");\r\n            });\r\n\r\n            lthilight.SafeAction(s =>\r\n            {\r\n                if (Config.GetInt(\"LTHilight\") != 0)\r\n                {\r\n                    InitPreviewHue(s, \"LTHilight\");\r\n                    s.Checked = setLTHilight.Enabled = true;\r\n                }\r\n                else\r\n                {\r\n                    s.Checked = setLTHilight.Enabled = false;\r\n                }\r\n            });\r\n\r\n            txtSpellFormat.SafeAction(s => { s.Text = Config.GetString(\"SpellFormat\"); });\r\n\r\n            txtObjDelay.SafeAction(s => { s.Text = Config.GetInt(\"ObjectDelay\").ToString(); });\r\n\r\n            chkStealth.SafeAction(s => { s.Checked = Config.GetBool(\"CountStealthSteps\"); });\r\n\r\n            radioUO.SafeAction(s => { s.Checked = !(radioFull.Checked = Config.GetBool(\"CapFullScreen\")); });\r\n\r\n            screenPath.SafeAction(s => { s.Text = Config.GetString(\"CapPath\"); });\r\n\r\n            dispTime.SafeAction(s => { s.Checked = Config.GetBool(\"CapTimeStamp\"); });\r\n\r\n            blockDis.SafeAction(s => { s.Checked = Config.GetBool(\"BlockDismount\"); });\r\n\r\n            autoOpenDoors.SafeAction(s => { s.Checked = Config.GetBool(\"AutoOpenDoors\"); });\r\n\r\n            objectDelay.SafeAction(s => { s.Checked = Config.GetBool(\"ObjectDelayEnabled\"); });\r\n\r\n            txtObjDelay.SafeAction(s => { s.Enabled = Config.GetBool(\"ObjectDelayEnabled\"); });\r\n\r\n            msglvl.SafeAction(s => { s.SelectedIndex = Config.GetInt(\"MessageLevel\"); });\r\n\r\n            imgFmt.SafeAction(s =>\r\n            {\r\n                try\r\n                {\r\n                    s.SelectedItem = Config.GetString(\"ImageFormat\");\r\n                }\r\n                catch\r\n                {\r\n                    s.SelectedIndex = 0;\r\n                    Config.SetProperty(\"ImageFormat\", \"jpg\");\r\n                }\r\n            });\r\n\r\n            lblExHue.SafeAction(s => { InitPreviewHue(s, \"ExemptColor\"); });\r\n\r\n            lblMsgHue.SafeAction(s => { InitPreviewHue(s, \"SysColor\"); });\r\n\r\n            lblWarnHue.SafeAction(s => { InitPreviewHue(s, \"WarningColor\"); });\r\n\r\n            chkForceSpeechHue.SafeAction(s => { InitPreviewHue(s, \"SpeechHue\"); });\r\n\r\n            lblBeneHue.SafeAction(s => { InitPreviewHue(s, \"BeneficialSpellHue\"); });\r\n\r\n            lblHarmHue.SafeAction(s => { InitPreviewHue(s, \"HarmfulSpellHue\"); });\r\n\r\n            lblNeuHue.SafeAction(s => { InitPreviewHue(s, \"NeutralSpellHue\"); });\r\n\r\n            undressConflicts.SafeAction(s => { s.Checked = Config.GetBool(\"UndressConflicts\"); });\r\n\r\n            taskbar.SafeAction(s => { s.Checked = !(systray.Checked = Config.GetBool(\"Systray\")); });\r\n\r\n            titlebarImages.SafeAction(s => { s.Checked = Config.GetBool(\"TitlebarImages\"); });\r\n\r\n            highlightSpellReags.SafeAction(s => { s.Checked = Config.GetBool(\"HighlightReagents\"); });\r\n\r\n            dispDelta.SafeAction(s => { s.Checked = Config.GetBool(\"DisplaySkillChanges\"); });\r\n\r\n            titleStr.SafeAction(s =>\r\n            {\r\n                s.Enabled = showInBar.Checked = Config.GetBool(\"TitleBarDisplay\");\r\n                s.Text = Config.GetString(\"TitleBarText\");\r\n            });\r\n\r\n            showNotoHue.SafeAction(s => { s.Checked = Config.GetBool(\"ShowNotoHue\"); });\r\n\r\n            corpseRange.SafeAction(s =>\r\n            {\r\n                s.Enabled = openCorpses.Checked = Config.GetBool(\"AutoOpenCorpses\");\r\n                s.Text = Config.GetInt(\"CorpseRange\").ToString();\r\n            });\r\n\r\n            actionStatusMsg.SafeAction(s => { s.Checked = Config.GetBool(\"ActionStatusMsg\"); });\r\n\r\n            autoStackRes.SafeAction(s => { s.Checked = Config.GetBool(\"AutoStack\"); });\r\n\r\n            rememberPwds.SafeAction(s => { s.Checked = Config.GetBool(\"RememberPwds\"); });\r\n\r\n            filterSnoop.SafeAction(s => { s.Checked = Config.GetBool(\"FilterSnoopMsg\"); });\r\n\r\n            preAOSstatbar.SafeAction(s => { s.Checked = Config.GetBool(\"OldStatBar\"); });\r\n\r\n            showtargtext.SafeAction(s => { s.Checked = Config.GetBool(\"LastTargTextFlags\"); });\r\n\r\n            smartLT.SafeAction(s => { s.Checked = Config.GetBool(\"SmartLastTarget\"); });\r\n\r\n            autoFriend.SafeAction(s => { s.Checked = Config.GetBool(\"AutoFriend\"); });\r\n            \r\n            forceSizeX.SafeAction(s => { s.Text = Config.GetInt(\"ForceSizeX\").ToString(); });\r\n\r\n            forceSizeY.SafeAction(s => { s.Text = Config.GetInt(\"ForceSizeY\").ToString(); });\r\n\r\n            gameSize.SafeAction(s => { s.Checked = Config.GetBool(\"ForceSizeEnabled\"); });\r\n\r\n            potionEquip.SafeAction(s => { s.Checked = Config.GetBool(\"PotionEquip\"); });\r\n\r\n            blockHealPoison.SafeAction(s => { s.Checked = Config.GetBool(\"BlockHealPoison\"); });\r\n\r\n            negotiate.SafeAction(s => { s.Checked = Config.GetBool(\"Negotiate\"); });\r\n\r\n            logPackets.SafeAction(s => { s.Checked = Config.GetBool(\"LogPacketsByDefault\"); });\r\n\r\n            healthFmt.SafeAction(s =>\r\n            {\r\n                s.Enabled = showHealthOH.Checked = Config.GetBool(\"ShowHealth\");\r\n                s.Text = Config.GetString(\"HealthFmt\");\r\n            });\r\n\r\n            chkPartyOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"ShowPartyStats\"); });\r\n\r\n            dressList.SafeAction(s => { s.SelectedIndex = -1; });\r\n\r\n            hotkeyTree.SafeAction(s => { s.SelectedNode = null; });\r\n\r\n            targetByTypeDifferent.SafeAction(s => { s.Checked = Config.GetBool(\"DiffTargetByType\"); });\r\n\r\n            stepThroughMacro.SafeAction(s => { s.Checked = Config.GetBool(\"StepThroughMacro\"); });\r\n\r\n            showTargetMessagesOverChar.SafeAction(s =>\r\n            {\r\n                s.Checked = Config.GetBool(\"ShowTargetSelfLastClearOverhead\");\r\n            });\r\n\r\n            showOverheadMessages.SafeAction(s => { s.Checked = Config.GetBool(\"ShowOverheadMessages\"); });\r\n            overheadFormat.SafeAction(s => { s.Text = Config.GetString(\"OverheadFormat\"); });\r\n\r\n            if (Config.GetInt(\"OverheadStyle\") == 0)\r\n            {\r\n                asciiStyle.SafeAction(s => { s.Checked = true; });\r\n            }\r\n            else\r\n            {\r\n                unicodeStyle.SafeAction(s => { s.Checked = true; });\r\n            }\r\n\r\n            showOverheadMessages.SafeAction(s => { s.Checked = Config.GetBool(\"ShowOverheadMessages\"); });\r\n\r\n            logSkillChanges.SafeAction(s => { s.Checked = Config.GetBool(\"LogSkillChanges\"); });\r\n\r\n            lightLevelBar.SafeAction(s => { s.Value = s.Maximum - Config.GetInt(\"LightLevel\"); });\r\n\r\n            double percent = Math.Round((lightLevelBar.Value / (double) lightLevelBar.Maximum) * 100.0);\r\n\r\n            lightLevel.SafeAction(s => { s.Text = $\"Light: {percent}%\"; });\r\n\r\n            captureMibs.SafeAction(s => { s.Checked = Config.GetBool(\"CaptureMibs\"); });\r\n\r\n            stealthOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"StealthOverhead\"); });\r\n\r\n            blockOpenCorpsesTwice.SafeAction(s => { s.Checked = Config.GetBool(\"BlockOpenCorpsesTwice\"); });\r\n\r\n            showContainerLabels.SafeAction(s => { s.Checked = Config.GetBool(\"ShowContainerLabels\"); });\r\n\r\n            seasonList.SafeAction(s => { s.SelectedIndex = Config.GetInt(\"Season\"); });\r\n\r\n            bool st = Config.GetBool(\"Systray\");\r\n            taskbar.Checked = ShowInTaskbar = !st;\r\n            systray.Checked = m_NotifyIcon.Visible = st;\r\n\r\n            showAttackTarget.SafeAction(s => { s.Checked = Config.GetBool(\"ShowAttackTargetOverhead\"); });\r\n\r\n            showBuffDebuffOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"ShowBuffDebuffOverhead\"); });\r\n            \r\n            BuffDebuffManager.ReloadFilter();\r\n\r\n            rangeCheckTargetByType.SafeAction(s => { s.Checked = Config.GetBool(\"RangeCheckTargetByType\"); });\r\n\r\n            rangeCheckDoubleClick.SafeAction(s => { s.Checked = Config.GetBool(\"RangeCheckDoubleClick\"); });\r\n\r\n            blockTradeRequests.SafeAction(s => { s.Checked = Config.GetBool(\"BlockTradeRequests\"); });\r\n\r\n            blockPartyInvites.SafeAction(s => { s.Checked = Config.GetBool(\"BlockPartyInvites\"); });\r\n\r\n            autoAcceptParty.SafeAction(s => { s.Checked = Config.GetBool(\"AutoAcceptParty\"); });\r\n\r\n            minMaxLightLevel.SafeAction(s => { s.Checked = Config.GetBool(\"MinMaxLightLevelEnabled\"); });\r\n\r\n            showTextTargetIndicator.SafeAction(s => { s.Checked = Config.GetBool(\"ShowTextTargetIndicator\"); });\r\n\r\n            showAttackTargetNewOnly.SafeAction(s => { s.Checked = Config.GetBool(\"ShowAttackTargetNewOnly\"); });\r\n\r\n            macroVariableTypeList.SafeAction(s => { s.SelectedIndex = 0; });\r\n\r\n            filterDragonGraphics.SafeAction(s => { s.Checked = Config.GetBool(\"FilterDragonGraphics\"); });\r\n\r\n            filterDrakeGraphics.SafeAction(s => { s.Checked = Config.GetBool(\"FilterDrakeGraphics\"); });\r\n\r\n            LoadAnimationLists();\r\n\r\n            showDamageDealt.SafeAction(s => { s.Checked = Config.GetBool(\"ShowDamageDealt\"); });\r\n\r\n            damageDealtOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"ShowDamageDealtOverhead\"); });\r\n\r\n            showDamageTaken.SafeAction(s => { s.Checked = Config.GetBool(\"ShowDamageTaken\"); });\r\n\r\n            damageTakenOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"ShowDamageTakenOverhead\"); });\r\n\r\n            razorTitleBar.SafeAction(s => { s.Text = Config.GetString(\"RazorTitleBarText\"); });\r\n\r\n            showInRazorTitleBar.SafeAction(s => { s.Checked = Config.GetBool(\"ShowInRazorTitleBar\"); });\r\n\r\n            enableUOAAPI.SafeAction(s => { s.Checked = Config.GetBool(\"EnableUOAAPI\"); });\r\n\r\n            lastBackup.SafeAction(s => { s.Text = $\"Last Backup: {Config.GetAppSetting<string>(\"BackupTime\")}\"; });\r\n\r\n            targetIndicatorFormat.SafeAction(s => { s.Text = Config.GetString(\"TargetIndicatorFormat\"); });\r\n\r\n            nextPrevIgnoresFriends.SafeAction(s => { s.Checked = Config.GetBool(\"NextPrevTargetIgnoresFriends\"); });\r\n\r\n            stealthStepsFormat.SafeAction(s => { s.Text = Config.GetString(\"StealthStepsFormat\"); });\r\n\r\n            showStaticWalls.SafeAction(s => { s.Checked = Config.GetBool(\"ShowStaticWalls\"); });\r\n\r\n            showStaticWallLabels.SafeAction(s => { s.Checked = Config.GetBool(\"ShowStaticWallLabels\"); });\r\n\r\n            showFriendOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"ShowFriendOverhead\"); });\r\n\r\n            dispDeltaOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"DisplaySkillChangesOverhead\"); });\r\n\r\n            macroActionDelay.SafeAction(s => { s.Checked = Config.GetBool(\"MacroActionDelay\"); });\r\n\r\n            autoOpenDoorWhenHidden.SafeAction(s => { s.Checked = Config.GetBool(\"AutoOpenDoorWhenHidden\"); });\r\n\r\n            disableMacroPlayFinish.SafeAction(s => { s.Checked = Config.GetBool(\"DisableMacroPlayFinish\"); });\r\n\r\n\r\n            showBandageTimer.SafeAction(s => { s.Checked = Config.GetBool(\"ShowBandageTimer\"); });\r\n            bandageTimerLocation.SafeAction(s => { s.SelectedIndex = Config.GetInt(\"ShowBandageTimerLocation\"); });\r\n            onlyShowBandageTimerSeconds.SafeAction(s => { s.Checked = Config.GetBool(\"OnlyShowBandageTimerEvery\"); });\r\n            bandageTimerSeconds.SafeAction(s => { s.Text = Config.GetInt(\"OnlyShowBandageTimerSeconds\").ToString(); });\r\n            bandageTimerFormat.SafeAction(s => { s.Text = Config.GetString(\"ShowBandageTimerFormat\"); });\r\n            lblBandageCountFormat.SafeAction(s => { InitPreviewHue(s, \"ShowBandageTimerHue\"); });\r\n\r\n            lblTargetFormat.SafeAction(s => { InitPreviewHue(s, \"TargetIndicatorHue\"); });\r\n\r\n            filterSystemMessages.SafeAction(s => { s.Checked = Config.GetBool(\"FilterSystemMessages\"); });\r\n            filterRazorMessages.SafeAction(s => { s.Checked = Config.GetBool(\"FilterRazorMessages\"); });\r\n            filterDelaySeconds.SafeAction(s => { s.Text = Config.GetDouble(\"FilterDelay\").ToString(); });\r\n            filterOverheadMessages.SafeAction(s => { s.Checked = Config.GetBool(\"FilterOverheadMessages\"); });\r\n\r\n            onlyNextPrevBeneficial.SafeAction(s => { s.Checked = Config.GetBool(\"OnlyNextPrevBeneficial\"); });\r\n            friendBeneficialOnly.SafeAction(s => { s.Checked = Config.GetBool(\"FriendlyBeneficialOnly\"); });\r\n            nonFriendlyHarmfulOnly.SafeAction(s => { s.Checked = Config.GetBool(\"NonFriendlyHarmfulOnly\"); });\r\n\r\n            showBandageStart.SafeAction(s => { s.Checked = Config.GetBool(\"ShowBandageStart\"); });\r\n            showBandageEnd.SafeAction(s => { s.Checked = Config.GetBool(\"ShowBandageEnd\"); });\r\n            bandageStartMessage.SafeAction(s => { s.Text = Config.GetString(\"BandageStartMessage\"); });\r\n            bandageEndMessage.SafeAction(s => { s.Text = Config.GetString(\"BandageEndMessage\"); });\r\n\r\n            captureOthersDeathDelay.SafeAction(\r\n                s => { s.Text = Config.GetDouble(\"CaptureOthersDeathDelay\").ToString(); });\r\n            captureOwnDeathDelay.SafeAction(s => { s.Text = Config.GetDouble(\"CaptureOwnDeathDelay\").ToString(); });\r\n            captureOthersDeath.SafeAction(s => { s.Checked = Config.GetBool(\"CaptureOthersDeath\"); });\r\n            captureOwnDeath.SafeAction(s => { s.Checked = Config.GetBool(\"CaptureOwnDeath\"); });\r\n\r\n            targetFilterEnabled.SafeAction(s => { s.Checked = Config.GetBool(\"TargetFilterEnabled\"); });\r\n\r\n            filterDaemonGraphics.SafeAction(s => { s.Checked = Config.GetBool(\"FilterDaemonGraphics\"); });\r\n            filterWhiteWyrm.SafeAction(s => { s.Checked = Config.GetBool(\"FilterWyrmGraphics\"); });\r\n\r\n            soundFilterEnabled.SafeAction(s => { s.Checked = Config.GetBool(\"SoundFilterEnabled\"); });\r\n            showFilteredSound.SafeAction(s => { s.Checked = Config.GetBool(\"ShowFilteredSound\"); });\r\n            showPlayingSoundInfo.SafeAction(s => { s.Checked = Config.GetBool(\"ShowPlayingSoundInfo\"); });\r\n            showPlayingMusic.SafeAction(s => { s.Checked = Config.GetBool(\"ShowMusicInfo\"); });\r\n\r\n            autoSaveScript.SafeAction(s => { s.Checked = Config.GetBool(\"AutoSaveScript\"); });\r\n            autoSaveScriptPlay.SafeAction(s => { s.Checked = Config.GetBool(\"AutoSaveScriptPlay\"); });\r\n\r\n            highlightFriend.SafeAction(s => { s.Checked = Config.GetBool(\"HighlightFriend\"); });\r\n            \r\n            scriptDisablePlayFinish.SafeAction(s => { s.Checked = Config.GetBool(\"ScriptDisablePlayFinish\"); });\r\n\r\n            showWaypointOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"ShowWaypointOverhead\"); });\r\n            showWaypointDistance.SafeAction(s => { s.Checked = Config.GetBool(\"ShowWaypointDistance\"); });\r\n            txtWaypointDistanceSec.SafeAction(s => { s.Text = Config.GetInt(\"ShowWaypointSeconds\").ToString(); });\r\n\r\n            hideWaypointWithin.SafeAction(s => { s.Checked = Config.GetBool(\"ClearWaypoint\"); });\r\n            hideWaypointDist.SafeAction(s => { s.Text = Config.GetInt(\"HideWaypointDistance\").ToString(); });\r\n\r\n            waypointOnDeath.SafeAction(s => { s.Checked = Config.GetBool(\"CreateWaypointOnDeath\"); });\r\n\r\n            showPartyFriendOverhead.SafeAction(s => { s.Checked = Config.GetBool(\"ShowPartyFriendOverhead\"); });\r\n\r\n            overrideSpellFormat.SafeAction(s => { s.Checked = Config.GetBool(\"OverrideSpellFormat\"); });\r\n\r\n            reequipHandsPotion.SafeAction(s => { s.Checked = Config.GetBool(\"PotionReequip\"); });\r\n\r\n            enableTextFilter.SafeAction(s => { s.Checked = Config.GetBool(\"EnableTextFilter\"); });\r\n\r\n            disableScriptTooltips.SafeAction(s => { s.Checked = Config.GetBool(\"DisableScriptTooltips\"); });\r\n\r\n            buyAgentIgnoreGold.SafeAction(s => { s.Checked = Config.GetBool(\"BuyAgentsIgnoreGold\"); });\r\n\r\n            nextPrevAbcOrder.SafeAction(s => { s.Checked = Config.GetBool(\"NextPrevAlphabetical\"); });\r\n\r\n            playEmoteSound.SafeAction(s => { s.Checked = Config.GetBool(\"PlayEmoteSound\"); });\r\n\r\n            showBuffDebuffGump.SafeAction(s => { s.Checked = Config.GetBool(\"ShowBuffDebuffGump\"); });\r\n            showBuffIcons.SafeAction(s => { s.Checked = Config.GetBool(\"ShowBuffDebuffIcons\"); });\r\n            buffBarWidth.SafeAction(s => { s.Text = Config.GetInt(\"ShowBuffDebuffWidth\").ToString(); });\r\n            buffBarHeight.SafeAction(s => { s.Text = Config.GetInt(\"ShowBuffDebuffHeight\").ToString(); });\r\n            useBlackBuffDebuffBg.SafeAction(s => { s.Checked = Config.GetBool(\"UseBlackBuffDebuffBg\"); });\r\n            buffBarSort.SafeAction(s => { s.SelectedIndex = Config.GetInt(\"ShowBuffDebuffSort\"); });\r\n            showBuffDebuffTimeType.SafeAction(s => { s.SelectedIndex = Config.GetInt(\"ShowBuffDebuffTimeType\"); });\r\n            \r\n            defaultScriptDelay.SafeAction(s => { s.Checked = Config.GetBool(\"DefaultScriptDelay\"); });\r\n            enableHighlight.SafeAction(s => { s.Checked = Config.GetBool(\"EnableHighlight\"); });\r\n            disableScriptStopwatch.SafeAction(s => { s.Checked = Config.GetBool(\"DisableScriptStopwatch\"); });\r\n\r\n            cooldownWidth.SafeAction(s => { s.Text = Config.GetInt(\"CooldownWidth\").ToString(); });\r\n            cooldownHeight.SafeAction(s => { s.Text = Config.GetInt(\"CooldownHeight\").ToString(); });\r\n\r\n            Engine.MainWindow.Size = new Size(Config.GetInt(\"WindowSizeX\"), Config.GetInt(\"WindowSizeY\"));\r\n\r\n            // Disable SmartCPU in case it was enabled before the feature was removed\r\n            Client.Instance.SetSmartCPU(false);\r\n\r\n            if (!Client.IsOSI)\r\n                DisableCUOFeatures();\r\n\r\n            m_Initializing = false;\r\n        }\r\n\r\n        private class AnimData\r\n        {\r\n            public string Name { get; set; }\r\n            public int BodyId { get; set; }\r\n        }\r\n\r\n        private List<AnimData> _animationData = new List<AnimData>();\r\n\r\n        private void LoadAnimationLists()\r\n        {\r\n            int hue = 0;\r\n\r\n            var lines = File.ReadLines(Path.Combine(Config.GetInstallDirectory(), \"animdata.csv\")).Select(a => a.Split(','));\r\n\r\n            _animationData.Clear();\r\n            dragonAnimationList.Items.Clear();\r\n            drakeAnimationList.Items.Clear();\r\n\r\n\r\n            foreach (string[] line in lines)\r\n            {\r\n                // ant_lion (787),787\r\n\r\n                AnimData animData = new AnimData\r\n                {\r\n                    Name = line[0],\r\n                    BodyId = Convert.ToInt32(line[1])\r\n                };\r\n\r\n                try\r\n                {\r\n                    Frame[] frames =\r\n                        Animations.GetAnimation(animData.BodyId, 0, 1, ref hue, false, false);\r\n                 \r\n                    if (frames != null)\r\n                    {\r\n                        _animationData.Add(animData);\r\n                        dragonAnimationList.Items.Add(animData.Name);\r\n                        drakeAnimationList.Items.Add(animData.Name);\r\n                        daemonAnimationList.Items.Add(animData.Name);\r\n                        wyrmAnimationList.Items.Add(animData.Name);\r\n                    }\r\n                }\r\n                catch //Unable to verify animation, lets add it anyway\r\n                {\r\n                    _animationData.Add(animData);\r\n                    dragonAnimationList.Items.Add(animData.Name);\r\n                    drakeAnimationList.Items.Add(animData.Name);\r\n                    daemonAnimationList.Items.Add(animData.Name);\r\n                    wyrmAnimationList.Items.Add(animData.Name);\r\n                }\r\n            }\r\n\r\n            int animIndex = 0;\r\n\r\n            foreach (AnimData animData in _animationData)\r\n            {\r\n                if (animData.BodyId.Equals(Config.GetInt(\"DragonGraphic\")))\r\n                {\r\n                    dragonAnimationList.SelectedIndex = animIndex;\r\n                    break;\r\n                }\r\n\r\n                animIndex++;\r\n            }\r\n\r\n            animIndex = 0;\r\n            foreach (AnimData animData in _animationData)\r\n            {\r\n                if (animData.BodyId.Equals(Config.GetInt(\"DrakeGraphic\")))\r\n                {\r\n                    drakeAnimationList.SelectedIndex = animIndex;\r\n                    break;\r\n                }\r\n\r\n                animIndex++;\r\n            }\r\n\r\n            animIndex = 0;\r\n            foreach (AnimData animData in _animationData)\r\n            {\r\n                if (animData.BodyId.Equals(Config.GetInt(\"DaemonGraphic\")))\r\n                {\r\n                    daemonAnimationList.SelectedIndex = animIndex;\r\n                    break;\r\n                }\r\n\r\n                animIndex++;\r\n            }\r\n\r\n            animIndex = 0;\r\n            foreach (AnimData animData in _animationData)\r\n            {\r\n                if (animData.BodyId.Equals(Config.GetInt(\"WyrmGraphic\")))\r\n                {\r\n                    wyrmAnimationList.SelectedIndex = animIndex;\r\n                    break;\r\n                }\r\n\r\n                animIndex++;\r\n            }\r\n\r\n            MobileFilter.Load();\r\n        }\r\n\r\n        private void tabs_IndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (tabs == null)\r\n                return;\r\n\r\n            if (tabs.SelectedTab != scriptsTab)\r\n            {\r\n                UpdateTitle();\r\n            }\r\n\r\n            if (tabs.SelectedTab == generalTab)\r\n            {\r\n                Filter.Draw(filters);\r\n                langSel.BeginUpdate();\r\n                langSel.Items.Clear();\r\n                langSel.Items.AddRange(Language.GetPackNames());\r\n                langSel.SelectedItem = Language.Current;\r\n                langSel.EndUpdate();\r\n            }\r\n            else if (tabs.SelectedTab == skillsTab)\r\n            {\r\n                RedrawSkills();\r\n            }\r\n            else if (tabs.SelectedTab == displayTab)\r\n            {\r\n                Counter.Redraw(counters);\r\n\r\n                titleBarParams.SelectedIndex = 0;\r\n            }\r\n            else if (tabs.SelectedTab == dressTab)\r\n            {\r\n                int sel = dressList.SelectedIndex;\r\n                dressItems.Items.Clear();\r\n                DressList.Redraw();\r\n                if (sel >= 0 && sel < dressList.Items.Count)\r\n                    dressList.SelectedIndex = sel;\r\n            }\r\n            else if (tabs.SelectedTab == hotkeysTab)\r\n            {\r\n                filterHotkeys.Text = string.Empty;\r\n\r\n                hotkeyTree.SelectedNode = null;\r\n                HotKey.Status = hkStatus;\r\n                if (hotkeyTree.TopNode != null)\r\n                    hotkeyTree.TopNode.Expand();\r\n                else\r\n                    HotKey.RebuildList(hotkeyTree);\r\n\r\n                RebuildHotKeyCache();\r\n            }\r\n            else if (tabs.SelectedTab == agentsTab)\r\n            {\r\n                int sel = agentList.SelectedIndex;\r\n                Agent.Redraw(agentList, agentGroup, agentB1, agentB2, agentB3, agentB4, agentB5, agentB6);\r\n                if (sel >= 0 && sel < agentList.Items.Count)\r\n                    agentList.SelectedIndex = sel;\r\n            }\r\n            else if (tabs.SelectedTab == advancedTab)\r\n            {\r\n                UpdateRazorStatus();\r\n            }\r\n            else if (tabs.SelectedTab == macrosTab)\r\n            {\r\n                RedrawMacros();\r\n\r\n                if (MacroManager.Playing || MacroManager.Recording)\r\n                    OnMacroStart(MacroManager.Current);\r\n                else\r\n                    OnMacroStop();\r\n\r\n                if (MacroManager.Current != null)\r\n                    MacroManager.Current.DisplayTo(actionList);\r\n\r\n                macroActGroup.Visible = macroTree.SelectedNode != null;\r\n            }\r\n            else if (tabs.SelectedTab == scriptsTab)\r\n            {\r\n                RedrawScripts();\r\n            }\r\n            else if (tabs.SelectedTab == friendsTab)\r\n            {\r\n                FriendsManager.RedrawGroup();\r\n            }\r\n            else if (tabs.SelectedTab == screenshotTab)\r\n            {\r\n                ReloadScreenShotsList();\r\n            }\r\n        }\r\n\r\n        private void subGeneralTab_IndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (subGeneralTab == null)\r\n                return;\r\n        }\r\n\r\n        private void RebuildHotKeyCache()\r\n        {\r\n            _hotkeyTreeViewCache.Nodes.Clear();\r\n\r\n            foreach (TreeNode node in hotkeyTree.Nodes)\r\n            {\r\n                _hotkeyTreeViewCache.Nodes.Add((TreeNode) node.Clone());\r\n            }\r\n        }\r\n\r\n        private void RebuildMacroCache()\r\n        {\r\n            _macroTreeViewCache.Nodes.Clear();\r\n\r\n            foreach (TreeNode node in macroTree.Nodes)\r\n            {\r\n                _macroTreeViewCache.Nodes.Add((TreeNode) node.Clone());\r\n            }\r\n        }\r\n\r\n        private void RebuildScriptCache()\r\n        {\r\n            _scriptTreeViewCache.Nodes.Clear();\r\n\r\n            foreach (TreeNode node in scriptTree.Nodes)\r\n            {\r\n                _scriptTreeViewCache.Nodes.Add((TreeNode)node.Clone());\r\n            }\r\n        }\r\n\r\n        private void RebuildItemCache()\r\n        {\r\n            _itemTreeCache.Nodes.Clear();\r\n\r\n            foreach (TreeNode node in itemTree.Nodes)\r\n            {\r\n                _itemTreeCache.Nodes.Add((TreeNode)node.Clone());\r\n            }\r\n        }\r\n\r\n        private Version m_Ver = System.Reflection.Assembly.GetCallingAssembly().GetName().Version;\r\n\r\n        private uint m_OutPrev;\r\n        private uint m_InPrev;\r\n\r\n        private class StatsTimer : Timer\r\n        {\r\n            MainForm m_Form;\r\n\r\n            public StatsTimer(MainForm form) : base(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5))\r\n            {\r\n                m_Form = form;\r\n            }\r\n\r\n            protected override void OnTick()\r\n            {\r\n                m_Form.UpdateRazorStatus();\r\n            }\r\n        }\r\n\r\n        private void UpdateRazorStatus()\r\n        {\r\n            if (!Client.Instance.ClientRunning)\r\n                Close();\r\n\r\n            uint ps = m_OutPrev;\r\n            uint pr = m_InPrev;\r\n            m_OutPrev = Client.Instance.TotalDataOut();\r\n            m_InPrev = Client.Instance.TotalDataIn();\r\n\r\n            tabs.SafeAction(s =>\r\n            {\r\n                if (s.SelectedTab != advancedTab)\r\n                {\r\n                    return;\r\n                }\r\n            });\r\n\r\n            int time = 0;\r\n            if (Client.Instance.ConnectionStart != DateTime.MinValue)\r\n                time = (int) ((DateTime.UtcNow - Client.Instance.ConnectionStart).TotalSeconds);\r\n\r\n\r\n            statusBox.SafeAction(s =>\r\n            {\r\n                if (string.IsNullOrEmpty(s.SelectedText))\r\n                {\r\n                    s.Lines = Language.Format(LocString.RazorStatus1,\r\n                        m_Ver,\r\n                        Utility.FormatSize(System.GC.GetTotalMemory(false)),\r\n                        Utility.FormatSize(m_OutPrev), Utility.FormatSize((long) ((m_OutPrev - ps))),\r\n                        Utility.FormatSize(m_InPrev), Utility.FormatSize((long) ((m_InPrev - pr))),\r\n                        Utility.FormatTime(time),\r\n                        (World.Player != null ? (uint) World.Player.Serial : 0),\r\n                        (World.Player != null && World.Player.Backpack != null\r\n                            ? (uint) World.Player.Backpack.Serial\r\n                            : 0),\r\n                        World.Items.Count,\r\n                        World.Mobiles.Count).Split('\\n');\r\n\r\n                    if (World.Player != null)\r\n                        statusBox.SafeAction(x =>\r\n                            x.AppendText(\r\n                                $\"\\r\\nCoordinates: {World.Player.Position.X} {World.Player.Position.Y} {World.Player.Position.Z}\"));\r\n                }\r\n            });\r\n\r\n            if (PacketHandlers.PlayCharTime < DateTime.UtcNow &&\r\n                PacketHandlers.PlayCharTime + TimeSpan.FromSeconds(5) < DateTime.UtcNow)\r\n            {\r\n                if (Config.GetBool(\"Negotiate\"))\r\n                {\r\n                    bool allAllowed = true;\r\n                    StringBuilder text = new StringBuilder();\r\n\r\n                    text.Append(Language.GetString(LocString.NegotiateTitle));\r\n                    text.Append(\"\\r\\n\");\r\n\r\n                    for (int i = 0; i < FeatureBit.MaxBit; i++)\r\n                    {\r\n                        if (!Client.Instance.AllowBit(i))\r\n                        {\r\n                            allAllowed = false;\r\n\r\n                            text.Append(Language.GetString((LocString) (((int) LocString.FeatureDescBase) + i)));\r\n                            text.Append(' ');\r\n                            text.Append(Language.GetString(LocString.NotAllowed));\r\n                            text.Append(\"\\r\\n\");\r\n                        }\r\n                    }\r\n\r\n                    if (allAllowed)\r\n                        text.Append(Language.GetString(LocString.AllFeaturesEnabled));\r\n\r\n                    text.Append(\"\\r\\n\");\r\n\r\n                    features.SafeAction(x => x.Visible = true);\r\n                    features.SafeAction(x => x.Text = text.ToString());\r\n                }\r\n                else\r\n                {\r\n                    features.SafeAction(x => x.Visible = false);\r\n                }\r\n            }\r\n        }\r\n\r\n        public void UpdateSkill(Skill skill)\r\n        {\r\n            double total = 0;\r\n            for (int i = 0; i < Skills.TotalSkills(); i++)\r\n            {\r\n                total += World.Player.Skills[i].Base;\r\n            }\r\n\r\n            baseTotal.Text = $\"{total:F1}\";\r\n\r\n            if (Config.GetBool(\"LogSkillChanges\"))\r\n            {\r\n                string skillLog = Path.Combine(Config.GetInstallDirectory(), \"SkillLog\");\r\n                skillLog = Path.Combine(skillLog, $\"{World.Player.Name}_{World.Player.Serial}_SkillLog.csv\");\r\n\r\n\r\n                if (!Directory.Exists(Path.GetDirectoryName(skillLog)))\r\n                {\r\n                    Directory.CreateDirectory(Path.GetDirectoryName(skillLog));\r\n                }\r\n\r\n                if (!File.Exists(skillLog))\r\n                {\r\n                    using (StreamWriter sr = File.CreateText(skillLog))\r\n                    {\r\n                        sr.WriteLine(\"Timestamp,SkillName,Value,Base,Gain,Cap\");\r\n                    }\r\n                }\r\n\r\n                using (StreamWriter sw = File.AppendText(skillLog))\r\n                {\r\n                    sw.WriteLine(\r\n                        $\"{DateTime.Now},{Skills.GetSkillDisplayName(skill.Index)},{skill.Value},{skill.Base},{skill.Delta},{skill.Cap}\");\r\n                }\r\n            }\r\n\r\n            for (int i = 0; i < skillList.Items.Count; i++)\r\n            {\r\n                ListViewItem cur = skillList.Items[i];\r\n                if (cur.Tag == skill)\r\n                {\r\n                    cur.SubItems[1].Text = $\"{skill.Value:F1}\";\r\n                    cur.SubItems[2].Text = $\"{skill.Base:F1}\";\r\n                    cur.SubItems[3].Text = $\"{(skill.Delta > 0 ? \"+\" : \"\")}{skill.Delta:F1}\";\r\n                    cur.SubItems[4].Text = $\"{skill.Cap:F1}\";\r\n                    cur.SubItems[5].Text = skill.Lock.ToString()[0].ToString();\r\n                    SortSkills();\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n\r\n        public void ToggleDamageTracker(bool enable)\r\n        {\r\n            if (World.Player == null)\r\n            {\r\n                DamageTracker.Stop();\r\n                return;\r\n            }\r\n\r\n            if (enable)\r\n            {\r\n                trackDps.Checked = true;\r\n            }\r\n            else\r\n            {\r\n                trackDps.Checked = false;\r\n            }\r\n        }\r\n\r\n        public void RedrawSkills()\r\n        {\r\n            skillList.BeginUpdate();\r\n            skillList.Items.Clear();\r\n            double Total = 0;\r\n            if (World.Player != null && World.Player.SkillsSent)\r\n            {\r\n                string[] items = new string[6];\r\n                for (int i = 0; i < Skills.TotalSkills(); i++)\r\n                {\r\n                    Skill sk = World.Player.Skills[i];\r\n                    Total += sk.Base;\r\n                    items[0] = Skills.GetSkillDisplayName(i);\r\n                    items[1] = $\"{sk.Value:F1}\";\r\n                    items[2] = $\"{sk.Base:F1}\";\r\n                    items[3] = $\"{(sk.Delta > 0 ? \"+\" : \"\")}{sk.Delta:F1}\";\r\n                    items[4] = $\"{sk.Cap:F1}\";\r\n                    items[5] = sk.Lock.ToString()[0].ToString();\r\n\r\n                    ListViewItem lvi = new ListViewItem(items);\r\n                    lvi.Tag = sk;\r\n                    skillList.Items.Add(lvi);\r\n                }\r\n\r\n                //Config.SetProperty( \"SkillListAsc\", false );\r\n                SortSkills();\r\n            }\r\n\r\n            skillList.EndUpdate();\r\n            baseTotal.Text = $\"{Total:F1}\";\r\n        }\r\n\r\n        private void OnFilterCheck(object sender, System.Windows.Forms.ItemCheckEventArgs e)\r\n        {\r\n            ((Filter) filters.Items[e.Index]).OnCheckChanged(e.NewValue);\r\n        }\r\n\r\n        private void incomingMob_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowMobNames\", incomingMob.Checked);\r\n        }\r\n\r\n        private void incomingCorpse_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowCorpseNames\", incomingCorpse.Checked);\r\n        }\r\n\r\n        private ContextMenuStrip m_SkillMenu;\r\n\r\n        private void skillList_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right)\r\n            {\r\n                ListView.SelectedListViewItemCollection items = skillList.SelectedItems;\r\n                if (items.Count <= 0)\r\n                    return;\r\n                Skill s = items[0].Tag as Skill;\r\n                if (s == null)\r\n                    return;\r\n\r\n                if (m_SkillMenu == null)\r\n                {\r\n                    m_SkillMenu = new ContextMenuStrip();\r\n                    m_SkillMenu.Items.Add(Language.GetString(LocString.SetSLUp), null, onSetSkillLockUP);\r\n                    m_SkillMenu.Items.Add(Language.GetString(LocString.SetSLDown), null, onSetSkillLockDOWN);\r\n                    m_SkillMenu.Items.Add(Language.GetString(LocString.SetSLLocked), null, onSetSkillLockLOCKED);\r\n                }\r\n\r\n                for (int i = 0; i < 3; i++)\r\n                    ((ToolStripMenuItem)m_SkillMenu.Items[i]).Checked = ((int) s.Lock) == i;\r\n\r\n                m_SkillMenu.Show(skillList, new Point(e.X, e.Y));\r\n            }\r\n        }\r\n\r\n        private void onSetSkillLockUP(object sender, EventArgs e)\r\n        {\r\n            SetLock(LockType.Up);\r\n        }\r\n\r\n        private void onSetSkillLockDOWN(object sender, EventArgs e)\r\n        {\r\n            SetLock(LockType.Down);\r\n        }\r\n\r\n        private void onSetSkillLockLOCKED(object sender, EventArgs e)\r\n        {\r\n            SetLock(LockType.Locked);\r\n        }\r\n\r\n        private void SetLock(LockType lockType)\r\n        {\r\n            ListView.SelectedListViewItemCollection items = skillList.SelectedItems;\r\n            if (items.Count <= 0)\r\n                return;\r\n            Skill s = items[0].Tag as Skill;\r\n            if (s == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                Client.Instance.SendToServer(new SetSkillLock(s.Index, lockType));\r\n\r\n                s.Lock = lockType;\r\n                UpdateSkill(s);\r\n\r\n                Client.Instance.SendToClient(new SkillUpdate(s));\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private void OnSkillColClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)\r\n        {\r\n            if (e.Column == Config.GetInt(\"SkillListCol\"))\r\n                Config.SetProperty(\"SkillListAsc\", !Config.GetBool(\"SkillListAsc\"));\r\n            else\r\n                Config.SetProperty(\"SkillListCol\", e.Column);\r\n            SortSkills();\r\n        }\r\n\r\n        private void SortSkills()\r\n        {\r\n            int col = Config.GetInt(\"SkillListCol\");\r\n            bool asc = Config.GetBool(\"SkillListAsc\");\r\n\r\n            if (col < 0 || col > 5)\r\n                col = 0;\r\n\r\n            skillList.BeginUpdate();\r\n            if (col == 0 || col == 5)\r\n            {\r\n                skillList.ListViewItemSorter = null;\r\n                skillList.Sorting = asc ? SortOrder.Ascending : SortOrder.Descending;\r\n            }\r\n            else\r\n            {\r\n                LVDoubleComparer.Column = col;\r\n                LVDoubleComparer.Asc = asc;\r\n\r\n                skillList.ListViewItemSorter = LVDoubleComparer.Instance;\r\n\r\n                skillList.Sorting = SortOrder.None;\r\n                skillList.Sort();\r\n            }\r\n\r\n            skillList.EndUpdate();\r\n            skillList.Refresh();\r\n        }\r\n\r\n        private class LVDoubleComparer : IComparer\r\n        {\r\n            public static readonly LVDoubleComparer Instance = new LVDoubleComparer();\r\n\r\n            public static int Column\r\n            {\r\n                set { Instance.m_Col = value; }\r\n            }\r\n\r\n            public static bool Asc\r\n            {\r\n                set { Instance.m_Asc = value; }\r\n            }\r\n\r\n            private int m_Col;\r\n            private bool m_Asc;\r\n\r\n            private LVDoubleComparer()\r\n            {\r\n            }\r\n\r\n            public int Compare(object x, object y)\r\n            {\r\n                if (x == null || !(x is ListViewItem))\r\n                    return m_Asc ? 1 : -1;\r\n                else if (y == null || !(y is ListViewItem))\r\n                    return m_Asc ? -1 : 1;\r\n\r\n                try\r\n                {\r\n                    double dx = Convert.ToDouble(((ListViewItem) x).SubItems[m_Col].Text);\r\n                    double dy = Convert.ToDouble(((ListViewItem) y).SubItems[m_Col].Text);\r\n\r\n                    if (dx > dy)\r\n                        return m_Asc ? -1 : 1;\r\n                    else if (dx == dy)\r\n                        return 0;\r\n                    else //if ( dx > dy )\r\n                        return m_Asc ? 1 : -1;\r\n                }\r\n                catch\r\n                {\r\n                    return ((ListViewItem) x).Text.CompareTo(((ListViewItem) y).Text) * (m_Asc ? 1 : -1);\r\n                }\r\n            }\r\n        }\r\n\r\n        private void OnResetSkillDelta(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            for (int i = 0; i < Skills.TotalSkills(); i++)\r\n                World.Player.Skills[i].Delta = 0;\r\n\r\n            RedrawSkills();\r\n        }\r\n\r\n        private void OnSetSkillLocks(object sender, System.EventArgs e)\r\n        {\r\n            if (locks.SelectedIndex == -1 || World.Player == null)\r\n                return;\r\n\r\n            LockType type = (LockType) locks.SelectedIndex;\r\n\r\n            for (short i = 0; i < Skills.TotalSkills(); i++)\r\n            {\r\n                World.Player.Skills[i].Lock = type;\r\n                Client.Instance.SendToServer(new SetSkillLock(i, type));\r\n            }\r\n\r\n            Client.Instance.SendToClient(new SkillsList());\r\n            RedrawSkills();\r\n        }\r\n\r\n        private void OnDispSkillCheck(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DispSkillChanges\", dispDelta.Checked);\r\n        }\r\n\r\n        private void delCounter_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (counters.SelectedItems.Count <= 0)\r\n                return;\r\n\r\n            Counter c = counters.SelectedItems[0].Tag as Counter;\r\n\r\n            if (c != null)\r\n            {\r\n                AddCounter ac = new AddCounter(c);\r\n                switch (ac.ShowDialog(this))\r\n                {\r\n                    case DialogResult.Abort:\r\n                        counters.Items.Remove(c.ViewItem);\r\n                        Counter.List.Remove(c);\r\n                        break;\r\n\r\n                    case DialogResult.OK:\r\n                        c.Set((ushort) ac.ItemID, ac.Hue, ac.NameStr, ac.FmtStr, ac.DisplayImage);\r\n                        break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private void addCounter_Click(object sender, System.EventArgs e)\r\n        {\r\n            AddCounter dlg = new AddCounter();\r\n\r\n            if (dlg.ShowDialog(this) == DialogResult.OK)\r\n            {\r\n                Counter.Register(new Counter(dlg.NameStr, dlg.FmtStr, (ushort) dlg.ItemID, (int) dlg.Hue,\r\n                    dlg.DisplayImage));\r\n                Counter.Redraw(counters);\r\n            }\r\n        }\r\n\r\n        private void showInBar_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            titleStr.Enabled = showInBar.Checked;\r\n            Config.SetProperty(\"TitleBarDisplay\", showInBar.Checked);\r\n            Client.Instance.RequestTitlebarUpdate();\r\n        }\r\n\r\n        private void titleStr_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"TitleBarText\", titleStr.Text.TrimEnd());\r\n            if (Config.GetBool(\"TitleBarDisplay\"))\r\n                Client.Instance.RequestTitlebarUpdate();\r\n        }\r\n\r\n        private void counters_ItemCheck(object sender, System.Windows.Forms.ItemCheckEventArgs e)\r\n        {\r\n            if (e.Index >= 0 && e.Index < Counter.List.Count && !Counter.SupressChecks)\r\n            {\r\n                ((Counter) (counters.Items[e.Index].Tag)).SetEnabled(e.NewValue == CheckState.Checked);\r\n                Client.Instance.RequestTitlebarUpdate();\r\n                counters.Sort();\r\n                //counters.Refresh();\r\n            }\r\n        }\r\n\r\n        public void RedrawCounters()\r\n        {\r\n            Counter.Redraw(counters);\r\n        }\r\n\r\n        private void checkNewConts_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoSearch\", checkNewConts.Checked);\r\n            excludePouches.Enabled = checkNewConts.Checked;\r\n        }\r\n\r\n        private void warnCount_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CounterWarn\", warnCount.Checked);\r\n            warnNum.Enabled = warnCount.Checked;\r\n        }\r\n\r\n        private void warnNum_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CounterWarnAmount\", Utility.ToInt32(warnNum.Text.Trim(), 3));\r\n        }\r\n\r\n        private void alwaysTop_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AlwaysOnTop\", this.TopMost = alwaysTop.Checked);\r\n        }\r\n\r\n        private void profiles_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (profiles.SelectedIndex < 0 || !m_ProfileConfirmLoad)\r\n                return;\r\n\r\n            string name = (string) profiles.Items[profiles.SelectedIndex];\r\n            if (MessageBox.Show(this, Language.Format(LocString.ProfLoadQ, name), \"Load?\", MessageBoxButtons.YesNo,\r\n                    MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                Config.Save();\r\n                if (!Config.LoadProfile(name))\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.ProfLoadE), \"Load Error\", MessageBoxButtons.OK,\r\n                        MessageBoxIcon.Warning);\r\n                }\r\n                else\r\n                {\r\n                    InitConfig();\r\n                    if (World.Player != null)\r\n                        Config.SetProfileFor(World.Player);\r\n                }\r\n\r\n                Client.Instance.RequestTitlebarUpdate();\r\n            }\r\n            else\r\n            {\r\n                m_ProfileConfirmLoad = false;\r\n                for (int i = 0; i < profiles.Items.Count; i++)\r\n                {\r\n                    if ((string) profiles.Items[i] == Config.CurrentProfile.Name)\r\n                    {\r\n                        profiles.SelectedIndex = i;\r\n                        break;\r\n                    }\r\n                }\r\n\r\n                m_ProfileConfirmLoad = true;\r\n            }\r\n        }\r\n\r\n        private void delProfile_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (profiles.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (MessageBox.Show(this, \"Are you sure you want to delete this profile?\", \"Delete Profile?\",\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)\r\n            {\r\n                return;\r\n            }\r\n\r\n            string remove = (string) profiles.Items[profiles.SelectedIndex];\r\n\r\n            if (remove == \"default\")\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.NoDelete), \"Not Allowed\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            string file = Path.Combine(Config.GetUserDirectory(\"Profiles\"), $\"{remove}.xml\");\r\n            if (File.Exists(file))\r\n            {\r\n                File.Delete(file);\r\n            }\r\n\r\n            profiles.Items.Remove(remove);\r\n\r\n            if (!Config.LoadProfile(\"default\"))\r\n            {\r\n                Config.CurrentProfile.MakeDefault();\r\n                Config.CurrentProfile.Name = \"default\";\r\n            }\r\n\r\n            InitConfig();\r\n\r\n            m_ProfileConfirmLoad = false;\r\n            for (int i = 0; i < profiles.Items.Count; i++)\r\n            {\r\n                if ((string) profiles.Items[i] == \"default\")\r\n                {\r\n                    profiles.SelectedIndex = i;\r\n                    m_ProfileConfirmLoad = true;\r\n                    return;\r\n                }\r\n            }\r\n\r\n            int sel = profiles.Items.Count;\r\n            profiles.Items.Add(\"default\");\r\n            profiles.SelectedIndex = sel;\r\n            m_ProfileConfirmLoad = true;\r\n        }\r\n\r\n        public void SelectProfile(string name)\r\n        {\r\n            m_ProfileConfirmLoad = false;\r\n            profiles.SelectedItem = name;\r\n            m_ProfileConfirmLoad = true;\r\n        }\r\n\r\n        private void newProfile_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (InputBox.Show(this, Language.GetString(LocString.EnterProfileName),\r\n                Language.GetString(LocString.EnterAName)))\r\n            {\r\n                string str = InputBox.GetString();\r\n                if (str == null || str == \"\" || str.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                    str.IndexOfAny(m_InvalidNameChars) != -1)\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.InvalidChars),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                m_ProfileConfirmLoad = false;\r\n                int sel = profiles.Items.Count;\r\n                string lwr = str.ToLower();\r\n                for (int i = 0; i < profiles.Items.Count; i++)\r\n                {\r\n                    if (lwr == ((string) profiles.Items[i]).ToLower())\r\n                    {\r\n                        if (MessageBox.Show(this, Language.GetString(LocString.ProfExists), \"Load Profile?\",\r\n                                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n                        {\r\n                            Config.Save();\r\n                            profiles.SelectedIndex = i;\r\n                            if (!Config.LoadProfile(str))\r\n                            {\r\n                                MessageBox.Show(this, Language.GetString(LocString.ProfLoadE), \"Load Error\",\r\n                                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                            }\r\n                            else\r\n                            {\r\n                                InitConfig();\r\n                                if (World.Player != null)\r\n                                    Config.SetProfileFor(World.Player);\r\n                            }\r\n\r\n                            Client.Instance.RequestTitlebarUpdate();\r\n                        }\r\n\r\n                        m_ProfileConfirmLoad = true;\r\n                        return;\r\n                    }\r\n                }\r\n\r\n                Config.Save();\r\n                Config.NewProfile(str);\r\n                profiles.Items.Add(str);\r\n                profiles.SelectedIndex = sel;\r\n                InitConfig();\r\n                if (World.Player != null)\r\n                    Config.SetProfileFor(World.Player);\r\n                m_ProfileConfirmLoad = true;\r\n            }\r\n        }\r\n\r\n        public bool CanClose\r\n        {\r\n            get { return m_CanClose; }\r\n            set { m_CanClose = value; }\r\n        }\r\n\r\n        private void MainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)\r\n        {\r\n            if (!m_CanClose && Client.Instance.ClientRunning)\r\n            {\r\n                DisableCloseButton();\r\n                e.Cancel = true;\r\n            }\r\n\r\n            //if ( Engine.NoPatch )\r\n            //\te.Cancel = MessageBox.Show( this, \"Are you sure you want to close Razor?\\n(This will not close the UO client.)\", \"Close Razor?\", MessageBoxButtons.YesNo, MessageBoxIcon.Question ) == DialogResult.No;\r\n        }\r\n\r\n        private void skillCopySel_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (skillList.SelectedItems == null || skillList.SelectedItems.Count <= 0)\r\n                return;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n            for (int i = 0; i < skillList.SelectedItems.Count; i++)\r\n            {\r\n                ListViewItem vi = skillList.SelectedItems[i];\r\n                if (vi != null && vi.SubItems != null && vi.SubItems.Count > 4)\r\n                {\r\n                    string name = vi.SubItems[0].Text;\r\n                    if (name != null && name.Length > 20)\r\n                        name = name.Substring(0, 16) + \"...\";\r\n\r\n                    sb.AppendFormat(\"{0,-20} {1,5:F1} {2,5:F1} {4:F1} {5,5:F1}\\n\",\r\n                        name,\r\n                        vi.SubItems[1].Text,\r\n                        vi.SubItems[2].Text,\r\n                        Utility.ToInt32(vi.SubItems[3].Text, 0) < 0 ? \"\" : \"+\",\r\n                        vi.SubItems[3].Text,\r\n                        vi.SubItems[4].Text);\r\n                }\r\n            }\r\n\r\n            if (sb.Length > 0)\r\n                Clipboard.SetDataObject(sb.ToString(), true);\r\n        }\r\n\r\n        private void skillCopyAll_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n            for (int i = 0; i < Skills.TotalSkills(); i++)\r\n            {\r\n                Skill sk = World.Player.Skills[i];\r\n                sb.AppendFormat(\"{0,-20} {1,-5:F1} {2,-5:F1} {3}{4,-5:F1} {5,-5:F1}\\n\", Ultima.Skills.GetSkillDisplayName(i), sk.Value,\r\n                    sk.Base, sk.Delta > 0 ? \"+\" : \"\", sk.Delta, sk.Cap);\r\n            }\r\n\r\n            if (sb.Length > 0)\r\n                Clipboard.SetDataObject(sb.ToString(), true);\r\n        }\r\n\r\n        private void addDress_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (InputBox.Show(this, Language.GetString(LocString.DressName), Language.GetString(LocString.EnterAName)))\r\n            {\r\n                string str = InputBox.GetString();\r\n                if (str == null || str == \"\")\r\n                    return;\r\n                DressList list = new DressList(str);\r\n                DressList.Add(list);\r\n\r\n                dressList.SafeAction(s =>\r\n                {\r\n                    s.Items.Add(list);\r\n                    s.SelectedItem = list;\r\n                });\r\n            }\r\n        }\r\n\r\n        private void removeDress_Click(object sender, System.EventArgs e)\r\n        {\r\n            DressList dress = (DressList) dressList.SelectedItem;\r\n\r\n            if (dress != null && MessageBox.Show(this, Language.GetString(LocString.DelDressQ), \"Confirm\",\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                dress.Items.Clear();\r\n\r\n                dressList.SafeAction(s =>\r\n                {\r\n                    s.Items.Remove(dress);\r\n                    s.SelectedIndex = -1;\r\n                });\r\n\r\n                dressItems.SafeAction(s => s.Items.Clear());\r\n\r\n                DressList.Remove(dress);\r\n            }\r\n        }\r\n\r\n        private void dressNow_Click(object sender, System.EventArgs e)\r\n        {\r\n            DressList dress = (DressList) dressList.SelectedItem;\r\n            if (dress != null && World.Player != null)\r\n                dress.Dress();\r\n        }\r\n\r\n        private void undressList_Click(object sender, System.EventArgs e)\r\n        {\r\n            DressList dress = (DressList) dressList.SelectedItem;\r\n            if (dress != null && World.Player != null && World.Player.Backpack != null)\r\n                dress.Undress();\r\n        }\r\n\r\n        private void targItem_Click(object sender, System.EventArgs e)\r\n        {\r\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(OnDressItemTarget));\r\n        }\r\n\r\n        private void OnDressItemTarget(bool loc, Serial serial, Point3D pt, ushort itemid)\r\n        {\r\n            if (loc)\r\n                return;\r\n\r\n            ShowMe();\r\n            if (serial.IsItem)\r\n            {\r\n                DressList list = (DressList) dressList.SelectedItem;\r\n\r\n                if (list == null)\r\n                    return;\r\n\r\n                list.Items.Add(serial);\r\n                Item item = World.FindItem(serial);\r\n\r\n                dressItems.SafeAction(s =>\r\n                {\r\n                    if (item == null)\r\n                        s.Items.Add(Language.Format(LocString.OutOfRangeA1, serial));\r\n                    else\r\n                        s.Items.Add(item.ToString());\r\n                });\r\n            }\r\n        }\r\n\r\n        private void dressDelSel_Click(object sender, System.EventArgs e)\r\n        {\r\n            DressList list = (DressList) dressList.SelectedItem;\r\n            if (list == null)\r\n                return;\r\n\r\n            int sel = dressItems.SelectedIndex;\r\n            if (sel < 0 || sel >= list.Items.Count)\r\n                return;\r\n\r\n            if (MessageBox.Show(this, Language.GetString(LocString.DelDressItemQ), \"Confirm\", MessageBoxButtons.YesNo,\r\n                    MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                try\r\n                {\r\n                    list.Items.RemoveAt(sel);\r\n                    dressItems.SafeAction(s => s.Items.RemoveAt(sel));\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        private void clearDress_Click(object sender, System.EventArgs e)\r\n        {\r\n            DressList list = (DressList) dressList.SelectedItem;\r\n            if (list == null)\r\n                return;\r\n\r\n            if (MessageBox.Show(this, Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                list.Items.Clear();\r\n                dressItems.SafeAction(s => s.Items.Clear());\r\n            }\r\n        }\r\n\r\n        private DressList undressBagList = null;\r\n\r\n        private void undressBag_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            DressList list = (DressList) dressList.SelectedItem;\r\n            if (list == null)\r\n                return;\r\n\r\n            undressBagList = list;\r\n            Targeting.OneTimeTarget(new Targeting.TargetResponseCallback(onDressBagTarget));\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.TargUndressBag, list.Name);\r\n        }\r\n\r\n        void onDressBagTarget(bool location, Serial serial, Point3D p, ushort gfxid)\r\n        {\r\n            if (undressBagList == null)\r\n                return;\r\n\r\n            ShowMe();\r\n            if (serial.IsItem)\r\n            {\r\n                Item item = World.FindItem(serial);\r\n                if (item != null)\r\n                {\r\n                    undressBagList.SetUndressBag(item.Serial);\r\n                    World.Player.SendMessage(MsgLevel.Force, LocString.UB_Set);\r\n                }\r\n                else\r\n                {\r\n                    undressBagList.SetUndressBag(Serial.Zero);\r\n                    World.Player.SendMessage(MsgLevel.Force, LocString.ItemNotFound);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                World.Player.SendMessage(MsgLevel.Force, LocString.ItemNotFound);\r\n            }\r\n\r\n            undressBagList = null;\r\n        }\r\n\r\n        private void dressList_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            DressList list = (DressList) dressList.SelectedItem;\r\n\r\n            dressItems.BeginUpdate();\r\n            dressItems.Items.Clear();\r\n            if (list != null)\r\n            {\r\n                for (int i = 0; i < list.Items.Count; i++)\r\n                {\r\n                    if (list.Items[i] is Serial)\r\n                    {\r\n                        Serial serial = (Serial) list.Items[i];\r\n                        Item item = World.FindItem(serial);\r\n\r\n                        if (item != null)\r\n                            dressItems.Items.Add(item.ToString());\r\n                        else\r\n                            dressItems.Items.Add(Language.Format(LocString.OutOfRangeA1, serial));\r\n                    }\r\n                    else if (list.Items[i] is ItemID)\r\n                    {\r\n                        dressItems.Items.Add(list.Items[i].ToString());\r\n                    }\r\n                }\r\n            }\r\n\r\n            dressItems.EndUpdate();\r\n        }\r\n\r\n        private void dressUseCur_Click(object sender, System.EventArgs e)\r\n        {\r\n            DressList list = (DressList) dressList.SelectedItem;\r\n            if (World.Player == null)\r\n                return;\r\n            if (list == null)\r\n                return;\r\n\r\n            for (int i = 0; i < World.Player.Contains.Count; i++)\r\n            {\r\n                Item item = (Item) World.Player.Contains[i];\r\n                if (item.Layer <= Layer.LastUserValid && item.Layer != Layer.Backpack && item.Layer != Layer.Hair &&\r\n                    item.Layer != Layer.FacialHair)\r\n                    list.Items.Add(item.Serial);\r\n            }\r\n\r\n            dressList.SafeAction(s =>\r\n            {\r\n                s.SelectedItem = null;\r\n                s.SelectedItem = list;\r\n            });\r\n        }\r\n\r\n        private void hotkeyTree_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)\r\n        {\r\n            ClearHKCtrls();\r\n\r\n            if (e.Node == null || !(e.Node.Tag is KeyData))\r\n                return;\r\n            KeyData hk = (KeyData) e.Node.Tag;\r\n\r\n            try\r\n            {\r\n                m_LastKV = hk.Key;\r\n                switch (hk.Key)\r\n                {\r\n                    case -1:\r\n                        hkKey.Text = (\"MouseWheel UP\");\r\n                        break;\r\n                    case -2:\r\n                        hkKey.Text = (\"MouseWheel DOWN\");\r\n                        break;\r\n                    case -3:\r\n                        hkKey.Text = (\"Mouse MID Button\");\r\n                        break;\r\n                    case -4:\r\n                        hkKey.Text = (\"Mouse XButton 1\");\r\n                        break;\r\n                    case -5:\r\n                        hkKey.Text = (\"Mouse XButton 2\");\r\n                        break;\r\n                    default:\r\n                        if (hk.Key > 0 && hk.Key < 256)\r\n                            hkKey.Text = (((Keys) hk.Key).ToString());\r\n                        else\r\n                            hkKey.Text = (\"\");\r\n                        break;\r\n                }\r\n            }\r\n            catch\r\n            {\r\n                hkKey.Text = \">>ERROR<<\";\r\n            }\r\n\r\n            chkCtrl.Checked = (hk.Mod & ModKeys.Control) != 0;\r\n            chkAlt.Checked = (hk.Mod & ModKeys.Alt) != 0;\r\n            chkShift.Checked = (hk.Mod & ModKeys.Shift) != 0;\r\n            chkPass.Checked = hk.SendToUO;\r\n\r\n            hkCommand.Text = hk.Command;\r\n\r\n            if ((hk.LocName >= (int) LocString.DrinkHeal && hk.LocName <= (int) LocString.DrinkAg &&\r\n                 !Client.Instance.AllowBit(FeatureBit.PotionHotkeys)) ||\r\n                (hk.LocName >= (int) LocString.TargCloseRed && hk.LocName <= (int) LocString.TargCloseCriminal &&\r\n                 !Client.Instance.AllowBit(FeatureBit.ClosestTargets)) ||\r\n                (((hk.LocName >= (int) LocString.TargRandRed && hk.LocName <= (int) LocString.TargRandNFriend) ||\r\n                  (hk.LocName >= (int) LocString.TargRandEnemyHuman && hk.LocName <= (int) LocString.TargRandCriminal)\r\n                 ) && !Client.Instance.AllowBit(FeatureBit.RandomTargets)))\r\n            {\r\n                LockControl(chkCtrl);\r\n                LockControl(chkAlt);\r\n                LockControl(chkShift);\r\n                LockControl(chkPass);\r\n                LockControl(hkKey);\r\n                LockControl(hkCommand);\r\n                LockControl(unsetHK);\r\n                LockControl(setHK);\r\n                LockControl(dohotkey);\r\n            }\r\n        }\r\n\r\n        private KeyData GetSelectedHK()\r\n        {\r\n            if (hotkeyTree != null && hotkeyTree.SelectedNode != null)\r\n                return hotkeyTree.SelectedNode.Tag as KeyData;\r\n            else\r\n                return null;\r\n        }\r\n\r\n        private void ClearHKCtrls()\r\n        {\r\n            m_LastKV = 0;\r\n            hkKey.Text = \"\";\r\n            hkCommand.Text = \"\";\r\n            chkCtrl.Checked = false;\r\n            chkAlt.Checked = false;\r\n            chkShift.Checked = false;\r\n            chkPass.Checked = false;\r\n\r\n            UnlockControl(chkCtrl);\r\n            UnlockControl(chkAlt);\r\n            UnlockControl(chkShift);\r\n            UnlockControl(chkPass);\r\n            UnlockControl(hkKey);\r\n            UnlockControl(hkCommand);\r\n            UnlockControl(unsetHK);\r\n            UnlockControl(setHK);\r\n            UnlockControl(dohotkey);\r\n        }\r\n\r\n        private void setHK_Click(object sender, System.EventArgs e)\r\n        {\r\n            KeyData hk = GetSelectedHK();\r\n            if (hk == null || m_LastKV == 0)\r\n                return;\r\n\r\n            ModKeys mod = ModKeys.None;\r\n            if (chkCtrl.Checked)\r\n                mod |= ModKeys.Control;\r\n            if (chkAlt.Checked)\r\n                mod |= ModKeys.Alt;\r\n            if (chkShift.Checked)\r\n                mod |= ModKeys.Shift;\r\n\r\n            KeyData g = HotKey.Get(m_LastKV, mod);\r\n            bool block = false;\r\n\r\n            if (g != null && g != hk)\r\n            {\r\n                if (MessageBox.Show(this, Language.Format(LocString.KeyUsed, g.DisplayName, hk.DisplayName),\r\n                        \"Hot Key Conflict\", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n                {\r\n                    g.Key = 0;\r\n                    g.Mod = ModKeys.None;\r\n                    g.SendToUO = false;\r\n                    g.Command = hkCommand.Text;\r\n                }\r\n                else\r\n                {\r\n                    block = true;\r\n                }\r\n            }\r\n\r\n            if (!block)\r\n            {\r\n                hk.Key = m_LastKV;\r\n                hk.Mod = mod;\r\n\r\n                hk.SendToUO = chkPass.Checked;\r\n            }\r\n\r\n            if (!string.IsNullOrEmpty(hkCommand.Text))\r\n            {\r\n                if (HotKey.ValidateCommand(hkCommand.Text.Trim()))\r\n                {\r\n                    hk.Command = hkCommand.Text.Trim();\r\n                }\r\n                else\r\n                {\r\n                    MessageBox.Show(this, \"That hotkey command is already in use, please enter another.\", \"HotKey Command In Use\", MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    hk.Command = string.Empty;\r\n                }\r\n            }\r\n\r\n            if (!string.IsNullOrEmpty(filterHotkeys.Text))\r\n            {\r\n                TreeNode node = hotkeyTree.SelectedNode;\r\n\r\n                HotKey.RebuildList(hotkeyTree);\r\n                RebuildHotKeyCache();\r\n\r\n                filterHotkeys_TextChanged(sender, e);\r\n\r\n                hotkeyTree.SelectedNode = node;\r\n            }\r\n        }\r\n\r\n        private void unsetHK_Click(object sender, System.EventArgs e)\r\n        {\r\n            KeyData hk = GetSelectedHK();\r\n            if (hk == null)\r\n                return;\r\n\r\n            hk.Key = 0;\r\n            hk.Mod = 0;\r\n            hk.SendToUO = false;\r\n            hk.Command = string.Empty;\r\n\r\n            ClearHKCtrls();\r\n\r\n            if (!string.IsNullOrEmpty(filterHotkeys.Text))\r\n            {\r\n                TreeNode node = hotkeyTree.SelectedNode;\r\n\r\n                HotKey.RebuildList(hotkeyTree);\r\n                RebuildHotKeyCache();\r\n\r\n                filterHotkeys_TextChanged(sender, e);\r\n\r\n                hotkeyTree.SelectedNode = node;\r\n            }\r\n        }\r\n\r\n        private void key_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)\r\n        {\r\n            m_LastKV = (int) e.KeyCode;\r\n            hkKey.Text = e.KeyCode.ToString();\r\n\r\n            e.Handled = true;\r\n        }\r\n\r\n        private void key_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Delta > 0)\r\n            {\r\n                m_LastKV = -1;\r\n                hkKey.Text = \"MouseWheel UP\";\r\n            }\r\n            else if (e.Delta < 0)\r\n            {\r\n                m_LastKV = -2;\r\n                hkKey.Text = \"MouseWheel DOWN\";\r\n            }\r\n        }\r\n\r\n        private void key_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Middle)\r\n            {\r\n                m_LastKV = -3;\r\n                hkKey.Text = \"Mouse MID Button\";\r\n            }\r\n            else if (e.Button == MouseButtons.XButton1)\r\n            {\r\n                m_LastKV = -4;\r\n                hkKey.Text = \"Mouse XButton 1\";\r\n            }\r\n            else if (e.Button == MouseButtons.XButton2)\r\n            {\r\n                m_LastKV = -5;\r\n                hkKey.Text = \"Mouse XButton 2\";\r\n            }\r\n        }\r\n\r\n        private void dohotkey_Click(object sender, System.EventArgs e)\r\n        {\r\n            KeyData hk = GetSelectedHK();\r\n            if (hk != null && World.Player != null)\r\n            {\r\n                if (MacroManager.AcceptActions)\r\n                    MacroManager.Action(new HotKeyAction(hk));\r\n\r\n                ScriptManager.AddToScript($\"hotkey '{hk.DisplayName}'\");\r\n\r\n                hk.Callback();\r\n            }\r\n        }\r\n\r\n        private void queueTargets_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"QueueTargets\", queueTargets.Checked);\r\n        }\r\n\r\n        private void chkForceSpeechHue_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            setSpeechHue.Enabled = chkForceSpeechHue.Checked;\r\n            Config.SetProperty(\"ForceSpeechHue\", chkForceSpeechHue.Checked);\r\n        }\r\n\r\n        private void lthilight_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (!(setLTHilight.Enabled = lthilight.Checked))\r\n            {\r\n                Config.SetProperty(\"LTHilight\", 0);\r\n                Client.Instance.SetCustomNotoHue(0);\r\n                lthilight.BackColor = SystemColors.Control;\r\n                lthilight.ForeColor = SystemColors.ControlText;\r\n            }\r\n        }\r\n\r\n        private void chkForceSpellHue_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (chkForceSpellHue.Checked)\r\n            {\r\n                setBeneHue.Enabled = setHarmHue.Enabled = setNeuHue.Enabled = true;\r\n                Config.SetProperty(\"ForceSpellHue\", true);\r\n            }\r\n            else\r\n            {\r\n                setBeneHue.Enabled = setHarmHue.Enabled = setNeuHue.Enabled = false;\r\n                Config.SetProperty(\"ForceSpellHue\", false);\r\n            }\r\n        }\r\n\r\n        private void txtSpellFormat_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"SpellFormat\", txtSpellFormat.Text.Trim());\r\n        }\r\n\r\n        private void InitPreviewHue(Control ctrl, string cfg)\r\n        {\r\n            int hueIdx = Config.GetInt(cfg);\r\n            if (hueIdx > 0 && hueIdx < 3000)\r\n                ctrl.BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\r\n            else\r\n                ctrl.BackColor = SystemColors.Control;\r\n            ctrl.ForeColor = (ctrl.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\r\n        }\r\n\r\n        private bool SetHue(Control ctrl, string cfg)\r\n        {\r\n            HueEntry h = new HueEntry(Config.GetInt(cfg));\r\n\r\n            if (h.ShowDialog(this) == DialogResult.OK)\r\n            {\r\n                int hueIdx = h.Hue;\r\n                Config.SetProperty(cfg, hueIdx);\r\n                if (hueIdx > 0 && hueIdx < 3000)\r\n                    ctrl.BackColor = Ultima.Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\r\n                else\r\n                    ctrl.BackColor = Color.White;\r\n                ctrl.ForeColor = (ctrl.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\r\n\r\n                return true;\r\n            }\r\n            else\r\n            {\r\n                return false;\r\n            }\r\n        }\r\n\r\n        private void setExHue_Click(object sender, System.EventArgs e)\r\n        {\r\n            SetHue(lblExHue, \"ExemptColor\");\r\n        }\r\n\r\n        private void setMsgHue_Click(object sender, System.EventArgs e)\r\n        {\r\n            SetHue(lblMsgHue, \"SysColor\");\r\n        }\r\n\r\n        private void setWarnHue_Click(object sender, System.EventArgs e)\r\n        {\r\n            SetHue(lblWarnHue, \"WarningColor\");\r\n        }\r\n\r\n        private void setSpeechHue_Click(object sender, System.EventArgs e)\r\n        {\r\n            SetHue(chkForceSpeechHue, \"SpeechHue\");\r\n        }\r\n\r\n        private void setLTHilight_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (SetHue(lthilight, \"LTHilight\"))\r\n                Client.Instance.SetCustomNotoHue(Config.GetInt(\"LTHilight\"));\r\n        }\r\n\r\n        private void setBeneHue_Click(object sender, System.EventArgs e)\r\n        {\r\n            SetHue(lblBeneHue, \"BeneficialSpellHue\");\r\n        }\r\n\r\n        private void setHarmHue_Click(object sender, System.EventArgs e)\r\n        {\r\n            SetHue(lblHarmHue, \"HarmfulSpellHue\");\r\n        }\r\n\r\n        private void setNeuHue_Click(object sender, System.EventArgs e)\r\n        {\r\n            SetHue(lblNeuHue, \"NeutralSpellHue\");\r\n        }\r\n\r\n        private void QueueActions_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            //txtObjDelay.Enabled = QueueActions.Checked;\r\n            Config.SetProperty(\"QueueActions\", QueueActions.Checked);\r\n        }\r\n\r\n        private void txtObjDelay_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ObjectDelay\", Utility.ToInt32(txtObjDelay.Text.Trim(), 500));\r\n        }\r\n\r\n        private void chkStealth_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CountStealthSteps\", chkStealth.Checked);\r\n\r\n            stealthOverhead.Enabled = chkStealth.Checked;\r\n        }\r\n\r\n        private void agentList_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                Agent.Select(agentList.SelectedIndex, agentList, agentSubList, agentGroup, agentB1, agentB2, agentB3,\r\n                    agentB4, agentB5, agentB6);\r\n\r\n                agentSetHotKey.Visible = true;\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private void Agent_Button(int b)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            Agent a = agentList.SelectedItem as Agent;\r\n            if (a == null)\r\n                agentList.SelectedIndex = -1;\r\n            else\r\n                a.OnButtonPress(b);\r\n        }\r\n\r\n        private void agentB1_Click(object sender, System.EventArgs e)\r\n        {\r\n            Agent_Button(1);\r\n        }\r\n\r\n        private void agentB2_Click(object sender, System.EventArgs e)\r\n        {\r\n            Agent_Button(2);\r\n        }\r\n\r\n        private void agentB3_Click(object sender, System.EventArgs e)\r\n        {\r\n            Agent_Button(3);\r\n        }\r\n\r\n        private void agentB4_Click(object sender, System.EventArgs e)\r\n        {\r\n            Agent_Button(4);\r\n        }\r\n\r\n        private void agentB5_Click(object sender, System.EventArgs e)\r\n        {\r\n            Agent_Button(5);\r\n        }\r\n\r\n        private void agentB6_Click(object sender, System.EventArgs e)\r\n        {\r\n            Agent_Button(6);\r\n        }\r\n\r\n        private void MainForm_Activated(object sender, System.EventArgs e)\r\n        {\r\n            DisableCloseButton();\r\n            //this.TopMost = true;\r\n        }\r\n\r\n        private void MainForm_Deactivate(object sender, System.EventArgs e)\r\n        {\r\n            if (this.TopMost)\r\n                this.TopMost = false;\r\n        }\r\n\r\n        private void MainForm_Resize(object sender, System.EventArgs e)\r\n        {\r\n            if (WindowState == FormWindowState.Minimized && !this.ShowInTaskbar)\r\n                this.Hide();\r\n        }\r\n\r\n        private void MainForm_ResizeEnd(object sender, System.EventArgs e)\r\n        {\r\n            cliLocOverheadView.SafeAction(s =>\r\n            {\r\n                s.BeginUpdate();\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);\r\n                s.EndUpdate();\r\n            });\r\n\r\n            cliLocSearchView.SafeAction(s =>\r\n            {\r\n                s.BeginUpdate();\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);\r\n                s.EndUpdate();\r\n            });\r\n\r\n            counters.SafeAction(s =>\r\n            {\r\n                s.BeginUpdate();\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);\r\n                s.EndUpdate();\r\n            });\r\n\r\n            skillList.SafeAction(s =>\r\n            {\r\n                s.BeginUpdate();\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);\r\n                s.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);\r\n                s.EndUpdate();\r\n            });\r\n\r\n            Config.SetProperty(\"WindowSizeX\", Engine.MainWindow.Size.Width);\r\n            Config.SetProperty(\"WindowSizeY\", Engine.MainWindow.Size.Height);\r\n        }\r\n\r\n        private bool IsNear(int a, int b)\r\n        {\r\n            return (a <= b + 5 && a >= b - 5);\r\n        }\r\n\r\n        public bool IsOnScreen(Form form)\r\n        {\r\n            Screen[] screens = Screen.AllScreens;\r\n            foreach (Screen screen in screens)\r\n            {\r\n                Point formTopLeft = new Point(form.Left, form.Top);\r\n\r\n                if (screen.WorkingArea.Contains(formTopLeft))\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        private void MainForm_Move(object sender, System.EventArgs e)\r\n        {\r\n            // atempt to dock to the side of the screen.  Also try not to save the X/Y when we are minimized (which is -32000, -32000)\r\n            System.Drawing.Point pt = this.Location;\r\n\r\n            Rectangle screen = Screen.GetWorkingArea(this);\r\n            if (this.WindowState != FormWindowState.Minimized && pt.X + this.Width / 2 >= screen.Left &&\r\n                pt.Y + this.Height / 2 >= screen.Top && pt.X <= screen.Right && pt.Y <= screen.Bottom)\r\n            {\r\n                if (IsNear(pt.X + this.Width, screen.Right))\r\n                    pt.X = screen.Right - this.Width;\r\n                else if (IsNear(pt.X, screen.Left))\r\n                    pt.X = screen.Left;\r\n\r\n                if (IsNear(pt.Y + this.Height, screen.Bottom))\r\n                    pt.Y = screen.Bottom - this.Height;\r\n                else if (IsNear(pt.Y, screen.Top))\r\n                    pt.Y = screen.Top;\r\n\r\n                this.Location = pt;\r\n                Config.SetProperty(\"WindowX\", (int) pt.X);\r\n                Config.SetProperty(\"WindowY\", (int) pt.Y);\r\n            }\r\n        }\r\n\r\n        private void opacity_Scroll(object sender, System.EventArgs e)\r\n        {\r\n            int o = opacity.Value;\r\n            Config.SetProperty(\"Opacity\", o);\r\n            opacityLabel.Text = $\"Opacity: {o}%\";\r\n            this.Opacity = ((double) o) / 100.0;\r\n        }\r\n\r\n        private void dispDelta_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DisplaySkillChanges\", dispDelta.Checked);\r\n        }\r\n\r\n        /*private void saveProfile_Click(object sender, System.EventArgs e)\r\n        {\r\n             Counter.Save();\r\n             Config.Save();\r\n             MacroManager.Save();\r\n             MessageBox.Show( this, Language.GetString( LocString.SaveOK ), \"Save OK\", MessageBoxButtons.OK, MessageBoxIcon.Information );\r\n        }\r\n\r\n        private void edit_Click(object sender, System.EventArgs e)\r\n        {\r\n             if ( counters.SelectedItems.Count <= 0 )\r\n                  return;\r\n\r\n             Counter c = counters.SelectedItems[0].Tag as Counter;\r\n             if ( c == null )\r\n                  return;\r\n\r\n             AddCounter dlg = new AddCounter( c.Name, c.Format, c.ItemID, c.Hue );\r\n\r\n             if ( dlg.ShowDialog( this ) == DialogResult.OK )\r\n             {\r\n                  c.Name = dlg.NameStr;\r\n                  c.Format = dlg.FmtStr;\r\n                  c.ItemID = (ushort)dlg.ItemID;\r\n                  c.Hue = (int)dlg.Hue;\r\n                  Counter.Redraw( counters );\r\n             }\r\n        }*/\r\n\r\n        private void logPackets_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (logPackets.Checked)\r\n            {\r\n                if (m_Initializing || MessageBox.Show(this, Language.GetString(LocString.PacketLogWarn), \"Caution!\",\r\n                        MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)\r\n                    Packet.Logging = true;\r\n                else\r\n                    logPackets.Checked = false;\r\n            }\r\n            else\r\n            {\r\n                Packet.Logging = false;\r\n            }\r\n        }\r\n\r\n        private void showNotoHue_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowNotoHue\", showNotoHue.Checked);\r\n            if (showNotoHue.Checked)\r\n                Client.Instance.RequestTitlebarUpdate();\r\n        }\r\n\r\n        private void recount_Click(object sender, System.EventArgs e)\r\n        {\r\n            Counter.FullRecount();\r\n        }\r\n\r\n        private void openCorpses_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoOpenCorpses\", openCorpses.Checked);\r\n            corpseRange.Enabled = openCorpses.Checked;\r\n        }\r\n\r\n        private void corpseRange_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CorpseRange\", Utility.ToInt32(corpseRange.Text, 2));\r\n        }\r\n\r\n        private void showWelcome_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetAppSetting(\"ShowWelcome\", (showWelcome.Checked ? 1 : 0).ToString());\r\n        }\r\n\r\n        private ContextMenuStrip m_DressItemsMenu = null;\r\n\r\n        private void dressItems_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right)\r\n            {\r\n                m_DressItemsMenu = new ContextMenuStrip();\r\n                m_DressItemsMenu.Items.Add(Language.GetString(LocString.Conv2Type), null, OnMakeType);\r\n                m_DressItemsMenu.Show(dressItems, new Point(e.X, e.Y));\r\n            }\r\n        }\r\n\r\n        private void OnMakeType(object sender, System.EventArgs e)\r\n        {\r\n            DressList list = (DressList) dressList.SelectedItem;\r\n            if (list == null)\r\n                return;\r\n            int sel = dressItems.SelectedIndex;\r\n            if (sel < 0 || sel >= list.Items.Count)\r\n                return;\r\n\r\n            if (list.Items[sel] is Serial)\r\n            {\r\n                Serial s = (Serial) list.Items[sel];\r\n                Item item = World.FindItem(s);\r\n                if (item != null)\r\n                {\r\n                    list.Items[sel] = item.ItemID;\r\n                    dressItems.BeginUpdate();\r\n                    dressItems.Items[sel] = item.ItemID.ToString();\r\n                    dressItems.EndUpdate();\r\n                }\r\n            }\r\n        }\r\n\r\n        private static char[] m_InvalidNameChars = new char[] {'/', '\\\\', ';', '?', ':', '*'};\r\n\r\n        private void newMacro_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (InputBox.Show(this, Language.GetString(LocString.NewMacro), Language.GetString(LocString.EnterAName)))\r\n            {\r\n                string name = InputBox.GetString();\r\n                if (name == null || name == \"\" || name.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                    name.IndexOfAny(m_InvalidNameChars) != -1)\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.InvalidChars),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                TreeNode node = GetMacroDirNode();\r\n                string path = (node == null || !(node.Tag is string))\r\n                    ? Config.GetUserDirectory(\"Macros\")\r\n                    : (string) node.Tag;\r\n                path = Path.Combine(path, name + \".macro\");\r\n                if (File.Exists(path))\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.MacroExists),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                try\r\n                {\r\n                    bool createFromClipboard = false;\r\n\r\n                    // TODO: Instead of contains, do we want to look at the first X number of characters\r\n                    if (Clipboard.GetText().Contains(\"Assistant.Macros.\"))\r\n                    {\r\n                        createFromClipboard = MessageBox.Show(this, Language.GetString(LocString.NewClipboardMacro),\r\n                                                  \"Create new macro from clipboard?\", MessageBoxButtons.YesNo,\r\n                                                  MessageBoxIcon.Question) == DialogResult.Yes;\r\n\r\n                        if (createFromClipboard)\r\n                        {\r\n                            string[] macroCommands = Clipboard.GetText()\r\n                                .Split(new[] {\"\\r\\n\", \"\\r\", \"\\n\"}, StringSplitOptions.None);\r\n\r\n                            File.WriteAllLines(path, macroCommands);\r\n\r\n                            Clipboard.Clear();\r\n                        }\r\n                        else\r\n                        {\r\n                            File.CreateText(path).Close();\r\n                        }\r\n                    }\r\n\r\n                    // If they didn't create from clipboard, create empty macro\r\n                    if (!createFromClipboard)\r\n                    {\r\n                        File.CreateText(path).Close();\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                    // access issue or other issue, create empty macro and move on\r\n                    File.CreateText(path).Close();\r\n                }\r\n\r\n                Macro m = new Macro(path);\r\n                MacroManager.Add(m);\r\n                TreeNode newNode = new TreeNode(Path.GetFileNameWithoutExtension(m.Filename));\r\n                newNode.Tag = m;\r\n                if (node == null)\r\n                    macroTree.Nodes.Add(newNode);\r\n                else\r\n                    node.Nodes.Add(newNode);\r\n                macroTree.SelectedNode = newNode;\r\n            }\r\n\r\n            filterMacros.Text = string.Empty;\r\n\r\n            RedrawMacros();\r\n        }\r\n\r\n        public Macro GetMacroSel()\r\n        {\r\n            if (macroTree.SelectedNode == null || !(macroTree.SelectedNode.Tag is Macro))\r\n                return null;\r\n            else\r\n                return (Macro) macroTree.SelectedNode.Tag;\r\n        }\r\n\r\n        public RazorScript GetScriptSel()\r\n        {\r\n            if (scriptTree.SelectedNode == null || !(scriptTree.SelectedNode.Tag is RazorScript))\r\n            {\r\n                return null;\r\n            }\r\n            else\r\n            {\r\n                return (RazorScript)scriptTree.SelectedNode.Tag;\r\n            }\r\n        }\r\n\r\n        public void playMacro_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            // Playing is true if the timer is running which in a step-through scenario isn't true\r\n            if (MacroManager.Playing || MacroManager.StepThrough)\r\n            {\r\n                MacroManager.Stop();\r\n                nextMacroAction.Enabled = false;\r\n            }\r\n            else\r\n            {\r\n                Macro m = GetMacroSel();\r\n                if (m == null || m.Actions.Count <= 0)\r\n                    return;\r\n\r\n                // Check if we're going to step through the macro\r\n                nextMacroAction.Enabled = stepThroughMacro.Checked;\r\n                m.StepThrough = stepThroughMacro.Checked;\r\n\r\n                actionList.SelectedIndex = 0;\r\n                MacroManager.Play(m);\r\n                playMacro.Text = \"Stop\";\r\n                recMacro.Enabled = false;\r\n                OnMacroStart(m);\r\n            }\r\n        }\r\n\r\n        private void recMacro_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            if (MacroManager.Recording)\r\n            {\r\n                MacroManager.Stop();\r\n                //OnMacroStop();\r\n            }\r\n            else\r\n            {\r\n                Macro m = GetMacroSel();\r\n                if (m == null)\r\n                    return;\r\n\r\n                bool rec = true;\r\n                if (m.Actions.Count > 0)\r\n                    rec = MessageBox.Show(this, Language.GetString(LocString.MacroConfRec), \"Overwrite?\",\r\n                              MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;\r\n\r\n                if (rec)\r\n                {\r\n                    MacroManager.Record(m);\r\n                    OnMacroStart(m);\r\n                    recMacro.Text = \"Stop\";\r\n                    playMacro.Enabled = false;\r\n                }\r\n            }\r\n        }\r\n\r\n        public void OnMacroStart(Macro m)\r\n        {\r\n            actionList.SelectedIndex = -1;\r\n            macroTree.Enabled = actionList.Enabled = false;\r\n            newMacro.Enabled = delMacro.Enabled = false;\r\n            //macroList.SelectedItem = m;\r\n            macroTree.SelectedNode = FindNode(macroTree.Nodes, m);\r\n            macroTree.Update();\r\n            macroTree.Refresh();\r\n            m.DisplayTo(actionList);\r\n        }\r\n\r\n        public void PlayMacro(Macro m)\r\n        {\r\n            playMacro.Text = \"Stop\";\r\n            recMacro.Enabled = false;\r\n        }\r\n\r\n        public void PlayScript()\r\n        {\r\n            playScript.Text = \"Stop\";\r\n            recordScript.Enabled = false;\r\n        }\r\n\r\n        public void OnMacroStop()\r\n        {\r\n            recMacro.Text = \"Record\";\r\n            recMacro.Enabled = true;\r\n            playMacro.Text = \"Play\";\r\n            playMacro.Enabled = true;\r\n            actionList.SelectedIndex = -1;\r\n            macroTree.Enabled = actionList.Enabled = true;\r\n            newMacro.Enabled = delMacro.Enabled = true;\r\n            nextMacroAction.Enabled = false;\r\n            RedrawMacros();\r\n        }\r\n\r\n        private ContextMenuStrip m_MacroContextMenu = null;\r\n\r\n        private void macroTree_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                if (m_MacroContextMenu == null)\r\n                {\r\n                    m_MacroContextMenu = new ContextMenuStrip();\r\n                    m_MacroContextMenu.Items.Add(\"Add Category\", null, Macro_AddCategory);\r\n                    m_MacroContextMenu.Items.Add(\"Delete Category\", null, Macro_DeleteCategory);\r\n                    m_MacroContextMenu.Items.Add(\"Move to Category\", null, Macro_Move2Category);\r\n                    m_MacroContextMenu.Items.Add(\"-\");\r\n                    m_MacroContextMenu.Items.Add(\"Copy to Clipboard\", null, Macro_CopyToClipboard);\r\n                    m_MacroContextMenu.Items.Add(\"Rename Macro\", null, Macro_Rename);\r\n                    m_MacroContextMenu.Items.Add(\"Open Externally\", null, Open_Externally);\r\n                    m_MacroContextMenu.Items.Add(\"-\");\r\n                    m_MacroContextMenu.Items.Add(\"Convert to Script\", null, ConvertMacroToScript);\r\n                    m_MacroContextMenu.Items.Add(\"-\");\r\n                    m_MacroContextMenu.Items.Add(\"Refresh Macro List\", null, Macro_RefreshList);\r\n                }\r\n\r\n                Macro sel = GetMacroSel();\r\n\r\n                m_MacroContextMenu.Items[1].Enabled = sel == null;\r\n                m_MacroContextMenu.Items[2].Enabled = sel != null;\r\n\r\n                m_MacroContextMenu.Show(this, new Point(e.X, e.Y));\r\n            }\r\n\r\n            //RedrawMacros();\r\n        }\r\n\r\n        private TreeNode GetMacroDirNode()\r\n        {\r\n            if (macroTree.SelectedNode == null)\r\n            {\r\n                return null;\r\n            }\r\n            else\r\n            {\r\n                if (macroTree.SelectedNode.Tag is string)\r\n                    return macroTree.SelectedNode;\r\n                else if (macroTree.SelectedNode.Parent == null || !(macroTree.SelectedNode.Parent.Tag is string))\r\n                    return null;\r\n                else\r\n                    return macroTree.SelectedNode.Parent;\r\n            }\r\n        }\r\n\r\n        private void Macro_AddCategory(object sender, EventArgs args)\r\n        {\r\n            if (!InputBox.Show(this, Language.GetString(LocString.CatName)))\r\n                return;\r\n\r\n            string path = InputBox.GetString();\r\n            if (string.IsNullOrEmpty(path) || path.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                path.IndexOfAny(m_InvalidNameChars) != -1)\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.InvalidChars), \"Invalid Path\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n                return;\r\n            }\r\n\r\n            TreeNode node = GetMacroDirNode();\r\n\r\n            try\r\n            {\r\n                if (node == null || !(node.Tag is string))\r\n                    path = Path.Combine(Config.GetUserDirectory(\"Macros\"), path);\r\n                else\r\n                    path = Path.Combine((string) node.Tag, path);\r\n                Engine.EnsureDirectory(path);\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.Format(LocString.CanCreateDir, path), \"Unable to Create Directory\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            TreeNode newNode = new TreeNode($\"[{Path.GetFileName(path)}]\");\r\n            newNode.Tag = path;\r\n            if (node == null)\r\n                macroTree.Nodes.Add(newNode);\r\n            else\r\n                node.Nodes.Add(newNode);\r\n            RedrawMacros();\r\n            macroTree.SelectedNode = newNode;\r\n        }\r\n\r\n        private void Macro_DeleteCategory(object sender, EventArgs args)\r\n        {\r\n            string path = null;\r\n            if (macroTree.SelectedNode != null)\r\n                path = macroTree.SelectedNode.Tag as string;\r\n\r\n            if (path == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                Directory.Delete(path);\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.CantDelDir), \"Unable to Delete Directory\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            TreeNode node = FindNode(macroTree.Nodes, path);\r\n            node?.Remove();\r\n        }\r\n\r\n        private void Script_DeleteCategory(object sender, EventArgs args)\r\n        {\r\n            string path = null;\r\n\r\n            if (scriptTree.SelectedNode != null)\r\n                path = scriptTree.SelectedNode.Tag as string;\r\n\r\n            if (path == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                Directory.Delete(path);\r\n\r\n                TreeNode node = FindNode(scriptTree.Nodes, path);\r\n                node?.Remove();\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.CantDelDir), \"Unable to Delete Directory\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n            }\r\n        }\r\n\r\n        private void Macro_Move2Category(object sender, EventArgs args)\r\n        {\r\n            Macro sel = GetMacroSel();\r\n            if (sel == null)\r\n                return;\r\n\r\n            List<string> dirNames = new List<string>();\r\n            dirNames.Add(\"<None>\");\r\n\r\n            foreach (string dir in Directory.GetDirectories(Config.GetUserDirectory(\"Macros\")))\r\n            {\r\n                dirNames.Add(dir.Substring(dir.LastIndexOf('\\\\') + 1));\r\n            }\r\n\r\n            if (!InputDropdown.Show(this, Language.GetString(LocString.CatName), dirNames.ToArray()))\r\n                return;\r\n\r\n            try\r\n            {\r\n                File.Move(sel.Filename, InputDropdown.GetString().Equals(\"<None>\")\r\n                    ? Path.Combine(Config.GetUserDirectory(\"Macros\"), $\"{Path.GetFileName(sel.Filename)}\")\r\n                    : Path.Combine(Config.GetUserDirectory(\"Macros\"),\r\n                        $\"{InputDropdown.GetString()}/{Path.GetFileName(sel.Filename)}\"));\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.CantMoveMacro), \"Unable to Move Macro\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n            }\r\n\r\n            RedrawMacros();\r\n            macroTree.SelectedNode = FindNode(macroTree.Nodes, sel);\r\n        }\r\n\r\n        /// <summary>\r\n        /// Copy the selected macro the user's clipboard\r\n        /// </summary>\r\n        /// <param name=\"sender\"></param>\r\n        /// <param name=\"args\"></param>\r\n        private void Macro_CopyToClipboard(object sender, EventArgs args)\r\n        {\r\n            Macro sel = GetMacroSel();\r\n            if (sel == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                string[] macroLines = File.ReadAllLines(sel.Filename);\r\n\r\n                Clipboard.SetText(string.Join(Environment.NewLine, macroLines));\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.ReadError), \"Copy Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void Macro_Rename(object sender, EventArgs args)\r\n        {\r\n            Macro sel = GetMacroSel();\r\n            if (sel == null)\r\n                return;\r\n\r\n            if (InputBox.Show(this, Language.GetString(LocString.MacroRename),\r\n                Language.GetString(LocString.EnterAName)))\r\n            {\r\n                string name = InputBox.GetString();\r\n                if (string.IsNullOrEmpty(name) || name.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                    name.IndexOfAny(m_InvalidNameChars) != -1)\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.InvalidChars),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                string newMacro = $\"{Path.GetDirectoryName(sel.Filename)}/{name}.macro\";\r\n\r\n\r\n                if (File.Exists(newMacro))\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.MacroExists),\r\n                        Language.GetString(LocString.Invalid),\r\n                        MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                try\r\n                {\r\n                    Engine.MainWindow.SafeAction(s =>\r\n                    {\r\n                        File.Move(sel.Filename, newMacro);\r\n                        MacroManager.Remove(sel);\r\n                    });\r\n                }\r\n                catch\r\n                {\r\n                    return;\r\n                }\r\n\r\n                RedrawMacros();\r\n            }\r\n        }\r\n\r\n        private void Open_Externally(object sender, EventArgs args)\r\n        {\r\n            Macro sel = GetMacroSel();\r\n            if (sel == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                Process.Start(sel.Filename);\r\n            }\r\n            catch (Exception)\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.UnableToOpenMacro),\r\n                    Language.GetString(LocString.ReadError),\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void ConvertMacroToScript(object sender, EventArgs args)\r\n        {\r\n            Macro sel = GetMacroSel();\r\n            if (sel == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                string name = sel.GetName();\r\n                string path = Path.Combine(ScriptManager.ScriptPath, $\"{name}.razor\");\r\n\r\n                if (File.Exists(Path.Combine(Config.GetUserDirectory(\"Scripts\"), name)))\r\n                {\r\n                    path = Path.Combine(ScriptManager.ScriptPath, $\"{name}-{Guid.NewGuid().ToString().Substring(0, 4)}.razor\");\r\n                }\r\n\r\n                List<string> scriptLines = new List<string>();\r\n\r\n                foreach (MacroAction selAction in sel.Actions)\r\n                {\r\n                    scriptLines.Add(selAction.ToScript());\r\n                }\r\n\r\n                File.WriteAllLines(path, scriptLines.ToArray());\r\n\r\n                RazorScript script = ScriptManager.AddScript(path);\r\n\r\n                RedrawScripts();\r\n\r\n                tabs.SelectedTab = scriptsTab;\r\n\r\n                TreeNode node = FindScriptNode(scriptTree.Nodes, script);\r\n                scriptTree.SelectedNode = node;\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                MessageBox.Show(this, $\"Unable to convert macro to script: {ex.Message}\", \"Macro to Script Conversion\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void Macro_RefreshList(object sender, EventArgs args)\r\n        {\r\n            RedrawMacros();\r\n        }\r\n\r\n        private static TreeNode FindNode(TreeNodeCollection nodes, object tag)\r\n        {\r\n            for (int i = 0; i < nodes.Count; i++)\r\n            {\r\n                TreeNode node = nodes[i];\r\n\r\n                if (node.Tag == tag)\r\n                {\r\n                    return node;\r\n                }\r\n                else if (node.Nodes.Count > 0)\r\n                {\r\n                    node = FindNode(node.Nodes, tag);\r\n                    if (node != null)\r\n                        return node;\r\n                }\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        private static TreeNode FindScriptNode(TreeNodeCollection nodes, object tag)\r\n        {\r\n            for (int i = 0; i < nodes.Count; i++)\r\n            {\r\n                TreeNode node = nodes[i];\r\n\r\n                if (node.Tag.ToString().Equals(tag.ToString()))\r\n                {\r\n                    return node;\r\n                }\r\n                else if (node.Nodes.Count > 0)\r\n                {\r\n                    node = FindScriptNode(node.Nodes, tag);\r\n                    if (node != null)\r\n                        return node;\r\n                }\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        private void RedrawMacros()\r\n        {\r\n            Macro ms = GetMacroSel();\r\n            MacroManager.DisplayTo(macroTree);\r\n            if (ms != null)\r\n                macroTree.SelectedNode = FindNode(macroTree.Nodes, ms);\r\n\r\n            RebuildMacroCache();\r\n\r\n            MacroManager.DisplayMacroVariables(macroVariables);\r\n        }\r\n\r\n        private void RedrawScripts()\r\n        {\r\n            RazorScript rs = GetScriptSel();\r\n\r\n            ScriptManager.RedrawScripts();\r\n\r\n            if (rs != null)\r\n            {\r\n                scriptTree.SelectedNode = FindScriptNode(scriptTree.Nodes, rs);\r\n            }\r\n\r\n            RebuildScriptCache();\r\n\r\n            ScriptManager.RedrawScriptVariables();\r\n        }\r\n\r\n        private void RedrawItems()\r\n        {\r\n            StaffToolsManager.LoadItems(itemTree);\r\n\r\n            RebuildItemCache();\r\n        }\r\n\r\n        public Macro LastSelectedMacro { get; set; }\r\n\r\n        private void macroTree_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)\r\n        {\r\n            if (MacroManager.Recording)\r\n                return;\r\n\r\n            Macro m = e.Node.Tag as Macro;\r\n            macroActGroup.Visible = m != null;\r\n            MacroManager.Select(m, actionList, playMacro, recMacro, loopMacro);\r\n\r\n            LastSelectedMacro = m;\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            Engine.MainWindow.SafeAction(s =>\r\n            {\r\n                if (hotkeyTree.TopNode == null)\r\n                {\r\n                    HotKey.RebuildList(hotkeyTree);\r\n                    RebuildHotKeyCache();\r\n                }\r\n                \r\n                TreeNode resultNode = SearchTreeView(Language.Format(LocString.PlayA1, m.GetName()), hotkeyTree.Nodes);\r\n\r\n                if (resultNode != null)\r\n                {\r\n                    KeyData hk = (KeyData) resultNode.Tag;\r\n\r\n                    if (hk != null && !string.IsNullOrEmpty(hk.KeyString()))\r\n                    {\r\n                        macroActGroup.Text = $\"Actions ({hk.KeyString()})\";\r\n                    }\r\n                    else\r\n                    {\r\n                        macroActGroup.Text = \"Actions (Not Set)\";\r\n                    }\r\n                }\r\n            });\r\n        }\r\n\r\n        private void delMacro_Click(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n            {\r\n                Macro_DeleteCategory(sender, e);\r\n                return;\r\n            }\r\n\r\n            if (m == MacroManager.Current)\r\n                return;\r\n\r\n            if (m.Actions.Count <= 0 || MessageBox.Show(this, Language.Format(LocString.DelConf, m.ToString()),\r\n                    \"Confirm Delete\", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                try\r\n                {\r\n                    File.Delete(m.Filename);\r\n                }\r\n                catch\r\n                {\r\n                    return;\r\n                }\r\n\r\n                MacroManager.Remove(m);\r\n\r\n                TreeNode node = FindNode(macroTree.Nodes, m);\r\n                node?.Remove();\r\n            }\r\n\r\n            RebuildMacroCache();\r\n        }\r\n\r\n        private void actionList_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\r\n                    return;\r\n\r\n                ContextMenuStrip menu = new ContextMenuStrip();\r\n                menu.Items.Add(Language.GetString(LocString.Reload), null, onMacroReload);\r\n                menu.Items.Add(Language.GetString(LocString.Save), null, onMacroSave);\r\n\r\n                MacroAction a;\r\n                try\r\n                {\r\n                    a = actionList.SelectedItem as MacroAction;\r\n                }\r\n                catch\r\n                {\r\n                    a = null;\r\n                }\r\n\r\n                if (a != null)\r\n                {\r\n                    int pos = actionList.SelectedIndex;\r\n\r\n                    menu.Items.Add(\"-\");\r\n                    if (actionList.Items.Count > 1)\r\n                    {\r\n                        menu.Items.Add(Language.GetString(LocString.MoveUp), null, OnMacroActionMoveUp);\r\n\r\n                        if (pos <= 0)\r\n                        {\r\n                            menu.Items[menu.Items.Count - 1].Enabled = false;\r\n                        }\r\n\r\n                        menu.Items.Add(Language.GetString(LocString.MoveDown), null, OnMacroActionMoveDown);\r\n\r\n                        if (pos >= actionList.Items.Count - 1)\r\n                        {\r\n                            menu.Items[menu.Items.Count - 1].Enabled = false;\r\n                        }\r\n\r\n                        menu.Items.Add(\"-\");\r\n                    }\r\n\r\n                    menu.Items.Add(\"Copy Line\", null, onMacroCopyLine);\r\n                    menu.Items.Add(\"Paste Line\", null, onMacroPasteLine);\r\n\r\n                    menu.Items.Add(Language.GetString(LocString.RemAct), null, onMacroActionDelete);\r\n                    menu.Items.Add(\"-\");\r\n                    menu.Items.Add(Language.GetString(LocString.BeginRec), null, onMacroBegRecHere);\r\n                    menu.Items.Add(Language.GetString(LocString.PlayFromHere), null, onMacroPlayHere);\r\n\r\n                    ToolStripMenuItem[] aMenus = a.GetContextMenuItems();\r\n                    if (aMenus != null && aMenus.Length > 0)\r\n                    {\r\n                        menu.Items.Add(\"-\");\r\n                        menu.Items.AddRange(aMenus);\r\n                    }\r\n                }\r\n\r\n                menu.Items.Add(\"-\");\r\n\r\n                ToolStripMenuItem submenu = new ToolStripMenuItem(Language.GetString(LocString.Constructs));\r\n\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsWait), null, onMacroInsPause);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsLT), null, onMacroInsertSetLT);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsComment), null, onMacroInsertComment);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsertOverheadMessage), null, onMacroInsertOverheadMessage);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsertWaitForTarget), null, onMacroInsertWaitForTarget);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsertClearSysMsg), null, onMacroInsertClearSysMsg);\r\n                submenu.DropDownItems.Add(\"-\");\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsIF), null, onMacroInsertIf);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsELSE), null, onMacroInsertElse);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsENDIF), null, onMacroInsertEndIf);\r\n                submenu.DropDownItems.Add(\"-\");\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsFOR), null, onMacroInsertFor);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsENDFOR), null, onMacroInsertEndFor);\r\n                submenu.DropDownItems.Add(\"-\");\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsertWhile), null, onMacroInsertWhile);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsertEndWhile), null, onMacroInsertEndWhile);\r\n                submenu.DropDownItems.Add(\"-\");\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsertDo), null, onMacroInsertDo);\r\n                submenu.DropDownItems.Add(Language.GetString(LocString.InsertDoWhile), null, onMacroInsertDoWhile);\r\n\r\n                menu.Items.Add(submenu);\r\n\r\n                menu.Show(actionList, new Point(e.X, e.Y));\r\n            }\r\n            else if (e.Button == MouseButtons.Left && e.Clicks == 2)\r\n            {\r\n                /*if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\r\n                    return;*/\r\n\r\n                MacroAction a;\r\n                try\r\n                {\r\n                    a = actionList.SelectedItem as MacroAction;\r\n                }\r\n                catch\r\n                {\r\n                    a = null;\r\n                }\r\n\r\n                if (a == null)\r\n                    return;\r\n\r\n                ToolStripMenuItem[] aMenus = a.GetContextMenuItems();\r\n\r\n                if (aMenus != null && aMenus.Length > 0)\r\n                {\r\n                    if (aMenus[0].Text.Equals(Language.GetString(LocString.Edit)))\r\n                    {\r\n                        if (a.GetType().Name.Equals(\"IfAction\"))\r\n                        {\r\n                            new MacroInsertIf(a).ShowDialog(Engine.MainWindow);\r\n                        }\r\n                        else if (a.GetType().Name.Equals(\"ForAction\"))\r\n                        {\r\n                            aMenus[0].PerformClick();\r\n                        }\r\n                        else if (a.GetType().Name.Equals(\"DoWhileAction\"))\r\n                        {\r\n                            aMenus[0].PerformClick();\r\n                        }\r\n                        else if (a.GetType().Name.Equals(\"WhileAction\"))\r\n                        {\r\n                            aMenus[0].PerformClick();\r\n                        }\r\n                        else if (a.GetType().Name.Equals(\"MacroComment\"))\r\n                        {\r\n                            aMenus[0].PerformClick();\r\n                        }\r\n                        else if (a.GetType().Name.Equals(\"SpeechAction\"))\r\n                        {\r\n                            aMenus[0].PerformClick();\r\n                        }\r\n                        else if (a.GetType().Name.Equals(\"GumpResponseAction\"))\r\n                        {\r\n                            aMenus[0].PerformClick();\r\n                        }\r\n                        else if (a.GetType().Name.Equals(\"OverheadMessageAction\"))\r\n                        {\r\n                            aMenus[0].PerformClick();\r\n                        }\r\n                        else\r\n                        {\r\n                            new MacroInsertWait(a).ShowDialog(Engine.MainWindow);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private void onMacroPlayHere(object sender, EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            ;\r\n            if (m == null)\r\n                return;\r\n\r\n            int sel = actionList.SelectedIndex + 1;\r\n            if (sel < 0 || sel > m.Actions.Count)\r\n                sel = m.Actions.Count;\r\n\r\n            MacroManager.PlayAt(m, sel);\r\n            playMacro.Text = \"Stop\";\r\n            nextMacroAction.Enabled = stepThroughMacro.Checked;\r\n            recMacro.Enabled = false;\r\n\r\n            OnMacroStart(m);\r\n        }\r\n\r\n        private void onMacroInsertClearSysMsg(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new ClearSysMessages());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertComment(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            if (InputBox.Show(Language.GetString(LocString.InsComment)))\r\n            {\r\n                m.Actions.Insert(a + 1, new MacroComment(InputBox.GetString()));\r\n                RedrawActionList(m);\r\n            }\r\n        }\r\n\r\n        private void onMacroInsertOverheadMessage(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            if (InputBox.Show(Language.GetString(LocString.InsertOverheadMessage)))\r\n            {\r\n                m.Actions.Insert(a + 1,\r\n                    new OverheadMessageAction((ushort) Config.GetInt(\"SysColor\"), InputBox.GetString()));\r\n                RedrawActionList(m);\r\n            }\r\n        }\r\n\r\n        private void onMacroInsertWaitForTarget(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new WaitForTargetAction());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertSetMacroVariable(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            ToolStripMenuItem mnu = (ToolStripMenuItem) sender;\r\n\r\n            m.Actions.Insert(a + 1, new SetMacroVariableTargetAction(mnu.Text));\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertIf(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            MacroInsertIf ins = new MacroInsertIf(m, a);\r\n            if (ins.ShowDialog(this) == DialogResult.OK)\r\n                RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertElse(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            ;\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new ElseAction());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertEndIf(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            ;\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new EndIfAction());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertFor(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            if (InputBox.Show(Language.GetString(LocString.NumIter)))\r\n            {\r\n                m.Actions.Insert(a + 1, new ForAction(InputBox.GetInt(1)));\r\n                RedrawActionList(m);\r\n            }\r\n        }\r\n\r\n        private void onMacroInsertEndFor(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new EndForAction());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertWhile(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            MacroInsertWhile ins = new MacroInsertWhile(m, a);\r\n            if (ins.ShowDialog(this) == DialogResult.OK)\r\n                RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertEndWhile(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new EndWhileAction());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertDo(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new StartDoWhileAction());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertDoWhile(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            MacroInsertDoWhile ins = new MacroInsertDoWhile(m, a);\r\n            if (ins.ShowDialog(this) == DialogResult.OK)\r\n                RedrawActionList(m);\r\n        }\r\n\r\n        private void OnMacroActionMoveUp(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            ;\r\n            if (m == null)\r\n                return;\r\n\r\n            int move = actionList.SelectedIndex;\r\n            if (move > 0 && move < m.Actions.Count)\r\n            {\r\n                MacroAction a = (MacroAction) m.Actions[move - 1];\r\n                m.Actions[move - 1] = m.Actions[move];\r\n                m.Actions[move] = a;\r\n\r\n                RedrawActionList(m);\r\n                actionList.SelectedIndex = move - 1;\r\n            }\r\n        }\r\n\r\n        private void OnMacroActionMoveDown(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            ;\r\n            if (m == null)\r\n                return;\r\n\r\n            int move = actionList.SelectedIndex;\r\n            if (move + 1 < m.Actions.Count)\r\n            {\r\n                MacroAction a = (MacroAction) m.Actions[move + 1];\r\n                m.Actions[move + 1] = m.Actions[move];\r\n                m.Actions[move] = a;\r\n\r\n                RedrawActionList(m);\r\n                actionList.SelectedIndex = move + 1;\r\n            }\r\n        }\r\n\r\n\r\n        private void OnMacroKeyMoveUp()\r\n        {\r\n            Macro m = GetMacroSel();\r\n            ;\r\n            if (m == null)\r\n                return;\r\n\r\n            int move = actionList.SelectedIndex;\r\n            if (move > 0 && move < m.Actions.Count)\r\n            {\r\n                MacroAction a = (MacroAction) m.Actions[move - 1];\r\n                m.Actions[move - 1] = m.Actions[move];\r\n                m.Actions[move] = a;\r\n\r\n                RedrawActionList(m);\r\n            }\r\n        }\r\n\r\n        private void OnMacroKeyMoveDown()\r\n        {\r\n            Macro m = GetMacroSel();\r\n            ;\r\n            if (m == null)\r\n                return;\r\n\r\n            int move = actionList.SelectedIndex;\r\n            if (move + 1 < m.Actions.Count)\r\n            {\r\n                MacroAction a = (MacroAction) m.Actions[move + 1];\r\n                m.Actions[move + 1] = m.Actions[move];\r\n                m.Actions[move] = a;\r\n\r\n                RedrawActionList(m);\r\n            }\r\n        }\r\n\r\n        private void RedrawActionList(Macro m)\r\n        {\r\n            int sel = actionList.SelectedIndex;\r\n            m.DisplayTo(actionList);\r\n            actionList.SelectedIndex = sel;\r\n        }\r\n\r\n        private void actionList_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)\r\n        {\r\n            if (e.KeyCode == Keys.Delete)\r\n            {\r\n                onMacroActionDelete(sender, e);\r\n\r\n                return;\r\n            }\r\n\r\n            int origIndex = actionList.SelectedIndex;\r\n\r\n            if ((e.KeyCode == Keys.Up && e.Control) && actionList.SelectedIndex > 0)\r\n            {\r\n                OnMacroKeyMoveUp();\r\n\r\n                return;\r\n            }\r\n\r\n            if ((e.KeyCode == Keys.Down && e.Control) && actionList.SelectedIndex < actionList.Items.Count)\r\n            {\r\n                OnMacroKeyMoveDown();\r\n\r\n                return;\r\n            }\r\n        }\r\n\r\n        private MacroAction _macroActionToCopy;\r\n\r\n        private void onMacroCopyLine(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a < 0 || a >= m.Actions.Count)\r\n                return;\r\n\r\n            _macroActionToCopy = (MacroAction) m.Actions[a];\r\n        }\r\n\r\n        private void onMacroPasteLine(object sender, System.EventArgs e)\r\n        {\r\n            if (_macroActionToCopy == null)\r\n                return;\r\n\r\n            Macro m = GetMacroSel();\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a < 0 || a >= m.Actions.Count)\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, _macroActionToCopy);\r\n\r\n            RedrawActionList(m);\r\n\r\n            actionList.SelectedIndex = a + 1;\r\n\r\n            onMacroSave(sender, e);\r\n            onMacroReload(sender, e);\r\n        }\r\n\r\n        private void onMacroActionDelete(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a < 0 || a >= m.Actions.Count)\r\n                return;\r\n\r\n            if (MessageBox.Show(this, Language.Format(LocString.DelConf, m.Actions[a].ToString()), \"Confirm\",\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                m.Actions.RemoveAt(a);\r\n                actionList.Items.RemoveAt(a);\r\n            }\r\n        }\r\n\r\n        private void onMacroBegRecHere(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            int sel = actionList.SelectedIndex + 1;\r\n            if (sel < 0 || sel > m.Actions.Count)\r\n                sel = m.Actions.Count;\r\n\r\n            MacroManager.RecordAt(m, sel);\r\n            recMacro.Text = \"Stop\";\r\n            playMacro.Enabled = false;\r\n            OnMacroStart(m);\r\n        }\r\n\r\n        private void onMacroInsPause(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            MacroInsertWait ins = new MacroInsertWait(m, a);\r\n            if (ins.ShowDialog(this) == DialogResult.OK)\r\n                RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroReload(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            m.Load();\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroSave(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            m.Save();\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void onMacroInsertSetLT(object sender, EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n            if (a >= m.Actions.Count) // -1 is valid, will insert @ top\r\n                return;\r\n\r\n            m.Actions.Insert(a + 1, new SetLastTargetAction());\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void loopMacro_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n            m.Loop = loopMacro.Checked;\r\n        }\r\n\r\n        private void jump2SearchEx_Click(object sender, System.EventArgs e)\r\n        {\r\n            tabs.SelectedTab = agentsTab;\r\n            agentList.SelectedItem = SearchExemptionAgent.Instance;\r\n        }\r\n\r\n        private void setScnPath_Click(object sender, System.EventArgs e)\r\n        {\r\n            FolderBrowserDialog folder = new FolderBrowserDialog();\r\n            folder.Description = Language.GetString(LocString.SelSSFolder);\r\n            folder.SelectedPath = Config.GetString(\"CapPath\");\r\n            folder.ShowNewFolderButton = true;\r\n\r\n            if (folder.ShowDialog(this) == DialogResult.OK)\r\n            {\r\n                Config.SetProperty(\"CapPath\", folder.SelectedPath);\r\n                screenPath.Text = folder.SelectedPath;\r\n\r\n                ReloadScreenShotsList();\r\n            }\r\n        }\r\n\r\n        public void ReloadScreenShotsList()\r\n        {\r\n            ScreenCapManager.DisplayTo(screensList);\r\n            if (screenPrev.Image != null)\r\n            {\r\n                screenPrev.Image.Dispose();\r\n                screenPrev.Image = null;\r\n            }\r\n        }\r\n\r\n        private void radioFull_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (radioFull.Checked)\r\n            {\r\n                radioUO.Checked = false;\r\n                Config.SetProperty(\"CapFullScreen\", true);\r\n            }\r\n        }\r\n\r\n        private void radioUO_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (radioUO.Checked)\r\n            {\r\n                radioFull.Checked = false;\r\n                Config.SetProperty(\"CapFullScreen\", false);\r\n            }\r\n        }\r\n\r\n        private void screensList_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (screenPrev.Image != null)\r\n            {\r\n                screenPrev.Image.Dispose();\r\n                screenPrev.Image = null;\r\n            }\r\n\r\n            if (screensList.SelectedIndex == -1)\r\n                return;\r\n\r\n            string file = Path.Combine(Config.GetString(\"CapPath\"), screensList.SelectedItem.ToString());\r\n            if (!File.Exists(file))\r\n            {\r\n                MessageBox.Show(this, Language.Format(LocString.FileNotFoundA1, file), \"File Not Found\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                screensList.Items.RemoveAt(screensList.SelectedIndex);\r\n                screensList.SelectedIndex = -1;\r\n                return;\r\n            }\r\n\r\n            using (Stream reader = new FileStream(file, FileMode.Open, FileAccess.Read))\r\n            {\r\n                screenPrev.Image = Image.FromStream(reader);\r\n            }\r\n        }\r\n\r\n        private void screensList_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                ContextMenuStrip menu = new ContextMenuStrip();\r\n\r\n                menu.Items.Add(\"Copy Image\", null, CopyScreenshot);\r\n                menu.Items.Add(\"-\");\r\n                menu.Items.Add(\"Delete Image\", null, DeleteScreenCap);\r\n\r\n                if (screensList.SelectedIndex == -1)\r\n                    menu.Items[menu.Items.Count - 1].Enabled = false;\r\n\r\n                menu.Items.Add(\"Delete ALL\", null, ClearScreensDirectory);\r\n\r\n\r\n                menu.Show(screensList, new Point(e.X, e.Y));\r\n            }\r\n        }\r\n\r\n        private void CopyScreenshot(object sender, System.EventArgs e)\r\n        {\r\n            int sel = screensList.SelectedIndex;\r\n            if (sel == -1)\r\n                return;\r\n\r\n            Clipboard.SetImage(screenPrev.Image);\r\n        }\r\n\r\n        private void DeleteScreenCap(object sender, System.EventArgs e)\r\n        {\r\n            int sel = screensList.SelectedIndex;\r\n            if (sel == -1)\r\n                return;\r\n\r\n            string file = Path.Combine(Config.GetString(\"CapPath\"), (string) screensList.SelectedItem);\r\n            if (MessageBox.Show(this, Language.Format(LocString.DelConf, file), \"Delete Confirmation\",\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)\r\n                return;\r\n\r\n            screensList.SelectedIndex = -1;\r\n            if (screenPrev.Image != null)\r\n            {\r\n                screenPrev.Image.Dispose();\r\n                screenPrev.Image = null;\r\n            }\r\n\r\n            try\r\n            {\r\n                File.Delete(file);\r\n                screensList.Items.RemoveAt(sel);\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                MessageBox.Show(this, ex.Message, \"Unable to Delete\", MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            ReloadScreenShotsList();\r\n        }\r\n\r\n        private void ClearScreensDirectory(object sender, System.EventArgs e)\r\n        {\r\n            string dir = Config.GetString(\"CapPath\");\r\n            if (MessageBox.Show(this, Language.Format(LocString.Confirm, dir), \"Delete Confirmation\",\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)\r\n                return;\r\n\r\n            string[] files = Directory.GetFiles(dir, \"*.jpg\");\r\n            StringBuilder sb = new StringBuilder();\r\n            int failed = 0;\r\n            for (int i = 0; i < files.Length; i++)\r\n            {\r\n                try\r\n                {\r\n                    File.Delete(files[i]);\r\n                }\r\n                catch\r\n                {\r\n                    sb.AppendFormat(\"{0}\\n\", files[i]);\r\n                    failed++;\r\n                }\r\n            }\r\n\r\n            if (failed > 0)\r\n                MessageBox.Show(this,\r\n                    Language.Format(LocString.FileDelError, failed, failed != 1 ? \"s\" : \"\", sb.ToString()), \"Warning\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n            ReloadScreenShotsList();\r\n        }\r\n\r\n        private void capNow_Click(object sender, System.EventArgs e)\r\n        {\r\n            ScreenCapManager.CaptureNow();\r\n        }\r\n\r\n        private void dispTime_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CapTimeStamp\", dispTime.Checked);\r\n        }\r\n\r\n        public static void LaunchBrowser(string site)\r\n        {\r\n            try\r\n            {\r\n                System.Diagnostics.Process.Start(site); //\"iexplore\", site );\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show($\"Unable to open browser to '{site}'\", \"Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Warning);\r\n            }\r\n        }\r\n\r\n        private void undressConflicts_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"UndressConflicts\", undressConflicts.Checked);\r\n        }\r\n\r\n        private void taskbar_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (taskbar.Checked)\r\n            {\r\n                systray.Checked = false;\r\n                Config.SetProperty(\"Systray\", false);\r\n                /*if (!this.ShowInTaskbar)\r\n                    MessageBox.Show(this, Language.GetString(LocString.NextRestart), \"Notice\", MessageBoxButtons.OK,\r\n                        MessageBoxIcon.Information);*/\r\n            }\r\n        }\r\n\r\n        private void systray_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (systray.Checked)\r\n            {\r\n                taskbar.Checked = false;\r\n                Config.SetProperty(\"Systray\", true);\r\n                /*if (this.ShowInTaskbar)\r\n                    MessageBox.Show(this, Language.GetString(LocString.NextRestart), \"Notice\", MessageBoxButtons.OK,\r\n                        MessageBoxIcon.Information);*/\r\n            }\r\n        }\r\n\r\n        public void UpdateTitle()\r\n        {\r\n            string str = Language.GetControlText(this.Name);\r\n            if (string.IsNullOrEmpty(str))\r\n            {\r\n                str = \"Razor v{0}\";\r\n            }\r\n\r\n            str = string.Format(str, Engine.Version);\r\n\r\n            if (World.Player != null)\r\n            {\r\n                if (Config.GetBool(\"ShowInRazorTitleBar\") && !string.IsNullOrEmpty(razorTitleBar.Text))\r\n                {\r\n                    Text = razorTitleBar.Text.Replace(\"{name}\", World.Player.Name).Replace(\"{shard}\", World.ShardName)\r\n                        .Replace(\"{version}\", Engine.Version).Replace(\"{profile}\", Config.CurrentProfile.Name)\r\n                        .Replace(\"{account}\", World.AccountName);\r\n                }\r\n                else\r\n                {\r\n                    string title = $\"{World.Player.Name} ({World.ShardName}) - {str}\";\r\n                    Text = title;\r\n                }\r\n            }\r\n            else\r\n            {\r\n                Text = str;\r\n            }\r\n\r\n            aboutVer.Text = str;\r\n\r\n            UpdateSystray();\r\n        }\r\n\r\n        public void UpdateSystray()\r\n        {\r\n            if (m_NotifyIcon != null && m_NotifyIcon.Visible)\r\n            {\r\n                if (World.Player != null)\r\n                    if (Config.GetBool(\"ShowInRazorTitleBar\") && !string.IsNullOrEmpty(razorTitleBar.Text))\r\n                    {\r\n                        string title = razorTitleBar.Text.Replace(\"{name}\", World.Player.Name).Replace(\"{shard}\", World.ShardName)\r\n                            .Replace(\"{version}\", Engine.Version).Replace(\"{profile}\", Config.CurrentProfile.Name)\r\n                            .Replace(\"{account}\", World.AccountName);\r\n\r\n                        m_NotifyIcon.Text = title.Length > 63 ? title.Substring(0, 63) : title;\r\n                    }\r\n                    else\r\n                    {\r\n                        m_NotifyIcon.Text = $\"Razor - {World.Player.Name} ({World.ShardName})\";\r\n                    }\r\n                else\r\n                    m_NotifyIcon.Text = \"Razor\";\r\n            }\r\n        }\r\n\r\n        private void DoShowMe(object sender, System.EventArgs e)\r\n        {\r\n            ShowMe();\r\n        }\r\n\r\n        public void ShowMe()\r\n        {\r\n            // In CUO, this can cause an error.\r\n            try\r\n            {\r\n                Platform.SetForegroundWindow(Handle);\r\n                Platform.BringToFront(Handle);\r\n            }\r\n            catch\r\n            {\r\n                BringToFront();\r\n            }\r\n\r\n            try\r\n            {\r\n                this.Show();\r\n            }\r\n            catch\r\n            {\r\n            }\r\n\r\n            if (Config.GetBool(\"AlwaysOnTop\"))\r\n                this.TopMost = true;\r\n            if (WindowState != FormWindowState.Normal)\r\n                WindowState = FormWindowState.Normal;\r\n        }\r\n\r\n        private void HideMe(object sender, System.EventArgs e)\r\n        {\r\n            //this.WindowState = FormWindowState.Minimized;\r\n            this.TopMost = false;\r\n            this.SendToBack();\r\n            this.Hide();\r\n        }\r\n\r\n        private void NotifyIcon_DoubleClick(object sender, System.EventArgs e)\r\n        {\r\n            ShowMe();\r\n        }\r\n\r\n        private void ToggleVisible(object sender, System.EventArgs e)\r\n        {\r\n            if (this.Visible)\r\n                HideMe(sender, e);\r\n            else\r\n                ShowMe();\r\n        }\r\n\r\n        private void OnClose(object sender, System.EventArgs e)\r\n        {\r\n            m_NotifyIcon.Visible = false;\r\n            m_NotifyIcon.Dispose();\r\n            m_CanClose = true;\r\n            this.Close();\r\n        }\r\n\r\n        private void titlebarImages_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"TitlebarImages\", titlebarImages.Checked);\r\n            Client.Instance.RequestTitlebarUpdate();\r\n        }\r\n\r\n        private void highlightSpellReags_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"HighlightReagents\", highlightSpellReags.Checked);\r\n            Client.Instance.RequestTitlebarUpdate();\r\n        }\r\n\r\n        private void actionStatusMsg_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ActionStatusMsg\", actionStatusMsg.Checked);\r\n        }\r\n\r\n        private void autoStackRes_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoStack\", autoStackRes.Checked);\r\n            //setAutoStackDest.Enabled = autoStackRes.Checked;\r\n        }\r\n\r\n        private void screenPath_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CapPath\", screenPath.Text);\r\n        }\r\n\r\n        private void rememberPwds_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (rememberPwds.Checked && !Config.GetBool(\"RememberPwds\"))\r\n            {\r\n                if (MessageBox.Show(this, Language.GetString(LocString.PWWarn), \"Security Warning\",\r\n                        MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)\r\n                {\r\n                    rememberPwds.Checked = false;\r\n                    return;\r\n                }\r\n            }\r\n\r\n            Config.SetProperty(\"RememberPwds\", rememberPwds.Checked);\r\n        }\r\n\r\n        private void langSel_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            string lang = langSel.SelectedItem as String;\r\n            if (lang != null && lang != Language.Current)\r\n            {\r\n                if (!Language.Load(lang))\r\n                {\r\n                    MessageBox.Show(this, \"Unable to load that language.\", \"Load Error\", MessageBoxButtons.OK,\r\n                        MessageBoxIcon.Exclamation);\r\n                    langSel.SelectedItem = Language.Current;\r\n                }\r\n                else\r\n                {\r\n                    Config.SetAppSetting(\"DefaultLanguage\", Language.Current);\r\n                    Language.LoadControlNames(this);\r\n                    HotKey.RebuildList(hotkeyTree);\r\n                }\r\n            }\r\n        }\r\n\r\n        private void tabs_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)\r\n        {\r\n            //HotKey.KeyDown(e.KeyData);\r\n        }\r\n\r\n        private void MainForm_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)\r\n        {\r\n            //HotKey.KeyDown(e.KeyData);\r\n        }\r\n\r\n        private void spellUnequip_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"SpellUnequip\", spellUnequip.Checked);\r\n        }\r\n\r\n        private void rangeCheckLT_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"RangeCheckLT\", ltRange.Enabled = rangeCheckLT.Checked);\r\n        }\r\n\r\n        private void ltRange_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"LTRange\", Utility.ToInt32(ltRange.Text, 11));\r\n        }\r\n\r\n        private void excludePouches_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"NoSearchPouches\", excludePouches.Checked);\r\n        }\r\n\r\n        private void filterSnoop_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterSnoopMsg\", filterSnoop.Checked);\r\n        }\r\n\r\n        private void preAOSstatbar_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OldStatBar\", preAOSstatbar.Checked);\r\n            Client.Instance.RequestStatbarPatch(preAOSstatbar.Checked);\r\n            if (World.Player != null && !m_Initializing)\r\n                MessageBox.Show(this, \"Close and re-open your status bar for the change to take effect.\",\r\n                    \"Status Window Note\", MessageBoxButtons.OK, MessageBoxIcon.Information);\r\n        }\r\n\r\n        private void smartLT_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"SmartLastTarget\", smartLT.Checked);\r\n        }\r\n\r\n        private void showtargtext_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"LastTargTextFlags\", showtargtext.Checked);\r\n        }\r\n\r\n        private void dressItems_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)\r\n        {\r\n            if (e.KeyCode == Keys.Delete)\r\n            {\r\n                DressList list = (DressList) dressList.SelectedItem;\r\n                if (list == null)\r\n                    return;\r\n\r\n                int sel = dressItems.SelectedIndex;\r\n                if (sel < 0 || sel >= list.Items.Count)\r\n                    return;\r\n\r\n                if (MessageBox.Show(this, Language.GetString(LocString.DelDressItemQ), \"Confirm\",\r\n                        MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n                {\r\n                    try\r\n                    {\r\n                        list.Items.RemoveAt(sel);\r\n                        dressItems.Items.RemoveAt(sel);\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private void blockDis_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"BlockDismount\", blockDis.Checked);\r\n        }\r\n\r\n        private void imgFmt_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (imgFmt.SelectedIndex != -1)\r\n                Config.SetProperty(\"ImageFormat\", imgFmt.SelectedItem);\r\n            else\r\n                Config.SetProperty(\"ImageFormat\", \"jpg\");\r\n        }\r\n\r\n        private void autoFriend_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoFriend\", autoFriend.Checked);\r\n        }\r\n\r\n        private void autoOpenDoors_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoOpenDoors\", autoOpenDoors.Checked);\r\n        }\r\n\r\n        private void msglvl_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"MessageLevel\", msglvl.SelectedIndex);\r\n        }\r\n\r\n        private void screenPrev_Click(object sender, System.EventArgs e)\r\n        {\r\n            string file = screensList.SelectedItem as String;\r\n            if (file != null)\r\n                System.Diagnostics.Process.Start(Path.Combine(Config.GetString(\"CapPath\"), file));\r\n        }\r\n\r\n        private Timer m_ResizeTimer = Timer.DelayedCallback(TimeSpan.FromSeconds(1.0), new TimerCallback(ForceSize));\r\n\r\n        private static void ForceSize()\r\n        {\r\n            int x, y;\r\n\r\n            if (Config.GetBool(\"ForceSizeEnabled\"))\r\n            {\r\n                x = Config.GetInt(\"ForceSizeX\");\r\n                y = Config.GetInt(\"ForceSizeY\");\r\n\r\n                if (x > 100 && x < 2000 && y > 100 && y < 2000)\r\n                    Client.Instance.SetGameSize(x, y);\r\n                else\r\n                    MessageBox.Show(Engine.MainWindow, Language.GetString(LocString.ForceSizeBad), \"Bad Size\",\r\n                        MessageBoxButtons.OK, MessageBoxIcon.Stop);\r\n            }\r\n        }\r\n\r\n        private void gameSize_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ForceSizeEnabled\", gameSize.Checked);\r\n            forceSizeX.Enabled = forceSizeY.Enabled = gameSize.Checked;\r\n\r\n            if (gameSize.Checked)\r\n            {\r\n                int x = Utility.ToInt32(forceSizeX.Text, 800);\r\n                int y = Utility.ToInt32(forceSizeY.Text, 600);\r\n\r\n                if (x < 100 || y < 100 || x > 2000 || y > 2000)\r\n                    MessageBox.Show(this, Language.GetString(LocString.ForceSizeBad), \"Bad Size\", MessageBoxButtons.OK,\r\n                        MessageBoxIcon.Stop);\r\n                else\r\n                    Client.Instance.SetGameSize(x, y);\r\n            }\r\n            else\r\n            {\r\n                Client.Instance.SetGameSize(800, 600);\r\n            }\r\n\r\n            if (!m_Initializing)\r\n                MessageBox.Show(this, Language.GetString(LocString.ApplyOptionsRequired), \"Additional Step\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Information);\r\n        }\r\n\r\n        private void forceSizeX_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            int x = Utility.ToInt32(forceSizeX.Text, 600);\r\n            if (x >= 100 && x <= 2000)\r\n                Config.SetProperty(\"ForceSizeX\", x);\r\n\r\n            if (!m_Initializing)\r\n            {\r\n                if (x > 100 && x < 2000)\r\n                {\r\n                    m_ResizeTimer.Stop();\r\n                    m_ResizeTimer.Start();\r\n                }\r\n            }\r\n        }\r\n\r\n        private void forceSizeY_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            int y = Utility.ToInt32(forceSizeY.Text, 600);\r\n            if (y >= 100 && y <= 2000)\r\n                Config.SetProperty(\"ForceSizeY\", y);\r\n\r\n            if (!m_Initializing)\r\n            {\r\n                if (y > 100 && y < 2000)\r\n                {\r\n                    m_ResizeTimer.Stop();\r\n                    m_ResizeTimer.Start();\r\n                }\r\n            }\r\n        }\r\n\r\n        private void potionEquip_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"PotionEquip\", potionEquip.Checked);\r\n        }\r\n\r\n        private void blockHealPoison_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"BlockHealPoison\", blockHealPoison.Checked);\r\n        }\r\n\r\n        private void negotiate_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (!m_Initializing)\r\n            {\r\n                Config.SetProperty(\"Negotiate\", negotiate.Checked);\r\n                Client.Instance.SetNegotiate(negotiate.Checked);\r\n            }\r\n        }\r\n\r\n        private void wikiLink_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)\r\n        {\r\n            LaunchBrowser(\"https://github.com/msturgill/razor/wiki\");\r\n        }\r\n\r\n        private void homeLink_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)\r\n        {\r\n            LaunchBrowser(\"https://github.com/msturgill/razor/wiki\");\r\n        }\r\n\r\n        private void issuesLink_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)\r\n        {\r\n            LaunchBrowser(\"https://github.com/msturgill/razor/issues\");\r\n        }\r\n\r\n        private void mleLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)\r\n        {\r\n            LaunchBrowser(\"http://www.mlewallpapers.com/\");\r\n        }\r\n\r\n        private void lockBox_Click(object sender, System.EventArgs e)\r\n        {\r\n            MessageBox.Show(this, Language.GetString(LocString.FeatureDisabledText),\r\n                Language.GetString(LocString.FeatureDisabled), MessageBoxButtons.OK, MessageBoxIcon.Stop);\r\n        }\r\n\r\n        private ArrayList m_LockBoxes = new ArrayList();\r\n\r\n        public void LockControl(Control locked)\r\n        {\r\n            if (locked != null)\r\n            {\r\n                if (locked.Parent != null && locked.Parent.Controls != null)\r\n                {\r\n                    try\r\n                    {\r\n                        int y_off = (locked.Size.Height - 16) / 2;\r\n                        int x_off = 0;\r\n                        System.Resources.ResourceManager resources =\r\n                            new System.Resources.ResourceManager(typeof(MainForm));\r\n                        PictureBox newLockBox = new PictureBox();\r\n\r\n                        if (locked is TextBox)\r\n                            x_off += 5;\r\n                        else if (!(locked is CheckBox || locked is RadioButton))\r\n                            x_off = (locked.Size.Width - 16) / 2;\r\n\r\n                        newLockBox.Cursor = System.Windows.Forms.Cursors.Help;\r\n                        //newLockBox.Image = ((System.Drawing.Image)(resources.GetObject(\"lockBox.Image\")));\r\n                        newLockBox.Size = new System.Drawing.Size(16, 16);\r\n                        newLockBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;\r\n                        newLockBox.Click += new System.EventHandler(this.lockBox_Click);\r\n\r\n                        newLockBox.TabIndex = locked.TabIndex;\r\n                        newLockBox.TabStop = locked.TabStop;\r\n                        newLockBox.Location =\r\n                            new System.Drawing.Point(locked.Location.X + x_off, locked.Location.Y + y_off);\r\n                        newLockBox.Name = locked.Name + \"LockBox\";\r\n                        newLockBox.Tag = locked;\r\n                        newLockBox.Visible = true;\r\n\r\n                        locked.Parent.Controls.Add(newLockBox);\r\n                        locked.Parent.Controls.SetChildIndex(newLockBox, 0);\r\n                        m_LockBoxes.Add(newLockBox);\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n\r\n                locked.Enabled = false;\r\n            }\r\n        }\r\n\r\n        public void UnlockControl(Control unlock)\r\n        {\r\n            if (unlock != null)\r\n            {\r\n                for (int i = 0; i < m_LockBoxes.Count; i++)\r\n                {\r\n                    PictureBox box = m_LockBoxes[i] as PictureBox;\r\n                    if (box == null)\r\n                        continue;\r\n\r\n                    if (box.Tag == unlock)\r\n                    {\r\n                        unlock.Enabled = true;\r\n                        if (box.Parent != null && box.Parent.Controls != null)\r\n                            box.Parent.Controls.Remove(box);\r\n\r\n                        m_LockBoxes.RemoveAt(i);\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        public void OnLogout()\r\n        {\r\n            OnMacroStop();\r\n\r\n            features.Visible = false;\r\n\r\n            for (int i = 0; i < m_LockBoxes.Count; i++)\r\n            {\r\n                PictureBox box = m_LockBoxes[i] as PictureBox;\r\n                if (box == null)\r\n                    continue;\r\n\r\n                box.Parent.Controls.Remove(box);\r\n                if (box.Tag is Control)\r\n                    ((Control) box.Tag).Enabled = true;\r\n            }\r\n\r\n            m_LockBoxes.Clear();\r\n        }\r\n\r\n        public void UpdateControlLocks()\r\n        {\r\n            for (int i = 0; i < m_LockBoxes.Count; i++)\r\n            {\r\n                PictureBox box = m_LockBoxes[i] as PictureBox;\r\n                if (box == null)\r\n                    continue;\r\n\r\n                box.Parent.Controls.Remove(box);\r\n                if (box.Tag is Control)\r\n                    ((Control) box.Tag).Enabled = true;\r\n            }\r\n\r\n            m_LockBoxes.Clear();\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.SmartLT))\r\n                LockControl(this.smartLT);\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.RangeCheckLT))\r\n                LockControl(this.rangeCheckLT);\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.AutoOpenDoors))\r\n                LockControl(this.autoOpenDoors);\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.UnequipBeforeCast))\r\n                LockControl(this.spellUnequip);\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.AutoPotionEquip))\r\n                LockControl(this.potionEquip);\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.BlockHealPoisoned))\r\n                LockControl(this.blockHealPoison);\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.LoopingMacros))\r\n                LockControl(this.loopMacro);\r\n\r\n            if (!Client.Instance.AllowBit(FeatureBit.OverheadHealth))\r\n            {\r\n                LockControl(this.showHealthOH);\r\n                LockControl(this.healthFmt);\r\n                LockControl(this.chkPartyOverhead);\r\n            }\r\n        }\r\n\r\n        public Assistant.MapUO.MapWindow MapWindow;\r\n\r\n        [System.Runtime.InteropServices.DllImport(\"user32.dll\")]\r\n        private static extern IntPtr SetParent(IntPtr child, IntPtr newParent);\r\n\r\n        private void btnMap_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                if (MapWindow == null)\r\n                    MapWindow = new MapUO.MapWindow();\r\n\r\n                MapWindow.SafeAction(s =>\r\n                {\r\n                    s.Show();\r\n                    s.BringToFront();\r\n                });\r\n            }\r\n        }\r\n\r\n        private void showHealthOH_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowHealth\", healthFmt.Enabled = showHealthOH.Checked);\r\n        }\r\n\r\n        private void healthFmt_TextChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"HealthFmt\", healthFmt.Text);\r\n        }\r\n\r\n        private void chkPartyOverhead_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowPartyStats\", chkPartyOverhead.Checked);\r\n        }\r\n\r\n        private void btcLabel_Click(object sender, EventArgs e)\r\n        {\r\n        }\r\n\r\n        private void cloneProfile_Click(object sender, EventArgs e)\r\n        {\r\n            if (profiles.SelectedIndex < 0)\r\n                return;\r\n\r\n            string profileToClone = (string) profiles.Items[profiles.SelectedIndex];\r\n\r\n            if (InputBox.Show(this, Language.GetString(LocString.EnterProfileName),\r\n                Language.GetString(LocString.EnterAName)))\r\n            {\r\n                string newProfileName = InputBox.GetString();\r\n                if (string.IsNullOrEmpty(newProfileName) ||\r\n                    newProfileName.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                    newProfileName.IndexOfAny(m_InvalidNameChars) != -1)\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.InvalidChars),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                string newXml = Path.Combine(Config.GetUserDirectory(\"Profiles\"), $\"{newProfileName}.xml\");\r\n\r\n                if (File.Exists(newXml))\r\n                {\r\n                    MessageBox.Show(this, \"A profile with that name exists, try another name.\",\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                File.Copy(Path.Combine(Config.GetUserDirectory(\"Profiles\"), $\"{profileToClone}.xml\"),\r\n                        Path.Combine(Config.GetUserDirectory(\"Profiles\"), $\"{newProfileName}.xml\"));\r\n\r\n                profiles.Items.Add(newProfileName);\r\n            }\r\n        }\r\n\r\n        private void filterHotkeys_TextChanged(object sender, EventArgs e)\r\n        {\r\n            this.hotkeyTree.BeginUpdate();\r\n            this.hotkeyTree.Nodes.Clear();\r\n\r\n            if (this.filterHotkeys.Text != string.Empty)\r\n            {\r\n                foreach (TreeNode _parentNode in _hotkeyTreeViewCache.Nodes) // We won't filter on the top parent domain\r\n                {\r\n                    foreach (TreeNode _childNode in _parentNode.Nodes) // lets not filter on the sub-ones either\r\n                    {\r\n                        foreach (TreeNode _subChildNode in _childNode.Nodes\r\n                        ) // we want all these sub child nodes to be filters\r\n                        {\r\n                            if (_subChildNode.Text.ToLower().Contains(filterHotkeys.Text.ToLower()))\r\n                            {\r\n                                this.hotkeyTree.Nodes.Add((TreeNode) _subChildNode.Clone());\r\n                            }\r\n\r\n                            if (_subChildNode.Nodes.Count > 0) // Just in case\r\n                            {\r\n                                foreach (TreeNode _subSubChildNode in _subChildNode.Nodes)\r\n                                {\r\n                                    if (_subSubChildNode.Text.ToLower().Contains(filterHotkeys.Text.ToLower()))\r\n                                    {\r\n                                        this.hotkeyTree.Nodes.Add((TreeNode) _subSubChildNode.Clone());\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                HotKey.RebuildList(hotkeyTree);\r\n            }\r\n\r\n            //enables redrawing tree after all objects have been added\r\n            this.hotkeyTree.EndUpdate();\r\n        }\r\n\r\n        private void filterMacros_TextChanged(object sender, EventArgs e)\r\n        {\r\n            macroTree.BeginUpdate();\r\n            macroTree.Nodes.Clear();\r\n\r\n            if (filterMacros.Text != string.Empty)\r\n            {\r\n                foreach (TreeNode _parentNode in _macroTreeViewCache.Nodes) // We won't filter on the top parent domain\r\n                {\r\n                    if (_parentNode.Text.ToLower().Contains(filterMacros.Text.ToLower()))\r\n                    {\r\n                        macroTree.Nodes.Add((TreeNode) _parentNode.Clone());\r\n                    }\r\n\r\n                    if (_parentNode.Nodes.Count > 0) // Just in case\r\n                    {\r\n                        foreach (TreeNode _subSubChildNode in _parentNode.Nodes)\r\n                        {\r\n                            if (_subSubChildNode.Text.ToLower().Contains(filterMacros.Text.ToLower()))\r\n                            {\r\n                                this.macroTree.Nodes.Add((TreeNode) _subSubChildNode.Clone());\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            else\r\n            {\r\n                MacroManager.DisplayTo(macroTree);\r\n            }\r\n\r\n            //enables redrawing tree after all objects have been added\r\n            this.macroTree.EndUpdate();\r\n        }\r\n\r\n        private void openRazorDataDir_Click(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                Process.Start(Config.GetUserDirectory());\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                MessageBox.Show(this, ex.Message, \"Unable to open directory\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Warning);\r\n            }\r\n        }\r\n\r\n        private void createBackup_Click(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                string backupTime = $\"{DateTime.Now:yyyyMMdd-HHmmss}\";\r\n                string backupDir = Path.Combine(Config.GetAppSetting<string>(\"BackupPath\"), backupTime);\r\n                ;\r\n\r\n                if (string.IsNullOrEmpty(backupDir))\r\n                    return;\r\n\r\n                if (!Directory.Exists(backupDir))\r\n                {\r\n                    Directory.CreateDirectory(backupDir);\r\n                }\r\n\r\n                // Backup the macros\r\n                Directory.CreateDirectory(Path.Combine(backupDir, \"Macros\"));\r\n\r\n                // Create folders\r\n                var macrosDirectory = Path.Combine(Config.GetUserDirectory(), \"Macros\");\r\n                foreach (string dirPath in Directory.GetDirectories(macrosDirectory, \"*\",\r\n                    SearchOption.AllDirectories))\r\n                {\r\n                    Directory.CreateDirectory(dirPath.Replace(macrosDirectory,\r\n                        Path.Combine(backupDir, \"Macros\")));\r\n                }\r\n\r\n                // Copy macros\r\n                foreach (string newPath in Directory.GetFiles(macrosDirectory, \"*.*\",\r\n                    SearchOption.AllDirectories))\r\n                {\r\n                    File.Copy(newPath,\r\n                        newPath.Replace(macrosDirectory,\r\n                            Path.Combine(backupDir, \"Macros\")), true);\r\n                }\r\n\r\n                Directory.CreateDirectory(Path.Combine(backupDir, \"Scripts\"));\r\n\r\n                // Create folders\r\n                foreach (string dirPath in Directory.GetDirectories(ScriptManager.ScriptPath, \"*\",\r\n                    SearchOption.AllDirectories))\r\n                {\r\n                    Directory.CreateDirectory(dirPath.Replace(ScriptManager.ScriptPath,\r\n                        Path.Combine(backupDir, \"Scripts\")));\r\n                }\r\n\r\n                // Copy macros\r\n                foreach (string newPath in Directory.GetFiles(ScriptManager.ScriptPath, \"*.*\",\r\n                    SearchOption.AllDirectories))\r\n                {\r\n                    File.Copy(newPath,\r\n                        newPath.Replace(ScriptManager.ScriptPath,\r\n                            Path.Combine(backupDir, \"Scripts\")), true);\r\n                }\r\n\r\n                // Backup the profiles\r\n                Directory.CreateDirectory(Path.Combine(backupDir, \"Profiles\"));\r\n                var profilesDirectory = Path.Combine(Config.GetUserDirectory(), \"Profiles\");\r\n\r\n                foreach (string newPath in Directory.GetFiles(profilesDirectory, \"*.*\",\r\n                    SearchOption.AllDirectories))\r\n                {\r\n                    File.Copy(newPath,\r\n                        newPath.Replace(profilesDirectory,\r\n                            Path.Combine(backupDir, \"Profiles\")), true);\r\n                }\r\n\r\n                MessageBox.Show(this, $\"Backup created: {backupDir}\", \"Razor Backup\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Information);\r\n\r\n                Config.SetAppSetting(\"BackupTime\", DateTime.Now.ToString());\r\n                lastBackup.Text = $\"Last Backup: {Config.GetAppSetting<string>(\"BackupTime\")}\";\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                MessageBox.Show(this, ex.Message, \"Unable to create backup\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Warning);\r\n            }\r\n        }\r\n\r\n        private void titleBarParams_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (titleBarParams.SelectedItem.ToString().Contains(\"{\") && titleBarParams.Focused)\r\n            {\r\n                titleStr.AppendText($\" {titleBarParams.SelectedItem} \");\r\n            }\r\n        }\r\n\r\n        private void OnMacroVariableAddTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            TargetInfo t = new TargetInfo\r\n            {\r\n                Gfx = gfx,\r\n                Serial = serial,\r\n                Type = (byte) (ground ? 1 : 0),\r\n                X = pt.X,\r\n                Y = pt.Y,\r\n                Z = pt.Z\r\n            };\r\n\r\n            if (InputBox.Show(this, Language.GetString(LocString.NewMacroVariable),\r\n                Language.GetString(LocString.EnterAName)))\r\n            {\r\n                string name = InputBox.GetString();\r\n\r\n                foreach (MacroVariables.MacroVariable mV in MacroVariables.MacroVariableList\r\n                )\r\n                {\r\n                    if (mV.Name.ToLower().Equals(name.ToLower()))\r\n                    {\r\n                        MessageBox.Show(this, \"Pick a unique Macro Variable name and try again\",\r\n                            \"New Macro Variable\", MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                        return;\r\n                    }\r\n                }\r\n\r\n                MacroVariables.MacroVariableList.Add(\r\n                    new MacroVariables.MacroVariable(name, t));\r\n\r\n                // Save and reload the macros and vars\r\n                MacroManager.DisplayMacroVariables(macroVariables);\r\n            }\r\n\r\n            Engine.MainWindow.ShowMe();\r\n        }\r\n\r\n        private void OnMacroVariableReTarget(bool ground, Serial serial, Point3D pt, ushort gfx)\r\n        {\r\n            TargetInfo t = new TargetInfo\r\n            {\r\n                Gfx = gfx,\r\n                Serial = serial,\r\n                Type = (byte) (ground ? 1 : 0),\r\n                X = pt.X,\r\n                Y = pt.Y,\r\n                Z = pt.Z\r\n            };\r\n\r\n            MacroVariables.MacroVariableList[macroVariables.SelectedIndex].TargetInfo = t;\r\n\r\n            // Save and reload the macros and vars\r\n            MacroManager.DisplayMacroVariables(macroVariables);\r\n\r\n            Engine.MainWindow.ShowMe();\r\n        }\r\n\r\n        private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)\r\n        {\r\n            Utility.LaunchBrowser(\"https://www.razorce.com\");\r\n        }\r\n\r\n        private void targetByTypeDifferent_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DiffTargetByType\", targetByTypeDifferent.Checked);\r\n        }\r\n\r\n        private void stepThroughMacro_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"StepThroughMacro\", stepThroughMacro.Checked);\r\n        }\r\n\r\n        private void nextMacroAction_Click(object sender, EventArgs e)\r\n        {\r\n            /*if (actionList.SelectedIndex + 1 > actionList.Items.Count - 1)\r\n            {\r\n                actionList.SelectedIndex = 0;\r\n            }*/\r\n\r\n            MacroManager.PlayNext();\r\n        }\r\n\r\n        private void disableSmartCPU_Click(object sender, EventArgs e)\r\n        {\r\n            Client.Instance.SetSmartCPU(false);\r\n        }\r\n\r\n        private void lightLevelBar_Scroll(object sender, EventArgs e)\r\n        {\r\n            if (Client.Instance.AllowBit(FeatureBit.LightFilter) && World.Player != null)\r\n            {\r\n                byte selectedLightLevel = Convert.ToByte(lightLevelBar.Maximum - lightLevelBar.Value);\r\n\r\n                World.Player.LocalLightLevel = 0;\r\n                World.Player.GlobalLightLevel = selectedLightLevel;\r\n\r\n                Client.Instance.SendToClient(new GlobalLightLevel(selectedLightLevel));\r\n                Client.Instance.SendToClient(new PersonalLightLevel(World.Player));\r\n\r\n                double percent = Math.Round((lightLevelBar.Value / (double) lightLevelBar.Maximum) * 100.0);\r\n\r\n                lightLevel.Text = $\"Light: {percent}%\";\r\n\r\n                Config.SetProperty(\"LightLevel\", (int) selectedLightLevel);\r\n            }\r\n        }\r\n\r\n        private BoatWindow _boatWindowForm = null;\r\n\r\n        private void boatControl_Click(object sender, EventArgs e)\r\n        {\r\n            if (_boatWindowForm != null)\r\n            {\r\n                _boatWindowForm.Show();\r\n            }\r\n            else\r\n            {\r\n                _boatWindowForm = new BoatWindow();\r\n                _boatWindowForm.Show();\r\n            }\r\n        }\r\n\r\n        private void showTargetMessagesOverChar_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowTargetSelfLastClearOverhead\", showTargetMessagesOverChar.Checked);\r\n        }\r\n\r\n        private void openUOPS_Click(object sender, EventArgs e)\r\n        {\r\n            MessageBox.Show(\"Soon(tm)\");\r\n\r\n            return;\r\n\r\n            /*if (World.Player != null)\r\n            {\r\n                if (MapWindow == null)\r\n                    MapWindow = new Assistant.MapUO.MapWindow();\r\n                //SetParent( MapWindow.Handle, Client.FindUOWindow() );\r\n                //MapWindow.Owner = (Form)Form.FromHandle( Client.FindUOWindow() );\r\n                MapWindow.Show();\r\n                MapWindow.BringToFront();\r\n            }*/\r\n        }\r\n\r\n        private void logSkillChanges_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"LogSkillChanges\", logSkillChanges.Checked);\r\n        }\r\n        \r\n        private void saveProfile_Click(object sender, EventArgs e)\r\n        {\r\n            if (profiles.SelectedIndex < 0)\r\n                return;\r\n\r\n            Config.Save();\r\n            Counter.Save();\r\n\r\n            string profileToClone = (string) profiles.Items[profiles.SelectedIndex];\r\n            MessageBox.Show(SplashScreen.Instance,\r\n                $\"Saved current settings to profile {Path.Combine(Config.GetUserDirectory(\"Profiles\"), $\"{profileToClone}.xml\")}\",\r\n                \"Save Profile\", MessageBoxButtons.OK, MessageBoxIcon.Information);\r\n        }\r\n\r\n        private void stealthOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"StealthOverhead\", stealthOverhead.Checked);\r\n        }\r\n\r\n        private void captureMibs_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CaptureMibs\", captureMibs.Checked);\r\n        }\r\n\r\n        private void trackIncomingGold_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n            {\r\n                GoldPerHourTimer.Stop();\r\n                return;\r\n            }\r\n\r\n            if (trackIncomingGold.Checked)\r\n            {\r\n                GoldPerHourTimer.Start();\r\n            }\r\n            else\r\n            {\r\n                GoldPerHourTimer.Stop();\r\n            }\r\n        }\r\n\r\n        private void objectDelay_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            txtObjDelay.Enabled = objectDelay.Checked;\r\n\r\n            Config.SetProperty(\"ObjectDelayEnabled\", objectDelay.Checked);\r\n        }\r\n\r\n        private void showBuffDebuffOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBuffDebuffOverhead\", showBuffDebuffOverhead.Checked);\r\n        }\r\n\r\n        private void blockOpenCorpsesTwice_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"BlockOpenCorpsesTwice\", blockOpenCorpsesTwice.Checked);\r\n\r\n            if (blockOpenCorpsesTwice.Checked)\r\n            {\r\n                if (World.Player == null)\r\n                    return;\r\n\r\n                World.Player.OpenedCorpses.Clear();\r\n            }\r\n        }\r\n\r\n        private void showAttackTarget_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowAttackTargetOverhead\", showAttackTarget.Checked);\r\n        }\r\n\r\n        private void rangeCheckTargetByType_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"RangeCheckTargetByType\", rangeCheckTargetByType.Checked);\r\n        }\r\n\r\n        private void rangeCheckDoubleClick_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"RangeCheckDoubleClick\", rangeCheckDoubleClick.Checked);\r\n        }\r\n\r\n        private void agentSubList_MouseDown(object sender, MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                ContextMenuStrip menu = new ContextMenuStrip();\r\n                menu.Items.Add(\"Export (Copy to clipboard)\", null, OnAgentExport);\r\n                menu.Items.Add(\"-\");\r\n                menu.Items.Add(\"Import (Copy from clipboard)\", null, OnAgentImport);\r\n\r\n                ToolStripMenuItem submenu = new ToolStripMenuItem(\"Import from profile\");\r\n\r\n                foreach (string profile in Config.GetProfileList())\r\n                {\r\n                    submenu.DropDownItems.Add(profile, null, OnAgentImportFromProfile);\r\n                }\r\n\r\n                menu.Items.Add(submenu);\r\n\r\n                menu.Show(agentSubList, new Point(e.X, e.Y));\r\n            }\r\n\r\n            if (agentList.SelectedIndex < 0 || agentSubList.Items.Count == 0)\r\n                return;\r\n\r\n            if (e.Button == MouseButtons.Left && e.Clicks == 2)\r\n            {\r\n                if (agentList.SelectedIndex < 0)\r\n                    return;\r\n\r\n                Agent a = agentList.SelectedItem as Agent;\r\n\r\n                switch (agentList.SelectedItem)\r\n                {\r\n                    case RestockAgent _:\r\n                        a.OnButtonPress(3);\r\n                        break;\r\n                    case BuyAgent _:\r\n                        a.OnButtonPress(2);\r\n                        break;\r\n                }\r\n            }\r\n        }\r\n\r\n        private void OnAgentExport(object sender, System.EventArgs e)\r\n        {\r\n            if (agentList.SelectedIndex < 0 || agentSubList.Items.Count == 0)\r\n                return;\r\n            \r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            Agent agent = (Agent)agentList.SelectedItem;\r\n\r\n            switch (agent)\r\n            {\r\n                case OrganizerAgent organizerAgent:\r\n                    sb.AppendLine(\"!Razor.Agents.Organizer\");\r\n\r\n                    foreach (ItemID item in agentSubList.Items)\r\n                    {\r\n                        sb.AppendLine(item.Value.ToString());\r\n                    }\r\n\r\n                    break;\r\n                case BuyAgent buyAgent:\r\n                    sb.AppendLine(\"!Razor.Agents.Buy\");\r\n\r\n                    foreach (BuyAgent.BuyEntry entry in agentSubList.Items)\r\n                    {\r\n                        sb.AppendLine($\"{entry.Id},{entry.Amount}\");\r\n                    }\r\n\r\n                    break;\r\n                case RestockAgent restockAgent:\r\n                    sb.AppendLine(\"!Razor.Agents.Restock\");\r\n\r\n                    foreach (RestockAgent.RestockItem entry in agentSubList.Items)\r\n                    {\r\n                        sb.AppendLine($\"{entry.ItemID.Value},{entry.Amount}\");\r\n                    }\r\n\r\n                    break;\r\n                case ScavengerAgent scavAgent:\r\n                    sb.AppendLine(\"!Razor.Agents.Scavenger\");\r\n\r\n                    foreach (ItemID item in agentSubList.Items)\r\n                    {\r\n                        sb.AppendLine(item.Value.ToString());\r\n                    }\r\n\r\n                    break;\r\n                case SellAgent sellAgent:\r\n                    sb.AppendLine(\"!Razor.Agents.Sell\");\r\n\r\n                    foreach (ItemID item in agentSubList.Items)\r\n                    {\r\n                        sb.AppendLine(item.Value.ToString());\r\n                    }\r\n\r\n                    break;\r\n            }\r\n\r\n            Clipboard.SetDataObject(sb.ToString(), true);\r\n        }\r\n\r\n        private void OnAgentImport(object sender, System.EventArgs e)\r\n        {\r\n            if (agentList.SelectedIndex < 0)\r\n                return;\r\n\r\n            Agent agent = (Agent)agentList.SelectedItem;\r\n\r\n            if (!Clipboard.GetText().Contains(\"!Razor.Agents\"))\r\n            {\r\n                return;\r\n            }\r\n\r\n            List<string> items = Clipboard.GetText()\r\n                .Split(new[] { \"\\r\\n\", \"\\r\", \"\\n\" }, StringSplitOptions.None).ToList();\r\n\r\n            if (agent is OrganizerAgent organizerAgent && Clipboard.GetText().Contains(\"!Razor.Agents.Organizer\"))\r\n            {\r\n                items.RemoveAt(0);\r\n\r\n                foreach (string item in items)\r\n                {\r\n                    if (!string.IsNullOrEmpty(item) && ushort.TryParse(item, out ushort gfx))\r\n                    {\r\n                        organizerAgent.AddItem(gfx);\r\n                    }\r\n                }\r\n            }\r\n            else if (agent is BuyAgent buyAgent && Clipboard.GetText().Contains(\"!Razor.Agents.Buy\"))\r\n            {\r\n                items.RemoveAt(0);\r\n\r\n                foreach (string item in items)\r\n                {\r\n                    string[] split = item.Split(',');\r\n\r\n                    if (!string.IsNullOrEmpty(item) && ushort.TryParse(split[0], out ushort id) && ushort.TryParse(split[1], out ushort amount))\r\n                    {\r\n                        buyAgent.AddItem(new BuyAgent.BuyEntry(id, amount));\r\n                    }\r\n                }\r\n            }\r\n            else if (agent is RestockAgent restockAgent && Clipboard.GetText().Contains(\"!Razor.Agents.Restock\"))\r\n            {\r\n                items.RemoveAt(0);\r\n\r\n                foreach (string item in items)\r\n                {\r\n                    string[] split = item.Split(',');\r\n\r\n                    if (!string.IsNullOrEmpty(item) && ushort.TryParse(split[0], out ushort id) && ushort.TryParse(split[1], out ushort amount))\r\n                    {\r\n                        restockAgent.AddItem(new RestockAgent.RestockItem(id, amount));\r\n                    }\r\n                }\r\n            }\r\n            else if (agent is ScavengerAgent scavengerAgent && Clipboard.GetText().Contains(\"!Razor.Agents.Scavenger\"))\r\n            {\r\n                items.RemoveAt(0);\r\n\r\n                foreach (string item in items)\r\n                {\r\n                    if (!string.IsNullOrEmpty(item) && ushort.TryParse(item, out ushort gfx))\r\n                    {\r\n                        scavengerAgent.Add(gfx);\r\n                    }\r\n                }\r\n            }\r\n            else if (agent is SellAgent sellAgent && Clipboard.GetText().Contains(\"!Razor.Agents.Sell\"))\r\n            {\r\n                items.RemoveAt(0);\r\n\r\n                foreach (string item in items)\r\n                {\r\n                    if (!string.IsNullOrEmpty(item) && ushort.TryParse(item, out ushort gfx))\r\n                    {\r\n                        sellAgent.Add(gfx);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private void OnAgentImportFromProfile(object sender, System.EventArgs e)\r\n        {\r\n            if (agentList.SelectedIndex < 0)\r\n                return;\r\n\r\n            Agent agent = (Agent)agentList.SelectedItem;\r\n\r\n            string file = Path.Combine(Config.GetUserDirectory(\"Profiles\"), $\"{sender}.xml\");\r\n            if (!File.Exists(file))\r\n                return;\r\n\r\n            XmlDocument doc = new XmlDocument();\r\n            doc.Load(file);\r\n\r\n            XmlElement root = doc[\"profile\"];\r\n            if (root == null)\r\n                return;\r\n\r\n            switch (agent)\r\n            {\r\n                case OrganizerAgent organizerAgent:\r\n\r\n                    try\r\n                    {\r\n                        foreach (XmlElement el in root.GetElementsByTagName(\"item\"))\r\n                        {\r\n                            try\r\n                            {\r\n                                string gfx = el.GetAttribute(\"id\");\r\n                                organizerAgent.AddItem(Convert.ToUInt16(gfx));\r\n                            }\r\n                            catch\r\n                            {\r\n                                // ignored\r\n                            }\r\n                        }\r\n                    }\r\n                    catch\r\n                    {\r\n                        // ignored\r\n                    }\r\n\r\n                    break;\r\n                case BuyAgent buyAgent:\r\n                    try\r\n                    {\r\n                        foreach (XmlElement el in root.GetElementsByTagName(\"item\"))\r\n                        {\r\n                            try\r\n                            {\r\n                                string gfx = el.GetAttribute(\"id\");\r\n                                string amount = el.GetAttribute(\"amount\");\r\n\r\n                                BuyAgent.BuyEntry entry = new BuyAgent.BuyEntry(Convert.ToUInt16(gfx), Convert.ToUInt16(amount));\r\n\r\n                                buyAgent.AddItem(entry);\r\n                            }\r\n                            catch\r\n                            {\r\n                                // ignored\r\n                            }\r\n                        }\r\n                    }\r\n                    catch\r\n                    {\r\n                        // ignored\r\n                    }\r\n\r\n                    break;\r\n                case RestockAgent restockAgent:\r\n\r\n                    foreach (XmlElement el in root.GetElementsByTagName(\"item\"))\r\n                    {\r\n                        try\r\n                        {\r\n                            string gfx = el.GetAttribute(\"id\");\r\n                            string amount = el.GetAttribute(\"amount\");\r\n\r\n                            RestockAgent.RestockItem entry = new RestockAgent.RestockItem(Convert.ToUInt16(gfx), Convert.ToUInt16(amount));\r\n\r\n                            restockAgent.AddItem(entry);\r\n                        }\r\n                        catch\r\n                        {\r\n                            // ignored\r\n                        }\r\n                    }\r\n\r\n                    break;\r\n                case ScavengerAgent scavAgent:\r\n                    try\r\n                    {\r\n                        foreach (XmlElement el in root.GetElementsByTagName(\"item\"))\r\n                        {\r\n                            try\r\n                            {\r\n                                string gfx = el.GetAttribute(\"id\");\r\n                                scavAgent.Add(Convert.ToUInt16(gfx));\r\n                            }\r\n                            catch\r\n                            {\r\n                                // ignored\r\n                            }\r\n                        }\r\n                    }\r\n                    catch\r\n                    {\r\n                        // ignored\r\n                    }\r\n\r\n                    break;\r\n                case SellAgent sellAgent:\r\n                    try\r\n                    {\r\n                        foreach (XmlElement el in root.GetElementsByTagName(\"item\"))\r\n                        {\r\n                            try\r\n                            {\r\n                                string gfx = el.GetAttribute(\"id\");\r\n                                sellAgent.Add(Convert.ToUInt16(gfx));\r\n                            }\r\n                            catch\r\n                            {\r\n                                // ignored\r\n                            }\r\n                        }\r\n                    }\r\n                    catch\r\n                    {\r\n                        // ignored\r\n                    }\r\n\r\n                    break;\r\n            }\r\n        }\r\n\r\n        private void showContainerLabels_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowContainerLabels\", showContainerLabels.Checked);\r\n\r\n            containerLabels.Enabled = showContainerLabels.Checked;\r\n        }\r\n\r\n        private ContainerLabels _containerLabelsForm = null;\r\n\r\n        private void containerLabels_Click(object sender, EventArgs e)\r\n        {\r\n            if (_containerLabelsForm != null)\r\n            {\r\n                _containerLabelsForm.Show();\r\n            }\r\n            else\r\n            {\r\n                _containerLabelsForm = new ContainerLabels();\r\n                _containerLabelsForm.Show();\r\n            }\r\n        }\r\n\r\n        private void seasonList_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            //Season Flag:\r\n            //0: Spring\r\n            //1: Summer\r\n            //2: Fall\r\n            //3: Winter\r\n            //4: Desolation\r\n            //Default server\r\n\r\n            if (seasonList.SelectedIndex < 0)\r\n                return;\r\n\r\n            Config.SetProperty(\"Season\", seasonList.SelectedIndex);\r\n\r\n            if (seasonList.SelectedIndex < 5)\r\n            {\r\n                Client.Instance.ForceSendToClient(new SeasonChange(seasonList.SelectedIndex, true));\r\n            }\r\n        }\r\n\r\n        private void blockPartyInvites_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"BlockPartyInvites\", blockPartyInvites.Checked);\r\n        }\r\n\r\n        private void blockTradeRequests_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"BlockTradeRequests\", blockTradeRequests.Checked);\r\n        }\r\n\r\n        private void autoAcceptParty_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoAcceptParty\", autoAcceptParty.Checked);\r\n        }\r\n\r\n        private void setMaxLightLevel_Click(object sender, EventArgs e)\r\n        {\r\n            int lightLevel = lightLevelBar.Maximum - lightLevelBar.Value;\r\n\r\n            if (lightLevel > Config.GetInt(\"MinLightLevel\"))\r\n            {\r\n                MessageBox.Show(this,\r\n                    $\"Selected maximum light level {lightLevel} exceeds minimum light level {Config.GetInt(\"MinLightLevel\")}\",\r\n                    \"Set Max Light Level\", MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n            }\r\n            else\r\n            {\r\n                Config.SetProperty(\"MaxLightLevel\", lightLevel);\r\n            }\r\n        }\r\n\r\n        private void setMinLightLevel_Click(object sender, EventArgs e)\r\n        {\r\n            int lightLevel = lightLevelBar.Maximum - lightLevelBar.Value;\r\n\r\n            if (lightLevel < Config.GetInt(\"MaxLightLevel\"))\r\n            {\r\n                MessageBox.Show(this,\r\n                    $\"Selected minimum light level {lightLevel} exceeds maximum light level {Config.GetInt(\"MaxLightLevel\")}\",\r\n                    \"Set Min Light Level\", MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n            }\r\n            else\r\n            {\r\n                Config.SetProperty(\"MinLightLevel\", lightLevel);\r\n            }\r\n        }\r\n\r\n        private void minMaxLightLevel_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"MinMaxLightLevelEnabled\", minMaxLightLevel.Checked);\r\n        }\r\n\r\n        private void showStaticWalls_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowStaticWalls\", showStaticWalls.Checked);\r\n        }\r\n\r\n        private void showStaticWallLabels_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowStaticWallLabels\", showStaticWallLabels.Checked);\r\n        }\r\n\r\n        private void showTextTargetIndicator_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowTextTargetIndicator\", showTextTargetIndicator.Checked);\r\n        }\r\n\r\n        private void showAttackTargetNewOnly_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowAttackTargetNewOnly\", showAttackTargetNewOnly.Checked);\r\n        }\r\n\r\n        private void addMacroVariable_Click(object sender, EventArgs e)\r\n        {\r\n            if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            //switch (macroVariableTypeList.SelectedIndex)\r\n            //{\r\n            //    case 0:\r\n            Targeting.OneTimeTarget(OnMacroVariableAddTarget);\r\n            //        break;\r\n            //    case 1:\r\n            //        Targeting.OneTimeTarget(OnDoubleClickAddTarget);\r\n            //        break;\r\n            //}\r\n\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void insertMacroVariable_Click(object sender, EventArgs e)\r\n        {\r\n            if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            Macro m = GetMacroSel();\r\n\r\n            if (m == null)\r\n                return;\r\n\r\n            int a = actionList.SelectedIndex;\r\n\r\n            if (macroVariables.SelectedIndex < 0)\r\n            {\r\n                return;\r\n            }\r\n\r\n            string[] macroVariableName = {MacroVariables.MacroVariableList[macroVariables.SelectedIndex].Name};\r\n\r\n            switch (macroVariableTypeList.SelectedIndex)\r\n            {\r\n                case 0:\r\n                    m.Actions.Insert(a + 1, new AbsoluteTargetVariableAction(macroVariableName));\r\n                    break;\r\n                case 1:\r\n                    m.Actions.Insert(a + 1, new DoubleClickVariableAction(macroVariableName));\r\n                    break;\r\n                case 2:\r\n                    m.Actions.Insert(a + 1, new SetMacroVariableTargetAction(macroVariableName));\r\n                    break;\r\n            }\r\n\r\n            RedrawActionList(m);\r\n        }\r\n\r\n        private void retargetMacroVariable_Click(object sender, EventArgs e)\r\n        {\r\n            if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            if (macroVariables.SelectedIndex < 0)\r\n                return;\r\n\r\n            Targeting.OneTimeTarget(OnMacroVariableReTarget);\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void removeMacroVariable_Click(object sender, EventArgs e)\r\n        {\r\n            if (MacroManager.Playing || MacroManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            if (macroVariables.SelectedIndex < 0)\r\n                return;\r\n\r\n            MacroVariables.MacroVariableList.RemoveAt(macroVariables.SelectedIndex);\r\n\r\n            // Save and reload the macros and vars\r\n            MacroManager.Save();\r\n            MacroManager.DisplayMacroVariables(macroVariables);\r\n        }\r\n\r\n        private void macroVariableTypeList_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            //MacroManager.DisplayMacroVariables(macroVariables);\r\n        }\r\n\r\n        private void filterDragonGraphics_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterDragonGraphics\", filterDragonGraphics.Checked);\r\n\r\n            if (filterDragonGraphics.Checked)\r\n            {\r\n                MobileFilter.ApplyToMobiles();\r\n            }\r\n        }\r\n\r\n        private void dragonAnimationList_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                if (dragonAnimationList.SelectedIndex < 0)\r\n                    return;\r\n\r\n                Config.SetProperty(\"DragonGraphic\", _animationData[dragonAnimationList.SelectedIndex].BodyId);\r\n\r\n                MobileFilter.Load();\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, \"Unable to find animation in file\", \"Animation Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void drakeAnimationList_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                if (drakeAnimationList.SelectedIndex < 0)\r\n                    return;\r\n\r\n                Config.SetProperty(\"DrakeGraphic\", _animationData[drakeAnimationList.SelectedIndex].BodyId);\r\n\r\n                MobileFilter.Load();\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, \"Unable to find animation in file\", \"Animation Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void trackDps_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            if (trackDps.Checked)\r\n            {\r\n                DamageTracker.Start();\r\n            }\r\n            else\r\n            {\r\n                DamageTracker.Stop();\r\n            }\r\n        }\r\n\r\n        private void showDamageDealt_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowDamageDealt\", showDamageDealt.Checked);\r\n        }\r\n\r\n        private void damageDealtOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowDamageDealtOverhead\", damageDealtOverhead.Checked);\r\n        }\r\n\r\n        private void damageTakenOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowDamageTakenOverhead\", damageTakenOverhead.Checked);\r\n        }\r\n\r\n        private void showDamageTaken_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowDamageTaken\", showDamageTaken.Checked);\r\n        }\r\n\r\n        private void filterDrakeGraphics_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterDrakeGraphics\", filterDrakeGraphics.Checked);\r\n\r\n            if (filterDrakeGraphics.Checked)\r\n            {\r\n                MobileFilter.ApplyToMobiles();\r\n            }\r\n        }\r\n\r\n        private void showInRazorTitleBar_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowInRazorTitleBar\", showInRazorTitleBar.Checked);\r\n\r\n            UpdateTitle();\r\n        }\r\n\r\n        private void razorTitleBar_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"RazorTitleBarText\", razorTitleBar.Text.TrimEnd());\r\n            if (Config.GetBool(\"ShowInRazorTitleBar\"))\r\n                UpdateTitle();\r\n        }\r\n\r\n        private void razorTitleBarKey_Click(object sender, EventArgs e)\r\n        {\r\n            //Replace(\"{name}\", World.Player.Name).Replace(\"{shard}\", World.ShardName)\r\n            //.Replace(\"{version}\", Engine.Version).Replace(\"{profile}\", Config.CurrentProfile.Name).Replace(\"{account}\", World.AccountName);\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n            sb.AppendLine(\"You can insert these variables into the Razor Title Bar to display specific information.\");\r\n            sb.AppendLine(string.Empty);\r\n            sb.AppendLine(\"{name} - Character name\");\r\n            sb.AppendLine(\"{shard} - Shard/Server name\");\r\n            sb.AppendLine(\"{version} - Razor version\");\r\n            sb.AppendLine(\"{profile} - Selected profile name\");\r\n            sb.AppendLine(\"{account} - Account name\");\r\n\r\n            MessageBox.Show(this, sb.ToString(), \"Razor Title Bar Variables\", MessageBoxButtons.OK,\r\n                MessageBoxIcon.Information);\r\n        }\r\n\r\n        private void linkHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)\r\n        {\r\n            Utility.LaunchBrowser(\"https://www.razorce.com/help/\");\r\n        }\r\n\r\n        private void enableUOAAPI_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"EnableUOAAPI\", enableUOAAPI.Checked);\r\n        }\r\n\r\n        private void setBackupFolder_Click(object sender, EventArgs e)\r\n        {\r\n            //Config.SetAppSetting(\"UODataDir\", dataDir.Text);\r\n\r\n            FolderBrowserDialog folder = new FolderBrowserDialog();\r\n            folder.Description = \"Select Backup Folder\";\r\n            folder.SelectedPath = Config.GetAppSetting<string>(\"BackupPath\");\r\n            folder.ShowNewFolderButton = true;\r\n\r\n            if (folder.ShowDialog(this) == DialogResult.OK)\r\n            {\r\n                Config.SetAppSetting(\"BackupPath\", folder.SelectedPath);\r\n            }\r\n        }\r\n\r\n        private void openBackupFolder_Click(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                Process.Start(Config.GetAppSetting<string>(\"BackupPath\"));\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private void targetIndicatorFormat_TextChanged(object sender, EventArgs e)\r\n        {\r\n            if (string.IsNullOrEmpty(targetIndicatorFormat.Text))\r\n            {\r\n                Config.SetProperty(\"TargetIndicatorFormat\", \"* Target *\");\r\n                targetIndicatorFormat.Text = \"* Target *\";\r\n            }\r\n\r\n            Config.SetProperty(\"TargetIndicatorFormat\", targetIndicatorFormat.Text);\r\n        }\r\n\r\n        private void nextPrevIgnoresFriends_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"NextPrevTargetIgnoresFriends\", nextPrevIgnoresFriends.Checked);\r\n        }\r\n\r\n        private void stealthStepsFormat_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"StealthStepsFormat\", stealthStepsFormat.Text);\r\n        }\r\n\r\n        private void showFriendOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            FriendsManager.SetOverheadFormatEnabled((FriendsManager.FriendGroup)friendsGroup.SelectedItem,\r\n                showFriendOverhead.Checked);\r\n        }\r\n\r\n        private void dispDeltaOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DisplaySkillChangesOverhead\", dispDeltaOverhead.Checked);\r\n        }\r\n\r\n        private void linkGitHub_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)\r\n        {\r\n            Utility.LaunchBrowser(\"https://github.com/markdwags/Razor\");\r\n        }\r\n\r\n        /// <summary>\r\n        /// Quickly disable UI elements not used when ClassicUO is the client\r\n        /// </summary>\r\n        public void DisableCUOFeatures()\r\n        {\r\n            forceSizeX.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Text = \"0\";\r\n            });\r\n\r\n            forceSizeY.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Text = \"0\";\r\n            });\r\n\r\n            gameSize.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Checked = false;\r\n            });\r\n\r\n            rememberPwds.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Checked = false;\r\n            });\r\n\r\n            highlightSpellReags.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Checked = false;\r\n            });\r\n\r\n            showNotoHue.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Checked = false;\r\n            });\r\n\r\n            titlebarImages.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Checked = false;\r\n            });\r\n\r\n            showWelcome.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Checked = false;\r\n            });\r\n\r\n            showHealthOH.SafeAction(s =>\r\n            {\r\n                s.Enabled = false;\r\n                s.Checked = false;\r\n            });\r\n\r\n            healthFmt.SafeAction(s => { s.Enabled = false; });\r\n        }\r\n\r\n        private void macroActionDelay_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"MacroActionDelay\", macroActionDelay.Checked);\r\n\r\n            if (m_Initializing)\r\n                return;\r\n\r\n            MessageBox.Show(this, Language.GetString(LocString.NextRestart), \"Notice\", MessageBoxButtons.OK,\r\n                MessageBoxIcon.Information);\r\n        }\r\n\r\n        private void autoDoorWhenHidden_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoOpenDoorWhenHidden\", autoOpenDoorWhenHidden.Checked);\r\n        }\r\n\r\n        private void disableMacroPlayFinish_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DisableMacroPlayFinish\", disableMacroPlayFinish.Checked);\r\n        }\r\n\r\n        private void showBandageTimer_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBandageTimer\", showBandageTimer.Checked);\r\n        }\r\n\r\n        private void bandageTimerLocation_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBandageTimerLocation\", bandageTimerLocation.SelectedIndex);\r\n        }\r\n\r\n        private void onlyShowBandageTimerSeconds_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OnlyShowBandageTimerEvery\", onlyShowBandageTimerSeconds.Checked);\r\n        }\r\n\r\n        private void bandageTimerSeconds_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OnlyShowBandageTimerSeconds\", Utility.ToInt32(bandageTimerSeconds.Text.Trim(), 1));\r\n        }\r\n\r\n        private void bandageTimerFormat_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBandageTimerFormat\", bandageTimerFormat.Text);\r\n\r\n            if (string.IsNullOrEmpty(bandageTimerFormat.Text))\r\n            {\r\n                Config.SetProperty(\"ShowBandageTimerFormat\", \"Bandage: {count}s\");\r\n                bandageTimerFormat.Text = \"Bandage: {count}s\";\r\n            }\r\n\r\n            Config.SetProperty(\"ShowBandageTimerFormat\", bandageTimerFormat.Text);\r\n        }\r\n\r\n        private void setBandageHue_Click(object sender, EventArgs e)\r\n        {\r\n            lblBandageCountFormat.SafeAction(s => { SetHue(s, \"ShowBandageTimerHue\"); });\r\n        }\r\n\r\n        private void friendRemoveSelected_Click(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0 || friendsList.SelectedIndex < 0)\r\n                return;\r\n\r\n            FriendsManager.RemoveFriend((FriendsManager.FriendGroup) friendsGroup.SelectedItem,\r\n                friendsList.SelectedIndex);\r\n        }\r\n\r\n        private void friendsGroupAdd_Click(object sender, EventArgs e)\r\n        {\r\n            if (InputBox.Show(this, \"Add Friend Group\", \"Enter the name of this new Friend Group\"))\r\n            {\r\n                string name = InputBox.GetString();\r\n\r\n                if (!string.IsNullOrEmpty(name) && !FriendsManager.FriendsGroupExists(name))\r\n                {\r\n                    FriendsManager.AddFriendGroup(name);\r\n                }\r\n                else\r\n                {\r\n                    MessageBox.Show(this, \"Invalid name, or friends group already exists\", \"Error\",\r\n                        MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                }\r\n            }\r\n        }\r\n\r\n        private void friendsGroupRemove_Click(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (MessageBox.Show(this, Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                if (FriendsManager.DeleteFriendGroup((FriendsManager.FriendGroup) friendsGroup.SelectedItem))\r\n                {\r\n                    FriendsManager.RedrawGroup();\r\n\r\n                    if (friendsGroup.Items.Count > 0)\r\n                    {\r\n                        friendsGroup.SafeAction(s => s.SelectedIndex = 0);\r\n                    }\r\n                    else\r\n                    {\r\n                        friendsList.SafeAction(s => s.Items.Clear());\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private void friendsGroup_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            var friendGroup = (FriendsManager.FriendGroup) friendsGroup.SelectedItem;\r\n\r\n            friendsListEnabled.SafeAction(s => s.Checked = friendGroup.Enabled);\r\n\r\n            friendFormat.SafeAction(s =>\r\n            {\r\n                int hueIdx = friendGroup.OverheadFormatHue;\r\n\r\n                if (hueIdx > 0 && hueIdx < 3000)\r\n                    s.BackColor = Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\r\n                else\r\n                    s.BackColor = SystemColors.Control;\r\n\r\n                s.ForeColor = (s.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\r\n            });\r\n\r\n            friendOverheadFormat.SafeAction(s => s.Text = friendGroup.OverheadFormat);\r\n            showFriendOverhead.SafeAction(s => s.Checked = friendGroup.OverheadFormatEnabled);\r\n\r\n            FriendsManager.RedrawList(friendGroup);\r\n        }\r\n\r\n        private void friendClearList_Click(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (MessageBox.Show(this, Language.GetString(LocString.Confirm), Language.GetString(LocString.ClearList),\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                FriendsManager.FriendGroup friendGroup = (FriendsManager.FriendGroup) friendsGroup.SelectedItem;\r\n                friendGroup.Friends.Clear();\r\n\r\n                FriendsManager.RedrawList(friendGroup);\r\n            }\r\n        }\r\n\r\n        private void friendsListEnabled_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            FriendsManager.EnableFriendsGroup((FriendsManager.FriendGroup) friendsGroup.SelectedItem,\r\n                friendsListEnabled.Checked);\r\n        }\r\n\r\n        private void friendOverheadFormat_TextChanged(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            //FriendOverheadFormat\r\n            if (string.IsNullOrEmpty(friendOverheadFormat.Text))\r\n            {\r\n                targetIndicatorFormat.SafeAction(s => s.Text = \"[Friend]\");\r\n            }\r\n\r\n            friendOverheadFormat.SafeAction(s => FriendsManager.SetOverheadFormat((FriendsManager.FriendGroup)friendsGroup.SelectedItem,\r\n                s.Text));\r\n        }\r\n\r\n        private void setFriendsFormatHue_Click(object sender, EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            friendFormat.SafeAction(s =>\r\n            {\r\n                FriendsManager.FriendGroup group = (FriendsManager.FriendGroup) friendsGroup.SelectedItem;\r\n\r\n                HueEntry h = new HueEntry(group.OverheadFormatHue);\r\n\r\n                if (h.ShowDialog(this) == DialogResult.OK)\r\n                {\r\n                    int hueIdx = h.Hue;\r\n                    \r\n                    if (hueIdx > 0 && hueIdx < 3000)\r\n                        s.BackColor = Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX);\r\n                    else\r\n                        s.BackColor = Color.White;\r\n\r\n                    s.ForeColor = (s.BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\r\n\r\n                    FriendsManager.SetOverheadHue((FriendsManager.FriendGroup)friendsGroup.SelectedItem,\r\n                        hueIdx);\r\n                }\r\n            });\r\n        }\r\n\r\n        private void friendAddTarget_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            if ((e.Button & MouseButtons.Right) != 0)\r\n            {\r\n                ContextMenuStrip menu = new ContextMenuStrip();\r\n                menu.Items.Add(Language.GetString(LocString.AddAllMobileFriends), null,\r\n                    onAddAllMobilesAsFriends);\r\n                menu.Items.Add(Language.GetString(LocString.AddAllHumanoidsAsFriends), null,\r\n                    onAddAllHumanoidsAsFriends);\r\n\r\n                menu.Show(friendAddTarget, new Point(e.X, e.Y));\r\n            }\r\n            else\r\n            {\r\n                FriendsManager.OnTargetAddFriend((FriendsManager.FriendGroup) friendsGroup.SelectedItem);\r\n            }\r\n        }\r\n\r\n        private void onAddAllMobilesAsFriends(object sender, System.EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            FriendsManager.FriendGroup friendGroup = (FriendsManager.FriendGroup) friendsGroup.SelectedItem;\r\n            friendGroup.AddAllMobileAsFriends();\r\n        }\r\n\r\n        private void onAddAllHumanoidsAsFriends(object sender, System.EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            FriendsManager.FriendGroup friendGroup = (FriendsManager.FriendGroup) friendsGroup.SelectedItem;\r\n            friendGroup.AddAllHumanoidsAsFriends();\r\n        }\r\n\r\n        private void friendsList_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)\r\n        {\r\n            if (e.KeyCode == Keys.Delete)\r\n            {\r\n                if (friendsList.SelectedIndex < 0 || friendsGroup.SelectedIndex < 0)\r\n                    return;\r\n\r\n                FriendsManager.RemoveFriend((FriendsManager.FriendGroup) friendsGroup.SelectedItem,\r\n                    friendsList.SelectedIndex);\r\n            }\r\n        }\r\n\r\n        private void friendsList_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (e.Button == MouseButtons.Right)\r\n            {\r\n                ContextMenuStrip menu = new ContextMenuStrip();\r\n                menu.Items.Add(\"Import 'Friends' from clipboard\", null, onImportFriends);\r\n                menu.Items.Add(\"Export 'Friends' to clipboard\", null, onExportFriends);\r\n\r\n                menu.Show(friendsList, new Point(e.X, e.Y));\r\n            }\r\n        }\r\n\r\n        private void onImportFriends(object sender, System.EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            try\r\n            {\r\n                if (Clipboard.GetText().Contains(\"!Razor.Friends.Import\"))\r\n                {\r\n                    List<string> friendsImport = Clipboard.GetText()\r\n                        .Split(new[] {\"\\r\\n\", \"\\r\", \"\\n\"}, StringSplitOptions.None).ToList();\r\n\r\n                    friendsImport.RemoveAt(0);\r\n\r\n                    foreach (string import in friendsImport)\r\n                    {\r\n                        if (string.IsNullOrEmpty(import))\r\n                            continue;\r\n\r\n                        string[] friend = import.Split('#');\r\n\r\n                        FriendsManager.FriendGroup friendGroup = (FriendsManager.FriendGroup) friendsGroup.SelectedItem;\r\n\r\n                        friendGroup.AddFriend(friend[0], Serial.Parse(friend[1]));\r\n                    }\r\n\r\n                    Clipboard.Clear();\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private void onExportFriends(object sender, System.EventArgs e)\r\n        {\r\n            if (friendsGroup.SelectedIndex < 0 || friendsList.Items.Count == 0)\r\n                return;\r\n\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            sb.AppendLine(\"!Razor.Friends.Import\");\r\n\r\n\r\n            FriendsManager.FriendGroup friendGroup = (FriendsManager.FriendGroup) friendsGroup.SelectedItem;\r\n\r\n            foreach (FriendsManager.Friend friend in friendGroup.Friends)\r\n            {\r\n                sb.AppendLine($\"{friend.Name}#{friend.Serial}\");\r\n            }\r\n\r\n\r\n            Clipboard.SetDataObject(sb.ToString(), true);\r\n        }\r\n\r\n        private void setTargetIndicatorHue_Click(object sender, EventArgs e)\r\n        {\r\n            lblTargetFormat.SafeAction(s => { SetHue(s, \"TargetIndicatorHue\"); });\r\n        }\r\n\r\n        private void filterSystemMessages_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterSystemMessages\", filterSystemMessages.Checked);\r\n        }\r\n\r\n        private void filterRazorMessages_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterRazorMessages\", filterRazorMessages.Checked);\r\n        }\r\n\r\n        private void filterDelaySeconds_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterDelay\", Utility.ToDouble(filterDelaySeconds.Text.Trim(), 3.5));\r\n\r\n            if (Config.GetDouble(\"FilterDelay\") < 0 || Config.GetDouble(\"FilterDelay\") > 20)\r\n            {\r\n                Config.SetProperty(\"FilterDelay\", 3.5);\r\n                filterDelaySeconds.SafeAction(s => s.Text = \"3.5\");\r\n            }\r\n        }\r\n\r\n        private void filterOverheadMessages_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterOverheadMessages\", filterOverheadMessages.Checked);\r\n        }\r\n\r\n        private void onlyNextPrevBeneficial_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OnlyNextPrevBeneficial\", onlyNextPrevBeneficial.Checked);\r\n        }\r\n\r\n        private void friendBeneficialOnly_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FriendlyBeneficialOnly\", friendBeneficialOnly.Checked);\r\n        }\r\n\r\n        private void nonFriendlyHarmfulOnly_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"NonFriendlyHarmfulOnly\", nonFriendlyHarmfulOnly.Checked);\r\n        }\r\n\r\n        private void ShowBandageStart_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBandageStart\", showBandageStart.Checked);\r\n        }\r\n\r\n        private void ShowBandageEnd_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBandageEnd\", showBandageEnd.Checked);\r\n        }\r\n\r\n        private void BandageStartMessage_TextChanged(object sender, EventArgs e)\r\n        {\r\n            if (string.IsNullOrEmpty(bandageStartMessage.Text))\r\n            {\r\n                Config.SetProperty(\"BandageStartMessage\", \"Bandage: Starting\");\r\n                bandageStartMessage.SafeAction(s => s.Text = \"Bandage: Starting\");\r\n            }\r\n\r\n            Config.SetProperty(\"BandageStartMessage\", bandageStartMessage.Text);\r\n        }\r\n\r\n        private void BandageEndMessage_TextChanged(object sender, EventArgs e)\r\n        {\r\n            if (string.IsNullOrEmpty(bandageEndMessage.Text))\r\n            {\r\n                Config.SetProperty(\"BandageEndMessage\", \"Bandage: Ending\");\r\n                bandageEndMessage.SafeAction(s => s.Text = \"Bandage: Ending\");\r\n            }\r\n\r\n            Config.SetProperty(\"BandageEndMessage\", bandageEndMessage.Text);\r\n        }\r\n\r\n        private BuffDebuffOptions _buffDebuffOptions = null;\r\n\r\n        private void buffDebuffOptions_Click(object sender, EventArgs e)\r\n        {\r\n            if (_buffDebuffOptions != null)\r\n            {\r\n                _buffDebuffOptions.SafeAction(s => s.Show());\r\n            }\r\n            else\r\n            {\r\n                _buffDebuffOptions = new BuffDebuffOptions();\r\n\r\n                _buffDebuffOptions.SafeAction(s => s.Show());\r\n            }\r\n        }\r\n\r\n        private void CaptureOthersDeathDelay_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CaptureOthersDeathDelay\", Utility.ToDouble(captureOthersDeathDelay.Text.Trim(), 0.5));\r\n\r\n            if (Config.GetDouble(\"CaptureOthersDeathDelay\") < 0 || Config.GetDouble(\"CaptureOthersDeathDelay\") > 5)\r\n            {\r\n                Config.SetProperty(\"CaptureOthersDeathDelay\", 0.5);\r\n                captureOthersDeathDelay.SafeAction(s => s.Text = \"0.5\");\r\n            }\r\n        }\r\n\r\n        private void CaptureOthersDeath_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CaptureOthersDeath\", captureOthersDeath.Checked);\r\n        }\r\n\r\n        private void CaptureOwnDeath_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CaptureOwnDeath\", captureOwnDeath.Checked);\r\n        }\r\n\r\n        private void CaptureOwnDeathDelay_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CaptureOwnDeathDelay\", Utility.ToDouble(captureOwnDeathDelay.Text.Trim(), 0.5));\r\n\r\n            if (Config.GetDouble(\"CaptureOwnDeathDelay\") < 0 || Config.GetDouble(\"CaptureOwnDeathDelay\") > 5)\r\n            {\r\n                Config.SetProperty(\"CaptureOwnDeathDelay\", 0.5);\r\n                captureOwnDeathDelay.SafeAction(s => s.Text = \"0.5\");\r\n            }\r\n        }\r\n\r\n        private void TargetFilterRemove_Click(object sender, EventArgs e)\r\n        {\r\n            if (targetFilter.SelectedIndex < 0)\r\n                return;\r\n\r\n            TargetFilterManager.RemoveTargetFilter(targetFilter.SelectedIndex);\r\n        }\r\n\r\n        private void TargetFilterClear_Click(object sender, EventArgs e)\r\n        {\r\n            TargetFilterManager.ClearTargetFilters();\r\n        }\r\n\r\n        private void TargetFilterEnabled_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"TargetFilterEnabled\", targetFilterEnabled.Checked);\r\n        }\r\n\r\n        /*private void onAddAllMobilesTargetFilter(object sender, System.EventArgs e)\r\n        {\r\n            if (targetFilter.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (World.Player == null)\r\n                return;\r\n            \r\n            TargetFilterManager.AddAllMobileAsTargetFilters();\r\n        }\r\n\r\n        private void onAddAllMobilesHumanoidTargetFilter(object sender, System.EventArgs e)\r\n        {\r\n            if (targetFilter.SelectedIndex < 0)\r\n                return;\r\n\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            TargetFilterManager.AddAllHumanoidsAsTargetFilters();\r\n        }*/\r\n\r\n        private void TargetFilterAdd_Click(object sender, EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            TargetFilterManager.OnTargetAddTargetFilter();\r\n        }\r\n\r\n        private void FriendAddTarget_Click(object sender, EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            if (friendsGroup.SelectedIndex < 0)\r\n                return;\r\n\r\n            ((FriendsManager.FriendGroup) friendsGroup.SelectedItem).AddFriendToGroup();\r\n        }\r\n\r\n        private TreeNode SearchTreeView(string p_sSearchTerm, TreeNodeCollection p_Nodes)\r\n        {\r\n            foreach (TreeNode node in p_Nodes)\r\n            {\r\n                if (node.Text.Contains(p_sSearchTerm))\r\n                    return node;\r\n\r\n                if (node.Nodes.Count > 0)\r\n                {\r\n                    TreeNode child = SearchTreeView(p_sSearchTerm, node.Nodes);\r\n                    if (child != null) return child;\r\n                }\r\n            }\r\n\r\n            return null;\r\n        }\r\n\r\n        private void SetMacroHotKey_Click(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                Engine.MainWindow.SafeAction(s =>\r\n                {\r\n                    Macro sel = GetMacroSel();\r\n\r\n                    tabs.SelectedTab = hotkeysTab;\r\n\r\n                    TreeNode resultNode = SearchTreeView(Language.Format(LocString.PlayA1, sel.GetName()), hotkeyTree.Nodes);\r\n\r\n                    if (resultNode != null)\r\n                    {\r\n                        KeyData hk = (KeyData) resultNode.Tag;\r\n\r\n                        hotkeyTree.SelectedNode = resultNode;\r\n                        hkKey.Focus();\r\n                    }\r\n                });\r\n            }\r\n            catch\r\n            {\r\n                // ignore\r\n            }\r\n        }\r\n\r\n        public void SaveMacroVariables()\r\n        {\r\n            MacroManager.DisplayMacroVariables(macroVariables);\r\n        }\r\n\r\n        public void SaveScriptVariables()\r\n        {\r\n            ScriptManager.RedrawScripts();\r\n        }\r\n\r\n        private void filterDaemonGraphics_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterDaemonGraphics\", filterDaemonGraphics.Checked);\r\n\r\n            if (filterDaemonGraphics.Checked)\r\n            {\r\n                MobileFilter.ApplyToMobiles();\r\n            }\r\n        }\r\n\r\n        private void daemonAnimationList_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                if (daemonAnimationList.SelectedIndex < 0)\r\n                    return;\r\n\r\n                Config.SetProperty(\"DaemonGraphic\", _animationData[daemonAnimationList.SelectedIndex].BodyId);\r\n\r\n                MobileFilter.Load();\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, \"Unable to find animation in file\", \"Animation Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void soundFilterEnabled_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"SoundFilterEnabled\", soundFilterEnabled.Checked);\r\n        }\r\n\r\n        private void soundFilterList_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (soundFilterList.SelectedIndex < 0)\r\n                return;\r\n\r\n            SoundMusicManager.Sound sound = (SoundMusicManager.Sound) soundFilterList.SelectedItem;\r\n\r\n            if (soundFilterList.GetItemChecked(soundFilterList.SelectedIndex))\r\n            {\r\n                SoundMusicManager.AddSoundFilter(sound);\r\n            }\r\n            else\r\n            {\r\n                SoundMusicManager.RemoveSoundFilter(sound);\r\n            }\r\n        }\r\n\r\n        private System.Media.SoundPlayer sp = new System.Media.SoundPlayer();\r\n\r\n        private void playSound_Click(object sender, EventArgs e)\r\n        {\r\n            sp.Stop();\r\n\r\n            if (soundFilterList.SelectedIndex < 0)\r\n                return;\r\n\r\n            SoundMusicManager.Sound sound = (SoundMusicManager.Sound) soundFilterList.SelectedItem;\r\n\r\n            if (playInClient.Checked && World.Player != null)\r\n            {\r\n                Client.Instance.SendToClient(new PlaySound(sound.Serial));\r\n            }\r\n            else\r\n            {\r\n                Ultima.UOSound s = Ultima.Sounds.GetSound(sound.Serial);\r\n                using (MemoryStream m = new MemoryStream(s.buffer))\r\n                {\r\n                    sp.Stream = m;\r\n                    sp.Play();\r\n                }\r\n            }\r\n        }\r\n\r\n        private void showFilteredSound_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowFilteredSound\", showFilteredSound.Checked);\r\n        }\r\n\r\n        private void showPlayingSoundInfo_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowPlayingSoundInfo\", showPlayingSoundInfo.Checked);\r\n        }\r\n\r\n        private void playMusic_Click(object sender, EventArgs e)\r\n        {\r\n            if (playableMusicList.SelectedIndex < 0 || World.Player == null)\r\n                return;\r\n\r\n            Client.Instance.SendToClient(new PlayMusic(Convert.ToUInt16(playableMusicList.SelectedIndex)));\r\n        }\r\n\r\n        private void showPlayingMusic_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowMusicInfo\", showPlayingMusic.Checked);\r\n        }\r\n\r\n        private void playScript_Click(object sender, EventArgs e)\r\n        {\r\n            if (ScriptManager.Running)\r\n            {\r\n                ScriptManager.StopScript();\r\n                return;\r\n            }\r\n\r\n            if (string.IsNullOrEmpty(scriptEditor.Text))\r\n            {\r\n                return;\r\n            }\r\n\r\n            if (Config.GetBool(\"AutoSaveScriptPlay\"))\r\n            {\r\n                SaveScript();\r\n            }\r\n            \r\n            RazorScript selScript = GetScriptSel();\r\n            \r\n            // We want to play the contents of the script editor\r\n\r\n            ScriptManager.PlayScriptFromUI(scriptEditor.Lines.ToArray(), selScript != null ? selScript.ToString() : \"N/A\", Config.GetBool(\"EnableHighlight\"));\r\n        }\r\n\r\n        public void LockScriptUI(bool enabled)\r\n        {\r\n            Engine.MainWindow.SafeAction(s =>\r\n            {\r\n                scriptEditor.Enabled = !enabled;\r\n                recordScript.Enabled = !enabled;\r\n                setScriptHotkey.Enabled = !enabled;\r\n                scriptTree.Enabled = !enabled;\r\n\r\n                saveScript.Enabled = !enabled;\r\n                newScript.Enabled = !enabled;\r\n\r\n                playScript.Text = !enabled ? \"Play\" : \"Stop\";\r\n\r\n                recMacro.Enabled = !enabled;\r\n                playMacro.Enabled = !enabled;\r\n                macroTree.Enabled = actionList.Enabled = !enabled;\r\n                newMacro.Enabled = delMacro.Enabled = !enabled;\r\n                nextMacroAction.Enabled = !enabled;\r\n            });\r\n        }\r\n\r\n        private void scriptEditor_LostFocus(object sender, EventArgs e)\r\n        {\r\n            if (Config.GetBool(\"AutoSaveScript\"))\r\n            {\r\n                SaveScript();\r\n            }\r\n        }\r\n\r\n        private bool _savedCurrentScript = true;\r\n\r\n        private void scriptEditor_KeyDown(object sender, KeyEventArgs e)\r\n        {\r\n            if (e.KeyData == (Keys.Control | Keys.S))\r\n            {\r\n                BeginInvoke(new Action(SaveScript));\r\n            }\r\n            \r\n            if (_savedCurrentScript)\r\n            {\r\n                UpdateScriptWindowTitle(false);\r\n                _savedCurrentScript = false;\r\n            }\r\n        }\r\n\r\n        private void SaveScript()\r\n        {\r\n            if (_selectedScript == null)\r\n            {\r\n                string filePath = $\"{Path.Combine(ScriptManager.ScriptPath, $\"auto-{Guid.NewGuid().ToString().Substring(0, 4)}.razor\")}\";\r\n\r\n                File.WriteAllText(filePath, scriptEditor.Text);\r\n\r\n                RazorScript script = new RazorScript\r\n                {\r\n                    Lines = File.ReadAllLines(filePath),\r\n                    Name = Path.GetFileNameWithoutExtension(filePath),\r\n                    Path = filePath\r\n                };\r\n                \r\n                TreeNode node = ScriptManager.GetScriptDirNode();\r\n\r\n                ScriptManager.RedrawScripts();\r\n\r\n                TreeNode newNode = new TreeNode(script.Name)\r\n                {\r\n                    Tag = script\r\n                };\r\n\r\n                if (node == null)\r\n                {\r\n                    scriptTree.Nodes.Add(newNode);\r\n                }\r\n                else\r\n                {\r\n                    node.Nodes.Add(newNode);\r\n                }\r\n\r\n                scriptTree.SelectedNode = newNode;\r\n            }\r\n            else\r\n            {\r\n                File.WriteAllText(_selectedScript.Path, scriptEditor.Text);\r\n                _selectedScript.Lines = File.ReadAllLines(_selectedScript.Path);\r\n            }\r\n\r\n            UpdateScriptWindowTitle(true);\r\n        }\r\n\r\n        private void recordScript_Click(object sender, EventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n                return;\r\n\r\n            if (ScriptManager.Recording) // stop recording\r\n            {\r\n                recordScript.Text = \"Record\";\r\n                ScriptManager.Recording = false;\r\n                scriptEditor.Enabled = true;\r\n                playScript.Enabled = true;\r\n            }\r\n            else //start recording\r\n            {\r\n                recordScript.Text = \"Stop\";\r\n                ScriptManager.Recording = true;\r\n                scriptEditor.Enabled = false;\r\n                playScript.Enabled = false;\r\n            }\r\n        }\r\n\r\n        private void newScript_Click(object sender, EventArgs e)\r\n        {\r\n            if (InputBox.Show(this, \"New Razor Script\", \"Enter the name of the script\"))\r\n            {\r\n                string name = InputBox.GetString();\r\n                if (string.IsNullOrEmpty(name) || name.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                    name.IndexOfAny(m_InvalidNameChars) != -1)\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.InvalidChars),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                TreeNode node = ScriptManager.GetScriptDirNode();\r\n\r\n                string path = (node == null || !(node.Tag is string))\r\n                    ? Config.GetUserDirectory(\"Scripts\")\r\n                    : (string)node.Tag;\r\n                path = Path.Combine(path, $\"{name}.razor\");\r\n\r\n                if (File.Exists(path))\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.MacroExists),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                File.CreateText(path).Close();\r\n\r\n                RazorScript script = ScriptManager.AddScript(path);\r\n\r\n                TreeNode newNode = new TreeNode(script.Name)\r\n                {\r\n                    Tag = script\r\n                };\r\n\r\n                if (node == null)\r\n                {\r\n                    scriptTree.Nodes.Add(newNode);\r\n                }\r\n                else\r\n                {\r\n                    node.Nodes.Add(newNode);\r\n                }\r\n\r\n                scriptTree.SelectedNode = newNode;\r\n            }\r\n        }\r\n\r\n        private void saveScript_Click(object sender, EventArgs e)\r\n        {\r\n            SaveScript();\r\n        }\r\n\r\n        private void setScriptHotkey_Click(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                Engine.MainWindow.SafeAction(s =>\r\n                {\r\n                    RazorScript script = GetScriptSel();\r\n\r\n                    tabs.SelectedTab = hotkeysTab;\r\n\r\n                    TreeNode resultNode = SearchTreeView($\"{Language.Format(LocString.PlayScript, script)}\",\r\n                        hotkeyTree.Nodes);\r\n\r\n                    if (resultNode != null)\r\n                    {\r\n                        KeyData hk = (KeyData) resultNode.Tag;\r\n\r\n                        hotkeyTree.SelectedNode = resultNode;\r\n                        hkKey.Focus();\r\n                    }\r\n                });\r\n            }\r\n            catch\r\n            {\r\n                // ignore\r\n            }\r\n        }\r\n\r\n        private void addScriptVariable_Click(object sender, EventArgs e)\r\n        {\r\n            if (ScriptManager.Running || ScriptManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            Targeting.OneTimeTarget((ground, serial, pt, gfx) =>\r\n            {\r\n                if (InputBox.Show(this, Language.GetString(LocString.NewScriptVariable),\r\n                        Language.GetString(LocString.EnterAName)))\r\n                {\r\n                    string name = InputBox.GetString();\r\n\r\n                    if (ScriptVariables.GetVariable(name) != Serial.MinusOne)\r\n                    {\r\n                        MessageBox.Show(this, \"Pick a unique script variable name and try again\",\r\n                            \"New Script Variable\", MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                        return;\r\n                    }\r\n\r\n                    ScriptVariables.RegisterVariable(name, serial);\r\n                    ScriptManager.RedrawScripts();\r\n                }\r\n\r\n                Engine.MainWindow.ShowMe();\r\n            });\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n        private void changeScriptVariable_Click(object sender, EventArgs e)\r\n        {\r\n            if (ScriptManager.Running || ScriptManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            if (scriptVariables.SelectedIndex < 0)\r\n                return;\r\n\r\n            var name = scriptVariables.SelectedItem.ToString();\r\n            name = name.Split('(')[0].Trim();\r\n\r\n            Targeting.OneTimeTarget((ground, serial, pt, gfx) =>\r\n            {\r\n                ScriptVariables.RegisterVariable(name, serial);\r\n                ScriptManager.RedrawScripts();\r\n                Engine.MainWindow.ShowMe();\r\n            });\r\n\r\n            World.Player.SendMessage(MsgLevel.Force, LocString.SelTargAct);\r\n        }\r\n\r\n        private void removeScriptVariable_Click(object sender, EventArgs e)\r\n        {\r\n            if (ScriptManager.Running || ScriptManager.Recording || World.Player == null)\r\n                return;\r\n\r\n            if (scriptVariables.SelectedIndex < 0)\r\n                return;\r\n\r\n            string name = scriptVariables.SelectedItem.ToString();\r\n            name = name.Split('(')[0].Trim();\r\n\r\n            ScriptVariables.UnregisterVariable(name);\r\n            ScriptManager.RedrawScripts();\r\n        }\r\n\r\n        private void autoSaveScript_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoSaveScript\", autoSaveScript.Checked);\r\n        }\r\n\r\n        private void CopyScriptToClipboard(object sender, EventArgs e)\r\n        {\r\n            RazorScript script = GetScriptSel();\r\n            if (script == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                Clipboard.SetText(string.Join(Environment.NewLine, script.Lines));\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.ReadError), \"Copy Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void ReloadScripts(object sender, EventArgs e)\r\n        {\r\n            RedrawScripts();\r\n        }\r\n\r\n        private void OpenScriptExternally(object sender, EventArgs args)\r\n        {\r\n            RazorScript script = GetScriptSel();\r\n            if (script == null)\r\n                return;\r\n\r\n            try\r\n            {\r\n                Process.Start(script.Path);\r\n            }\r\n            catch (Exception)\r\n            {\r\n                MessageBox.Show(this, \"Unable to open script\",\r\n                    Language.GetString(LocString.ReadError),\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void scriptEditor_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                ContextMenuStrip menu = new ContextMenuStrip();\r\n\r\n                menu.Items.Add(\"Cut\", null, OnScriptCut);\r\n                menu.Items.Add(\"Copy\", null, OnScriptCopy);\r\n                menu.Items.Add(\"Paste\", null, OnScriptPaste);\r\n                menu.Items.Add(\"Delete\", null, OnScriptDelete);\r\n                menu.Items.Add(\"-\");\r\n                menu.Items.Add(\"Select All\", null, OnScriptSelectAll);\r\n                menu.Items.Add(\"-\");\r\n\r\n                menu.Items[0].Enabled = false;\r\n                menu.Items[1].Enabled = false;\r\n                menu.Items[3].Enabled = false;\r\n\r\n                if (!string.IsNullOrEmpty(scriptEditor.SelectedText))\r\n                {\r\n                    menu.Items[0].Enabled = true;\r\n                    menu.Items[1].Enabled = true;\r\n                    menu.Items[3].Enabled = true;\r\n\r\n                    menu.Items.Add(\"Comment\", null, OnScriptComment);\r\n                    menu.Items.Add(\"Uncomment\", null, OnScriptUncomment);\r\n\r\n                    if (!string.IsNullOrEmpty(scriptEditor.SelectedText) && !ScriptManager.Running && !ScriptManager.Recording && World.Player != null)\r\n                    {\r\n                        menu.Items.Add(\"-\");\r\n                        menu.Items.Add(\"Play selected script code\", null, OnScriptPlaySelected);\r\n\r\n                        int space = scriptEditor.SelectedText.IndexOf(\" \", StringComparison.Ordinal);\r\n\r\n                        if (space > -1)\r\n                        {\r\n                            string command = scriptEditor.SelectedText.Substring(0, space);\r\n\r\n                            if (command.Equals(\"dclick\"))\r\n                            {\r\n                                menu.Items.Add(\"-\");\r\n                                menu.Items.Add(\"Convert to 'dclicktype' by gfxid\", null, OnScriptDclickTypeId);\r\n                                menu.Items.Add(\"Convert to 'dclicktype' by name\", null, OnScriptDclickTypeName);\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    menu.Items.Add(\"-\");\r\n                }\r\n\r\n                menu.Items.Add(scriptSplitContainer.Panel1Collapsed ? \"Show script tree\" : \"Hide script tree\",\r\n                    null,\r\n                    OnScriptHideTreeView);\r\n\r\n\r\n                menu.Show(scriptEditor, new Point(e.X, e.Y));\r\n            }\r\n            else if (e.Button == MouseButtons.Left && e.Clicks == 2)\r\n            {\r\n                if (ScriptManager.Running || ScriptManager.Recording || World.Player == null)\r\n                    return;\r\n            }\r\n        }\r\n\r\n        private void OnScriptSelectAll(object sender, EventArgs e)\r\n        {\r\n            scriptEditor.SelectAll();\r\n        }\r\n\r\n        private void OnScriptDelete(object sender, EventArgs e)\r\n        {\r\n            if (!string.IsNullOrEmpty(scriptEditor.SelectedText))\r\n            {\r\n                scriptEditor.SelectedText = string.Empty;\r\n            }\r\n        }\r\n\r\n        private void OnScriptPaste(object sender, EventArgs e)\r\n        {\r\n            scriptEditor.Paste();\r\n        }\r\n\r\n        private void OnScriptCopy(object sender, EventArgs e)\r\n        {\r\n            if (!string.IsNullOrEmpty(scriptEditor.SelectedText))\r\n            {\r\n                scriptEditor.Copy();\r\n            }\r\n        }\r\n\r\n        private void OnScriptCut(object sender, EventArgs e)\r\n        {\r\n            if (!string.IsNullOrEmpty(scriptEditor.SelectedText))\r\n            {\r\n                scriptEditor.Cut();\r\n            }\r\n        }\r\n\r\n        private void OnScriptHideTreeView(object sender, EventArgs e)\r\n        {\r\n            scriptSplitContainer.Panel1Collapsed = !scriptSplitContainer.Panel1Collapsed;\r\n        }\r\n\r\n        private void OnScriptComment(object sender, System.EventArgs e)\r\n        {\r\n            string[] lines = scriptEditor.SelectedText.Split(new[] {\"\\r\\n\", \"\\r\", \"\\n\"}, StringSplitOptions.None);\r\n\r\n            scriptEditor.SelectedText = \"\";\r\n            for (int i = 0; i < lines.Count(); i++)\r\n            {\r\n                scriptEditor.SelectedText += \"#\" + lines[i];\r\n                if (i < lines.Count() - 1)\r\n                    scriptEditor.SelectedText += \"\\r\\n\";\r\n            }\r\n        }\r\n\r\n        private void OnScriptUncomment(object sender, System.EventArgs e)\r\n        {\r\n            string[] lines = scriptEditor.SelectedText.Split(new[] {\"\\r\\n\", \"\\r\", \"\\n\"}, StringSplitOptions.None);\r\n\r\n            scriptEditor.SelectedText = \"\";\r\n            for (int i = 0; i < lines.Count(); i++)\r\n            {\r\n                scriptEditor.SelectedText += lines[i].TrimStart('#');\r\n                if (i < lines.Count() - 1)\r\n                    scriptEditor.SelectedText += \"\\r\\n\";\r\n            }\r\n        }\r\n\r\n        private void OnScriptDclickTypeId(object sender, System.EventArgs e)\r\n        {\r\n            Serial itemId = Serial.Zero;\r\n\r\n            try\r\n            {\r\n                itemId = Serial.Parse(scriptEditor.SelectedText.Split(' ')[1]);\r\n            }\r\n            catch\r\n            {\r\n                return;\r\n            }\r\n\r\n            Item item = World.FindItem(itemId);\r\n\r\n            if (item == null)\r\n                return;\r\n\r\n            scriptEditor.SelectedText = \"\";\r\n            scriptEditor.SelectedText = $\"dclicktype '{item.ItemID.Value}'\";\r\n        }\r\n\r\n        private void OnScriptDclickTypeName(object sender, System.EventArgs e)\r\n        {\r\n            Serial gfxid = Serial.Zero;\r\n\r\n            try\r\n            {\r\n                gfxid = Serial.Parse(scriptEditor.SelectedText.Split(' ')[1]);\r\n            }\r\n            catch\r\n            {\r\n                return;\r\n            }\r\n\r\n\r\n            Item item = World.FindItem(gfxid);\r\n\r\n            if (item == null)\r\n                return;\r\n\r\n            scriptEditor.SelectedText = \"\";\r\n            scriptEditor.SelectedText = $\"dclicktype '{item.ItemID.ItemData.Name}'\";\r\n        }\r\n\r\n        private void OnScriptPlaySelected(object sender, System.EventArgs e)\r\n        {\r\n            if (ScriptManager.Running)\r\n            {\r\n                ScriptManager.StopScript();\r\n                return;\r\n            }\r\n\r\n            if (string.IsNullOrEmpty(scriptEditor.SelectedText))\r\n                return;\r\n\r\n            string[] lines = scriptEditor.SelectedText.Split(new[] {\"\\r\\n\", \"\\r\", \"\\n\"}, StringSplitOptions.None);\r\n\r\n            \r\n            RazorScript selScript = GetScriptSel();\r\n            \r\n            // We want to play the contents of the script editor\r\n            ScriptManager.PlayScriptFromUI(lines, selScript != null ? selScript.ToString() : \"N/A\", Config.GetBool(\"EnableHighlight\"));\r\n        }\r\n\r\n        private void autoSaveScriptPlay_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"AutoSaveScriptPlay\", autoSaveScriptPlay.Checked);\r\n        }\r\n        \r\n        private void highlightFriend_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"HighlightFriend\", highlightFriend.Checked);\r\n        }\r\n\r\n        private void scriptFilter_TextChanged(object sender, EventArgs e)\r\n        {\r\n            scriptTree.SafeAction(s =>\r\n            {\r\n                s.BeginUpdate();\r\n                s.Nodes.Clear();\r\n\r\n                if (scriptFilter.Text != string.Empty)\r\n                {\r\n                    foreach (TreeNode _parentNode in _scriptTreeViewCache.Nodes) // We won't filter on the top parent domain\r\n                    {\r\n                        if (_parentNode.Text.ToLower().Contains(scriptFilter.Text.ToLower()))\r\n                        {\r\n                            s.Nodes.Add((TreeNode)_parentNode.Clone());\r\n                        }\r\n\r\n                        if (_parentNode.Nodes.Count > 0) // Just in case\r\n                        {\r\n                            foreach (TreeNode _subSubChildNode in _parentNode.Nodes)\r\n                            {\r\n                                if (_subSubChildNode.Text.ToLower().Contains(scriptFilter.Text.ToLower()))\r\n                                {\r\n                                    s.Nodes.Add((TreeNode)_subSubChildNode.Clone());\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    RedrawScripts();\r\n                }\r\n\r\n                //enables redrawing tree after all objects have been added\r\n                s.EndUpdate();\r\n            });\r\n        }\r\n        \r\n        private void disableScriptPlayFinish_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ScriptDisablePlayFinish\", scriptDisablePlayFinish.Checked);\r\n        }\r\n\r\n        private void btnUseCurrentLoc_Click(object sender, EventArgs e)\r\n        {\r\n            if (World.Player != null)\r\n            {\r\n                txtWaypointX.SafeAction(s => s.Text = World.Player.Position.X.ToString());\r\n                txtWaypointY.SafeAction(s => s.Text = World.Player.Position.Y.ToString());\r\n            }\r\n        }\r\n\r\n        private void btnAddWaypoint_Click(object sender, EventArgs e)\r\n        {\r\n            WaypointManager.Waypoint waypoint = new WaypointManager.Waypoint();\r\n\r\n            waypoint.Name = !string.IsNullOrEmpty(txtWaypointName.Text) ? txtWaypointName.Text.Replace(\"#\", string.Empty) : \"N/A\";\r\n\r\n            txtWaypointX.SafeAction(s =>\r\n            {\r\n                waypoint.X = Utility.ToInt32(s.Text.Trim(), 0);\r\n            });\r\n\r\n            txtWaypointY.SafeAction(s =>\r\n            {\r\n                waypoint.Y = Utility.ToInt32(s.Text.Trim(), 0);\r\n            });\r\n\r\n            if (waypoint.X != 0 && waypoint.Y != 0)\r\n            {\r\n                WaypointManager.AddWaypoint(waypoint);\r\n            }\r\n        }\r\n        \r\n        private void btnHideWaypoint_Click(object sender, EventArgs e)\r\n        {\r\n            if (World.Player != null)\r\n                WaypointManager.ClearWaypoint();\r\n        }\r\n\r\n        private void btnRemoveSelectedWaypoint_Click(object sender, EventArgs e)\r\n        {\r\n            if (waypointList.SelectedIndex < 0)\r\n                return;\r\n\r\n            WaypointManager.RemoveWaypoint((WaypointManager.Waypoint) waypointList.SelectedItem);\r\n        }\r\n\r\n        private void showWaypointOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowWaypointOverhead\", showWaypointOverhead.Checked);\r\n        }\r\n\r\n        private void showWaypointDistance_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowWaypointDistance\", showWaypointDistance.Checked);\r\n\r\n            if (showWaypointDistance.Checked)\r\n            {\r\n                WaypointManager.StartTimer();\r\n            }\r\n            else\r\n            {\r\n                WaypointManager.StopTimer();\r\n            }\r\n        }\r\n\r\n        private void txtWaypointDistanceSec_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowWaypointSeconds\", Utility.ToInt32(txtWaypointDistanceSec.Text, 10));\r\n\r\n            WaypointManager.ResetTimer();\r\n        }\r\n\r\n        private void hideWaypointDist_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"HideWaypointDistance\", Utility.ToInt32(hideWaypointDist.Text, 4));\r\n        }\r\n\r\n        private void hideWaypointWithin_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ClearWaypoint\", hideWaypointWithin.Checked);\r\n        }\r\n\r\n        private void listWaypoints_MouseDoubleClick(object sender, MouseEventArgs e)\r\n        {\r\n            if (World.Player == null || waypointList.SelectedIndex < 0)\r\n                return;\r\n\r\n            WaypointManager.ShowWaypoint((WaypointManager.Waypoint)waypointList.SelectedItem);\r\n        }\r\n\r\n        private void waypointOnDeath_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"CreateWaypointOnDeath\", waypointOnDeath.Checked);\r\n        }\r\n\r\n        private void scriptGuide_Click(object sender, EventArgs e)\r\n        {\r\n            Utility.LaunchBrowser(\"https://www.razorce.com/guide/\");\r\n        }\r\n        private void listWaypoints_MouseDown(object sender, MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                ContextMenuStrip menu = new ContextMenuStrip();\r\n                menu.Items.Add(\"Import Waypoints\", null, onImportWaypoints);\r\n                menu.Items.Add(\"Export Waypoints\", null, onExportWaypoints);\r\n                menu.Items.Add(\"-\");\r\n                menu.Items.Add(\"Clear All Waypoints\", null, onClearWaypoints);\r\n\r\n                menu.Show(waypointList, new Point(e.X, e.Y));\r\n            }\r\n        }\r\n\r\n        private void onClearWaypoints(object sender, EventArgs e)\r\n        {\r\n            if (MessageBox.Show(this, \"Are you sure you want to clear all of your waypoints?\", \"Clear Waypoints?\",\r\n                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                WaypointManager.ClearAll();\r\n                WaypointManager.RedrawList();\r\n            }\r\n        }\r\n\r\n        private void onExportWaypoints(object sender, EventArgs e)\r\n        {\r\n            StringBuilder sb = new StringBuilder();\r\n\r\n            sb.AppendLine(\"!Razor.Waypoints.Import\");\r\n\r\n            foreach (WaypointManager.Waypoint waypoint in WaypointManager.Waypoints)\r\n            {\r\n                sb.AppendLine($\"{waypoint.Name}#{waypoint.X}#{waypoint.Y}\");\r\n            }\r\n\r\n            Clipboard.SetDataObject(sb.ToString(), true);\r\n        }\r\n\r\n        private void onImportWaypoints(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                if (Clipboard.GetText().Contains(\"!Razor.Waypoints.Import\"))\r\n                {\r\n                    List<string> waypointImport = Clipboard.GetText()\r\n                        .Split(new[] { \"\\r\\n\", \"\\r\", \"\\n\" }, StringSplitOptions.None).ToList();\r\n\r\n                    waypointImport.RemoveAt(0);\r\n\r\n                    foreach (string import in waypointImport)\r\n                    {\r\n                        if (string.IsNullOrEmpty(import))\r\n                            continue;\r\n\r\n                        string[] waypoint = import.Split('#');\r\n\r\n                        WaypointManager.AddWaypoint(new WaypointManager.Waypoint\r\n                        {\r\n                            Name = waypoint[0],\r\n                            X = Convert.ToInt32(waypoint[1]),\r\n                            Y = Convert.ToInt32(waypoint[2])\r\n                        });\r\n                    }\r\n\r\n                    Clipboard.Clear();\r\n                }\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private void showPartyFriendOverhead_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowPartyFriendOverhead\", showPartyFriendOverhead.Checked);\r\n        }\r\n\r\n        private void filterTabs_IndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (filterTabs.SelectedTab == subFilterTargets)\r\n            {\r\n                TargetFilterManager.RedrawList();\r\n            }\r\n            else if (filterTabs.SelectedTab == subFilterText)\r\n            {\r\n                TextFilterManager.RedrawList();\r\n            }\r\n            else if (filterTabs.SelectedTab == subFilterSoundMusic)\r\n            {\r\n                SoundMusicManager.RedrawList();\r\n            }\r\n        }\r\n\r\n        private void cliLocSearch_Click(object sender, EventArgs e)\r\n        {\r\n            cliLocSearchView.SafeAction(s => s.Items.Clear());\r\n\r\n            if (string.IsNullOrEmpty(cliLocTextSearch.Text) || cliLocTextSearch.Text.Length < 4)\r\n                return;\r\n\r\n            foreach (StringEntry entry in Language.CliLoc.Entries)\r\n            {\r\n                if (entry.Text.IndexOf(cliLocTextSearch.Text, StringComparison.OrdinalIgnoreCase) >= 0)\r\n                {\r\n                    ListViewItem item = new ListViewItem($\"{entry.Number}\");\r\n                    item.SubItems.Add(new ListViewItem.ListViewSubItem(item, $\"{entry.Text}\"));\r\n\r\n                    cliLocSearchView.SafeAction(s => s.Items.Add(item));\r\n                }\r\n            }\r\n\r\n            if (cliLocSearchView.Items.Count == 0)\r\n            {\r\n                if (MessageBox.Show(this,\r\n                    $\"Unable to find that message. Would you still like to setup an overhead message with '{cliLocTextSearch.Text}' anyway?\",\r\n                    \"Overhead Messages\",\r\n                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n                {\r\n                    setOverheadMessage.PerformClick();\r\n                }\r\n            }\r\n        }\r\n\r\n        private void setOverheadMessage_Click(object sender, EventArgs e)\r\n        {\r\n            int hueIdx = Config.GetInt(\"SysColor\");\r\n            string newItemText;\r\n\r\n            if (string.IsNullOrEmpty(cliLocTextSearch.Text))\r\n                return;\r\n\r\n            if (cliLocSearchView.SelectedItems.Count > 0)\r\n            {\r\n                ListViewItem selectedItem = cliLocSearchView.SelectedItems[0];\r\n                newItemText = selectedItem.SubItems[1].Text;\r\n            }\r\n            else\r\n            {\r\n                newItemText = cliLocTextSearch.Text;\r\n            }\r\n\r\n            ListViewItem item = new ListViewItem(newItemText);\r\n\r\n            if (InputBox.Show(this, \"Enter text to display overhead\", newItemText))\r\n            {\r\n                string overheadMessage = InputBox.GetString();\r\n\r\n                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, overheadMessage));\r\n                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, \"None\"));\r\n\r\n                item.SubItems[1].BackColor = hueIdx > 0 && hueIdx < 3000\r\n                    ? Hues.GetHue(hueIdx - 1).GetColor(HueEntry.TextHueIDX)\r\n                    : SystemColors.Control;\r\n\r\n                item.SubItems[1].ForeColor = (item.SubItems[1].BackColor.GetBrightness() < 0.35 ? Color.White : Color.Black);\r\n                item.UseItemStyleForSubItems = false;\r\n\r\n                cliLocOverheadView.SafeAction(s => s.Items.Add(item));\r\n\r\n                OverheadManager.OverheadMessages.Add(new OverheadMessage\r\n                {\r\n                    SearchMessage = newItemText,\r\n                    Hue = hueIdx,\r\n                    MessageOverhead = overheadMessage,\r\n                    Sound = 0\r\n                });\r\n            }\r\n        }\r\n\r\n        private void editOverheadMessage_Click(object sender, EventArgs e)\r\n        {\r\n            if (cliLocOverheadView.SelectedItems.Count == 0)\r\n                return;\r\n\r\n            ListViewItem selectedItem = cliLocOverheadView.SelectedItems[0];\r\n            string oldMessage = selectedItem.SubItems[1].Text;\r\n\r\n            //ListViewItem item = new ListViewItem(newItemText);\r\n\r\n            if (InputBox.Show(this, \"Enter Overhead Text\", \"Enter text to display overhead\", oldMessage))\r\n            {\r\n                string newMessage = InputBox.GetString();\r\n\r\n                if (string.IsNullOrEmpty(newMessage))\r\n                    return;\r\n\r\n                selectedItem.SubItems[1].Text = newMessage;\r\n\r\n                foreach (OverheadMessage list in OverheadManager.OverheadMessages)\r\n                {\r\n                    if (list.MessageOverhead.Equals(oldMessage))\r\n                    {\r\n                        list.MessageOverhead = newMessage;\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private void removeOverheadMessage_Click(object sender, EventArgs e)\r\n        {\r\n            if (cliLocOverheadView.SelectedItems.Count > 0)\r\n            {\r\n                cliLocOverheadView.SafeAction(s =>\r\n                {\r\n                    OverheadManager.Remove(s.SelectedItems[0].Text);\r\n                    s.Items.Remove(s.SelectedItems[0]);\r\n                });\r\n            }\r\n        }\r\n\r\n        private void setColorHue_Click(object sender, EventArgs e)\r\n        {\r\n            if (cliLocOverheadView.SelectedItems.Count > 0)\r\n            {\r\n                OverheadManager.SetOverheadHue();\r\n            }\r\n        }\r\n\r\n        private void unicodeStyle_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OverheadStyle\", unicodeStyle.Checked ? 1 : 0);\r\n        }\r\n\r\n        private void asciiStyle_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OverheadStyle\", asciiStyle.Checked ? 0 : 1);\r\n        }\r\n\r\n        private void overheadFormat_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OverheadFormat\", overheadFormat.Text);\r\n\r\n            if (string.IsNullOrEmpty(overheadFormat.Text))\r\n            {\r\n                Config.SetProperty(\"OverheadFormat\", \"{msg}\");\r\n                overheadFormat.Text = \"{msg}\";\r\n            }\r\n\r\n            Config.SetProperty(\"OverheadFormat\", overheadFormat.Text);\r\n        }\r\n\r\n        private void showOverheadMessages_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowOverheadMessages\", showOverheadMessages.Checked);\r\n        }\r\n\r\n        private void displayCountersTabCtrl_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (displayCountersTabCtrl.SelectedTab == subOverheadTab)\r\n            {\r\n                OverheadManager.RedrawList();\r\n            }\r\n\r\n            if (displayCountersTabCtrl.SelectedTab == subWaypoints)\r\n            {\r\n                WaypointManager.RedrawList();\r\n            }\r\n        }\r\n\r\n        private void overrideSpellFormat_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"OverrideSpellFormat\", overrideSpellFormat.Checked);            \r\n        }\r\n\r\n        private void reequipHandsPotion_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"PotionReequip\", reequipHandsPotion.Checked);\r\n        }\r\n\r\n        private void agentSetHotKey_Click(object sender, EventArgs e)\r\n        {\r\n            if (agentList.SelectedIndex < 0)\r\n                return;\r\n\r\n            try\r\n            {\r\n                Engine.MainWindow.SafeAction(s =>\r\n                {\r\n                    Agent agent = (Agent) agentList.SelectedItem;\r\n\r\n                    tabs.SelectedTab = hotkeysTab;\r\n\r\n                    string search = string.Empty;\r\n\r\n                    switch (agent)\r\n                    {\r\n                        case OrganizerAgent _:\r\n                            search = $\"{Language.GetString(LocString.OrganizerAgent)}-{agent.Number:D2}\";\r\n                            break;\r\n                        case RestockAgent _:\r\n                            search = $\"{Language.GetString(LocString.RestockAgent)}-{agent.Number:D2}\";\r\n                            break;\r\n                        case UseOnceAgent _:\r\n                            search = agent.Name;\r\n                            break;\r\n                        case ScavengerAgent _:\r\n                            search = Language.GetString(LocString.ScavengerEnableDisable);\r\n                            break;\r\n                        case SellAgent _:\r\n                            search = Language.GetString(LocString.SetSellAgentHotBag);\r\n                            break;\r\n                    }\r\n\r\n                    TreeNode resultNode = SearchTreeView(search, hotkeyTree.Nodes);\r\n\r\n                    if (resultNode != null)\r\n                    {\r\n                        hotkeyTree.SelectedNode = resultNode;\r\n                        hkKey.Focus();\r\n                    }\r\n                });\r\n            }\r\n            catch\r\n            {\r\n                // ignore\r\n            }\r\n        }\r\n        private void addFilterText_Click(object sender, EventArgs e)\r\n        {\r\n            if (InputBox.Show(this, \"Enter text to filter\", \"Text Filter\"))\r\n            {\r\n                string message = InputBox.GetString();\r\n                TextFilterManager.AddFilter(message);\r\n            }\r\n        }\r\n\r\n        private void removeFilterText_Click(object sender, EventArgs e)\r\n        {\r\n            if (textFilterList.SelectedIndex < 0)\r\n                return;\r\n\r\n            TextFilterManager.RemoveFilter((string) textFilterList.SelectedItem);\r\n        }\r\n\r\n        private void enableTextFilter_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"EnableTextFilter\", enableTextFilter.Checked);\r\n        }\r\n\r\n        private void disableScriptTooltips_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DisableScriptTooltips\", disableScriptTooltips.Checked);\r\n\r\n            ScriptManager.InitScriptEditor();\r\n        }\r\n\r\n        private RazorScript _selectedScript;\r\n\r\n        private void scriptTree_AfterSelect(object sender, TreeViewEventArgs e)\r\n        {\r\n            if (e.Node.Tag is string)\r\n            {\r\n                return;\r\n            }\r\n\r\n            _selectedScript = e.Node.Tag as RazorScript;\r\n\r\n            if (_selectedScript == null)\r\n                return;\r\n\r\n            Engine.MainWindow.SafeAction(s =>\r\n            {\r\n                UpdateScriptWindowTitle(true);\r\n\r\n                if (hotkeyTree.TopNode == null)\r\n                {\r\n                    HotKey.RebuildList(hotkeyTree);\r\n                    RebuildHotKeyCache();\r\n                }\r\n                \r\n                TreeNode resultNode = SearchTreeView($\"{Language.Format(LocString.PlayScript, _selectedScript.ToString())}\", hotkeyTree.Nodes);\r\n\r\n                if (resultNode != null)\r\n                {\r\n                    KeyData hk = (KeyData)resultNode.Tag;\r\n\r\n                    if (hk != null && !string.IsNullOrEmpty(hk.KeyString()))\r\n                    {\r\n                        scriptHotkey.Text = hk.KeyString();\r\n                    }\r\n                    else\r\n                    {\r\n                        scriptHotkey.Text = \"Not Set\";\r\n                    }\r\n                }\r\n                \r\n                ScriptManager.SetEditorText(_selectedScript);\r\n\r\n                ScriptManager.ClearAllHighlightLines();\r\n            });\r\n        }\r\n\r\n        private ContextMenuStrip m_ScriptContextMenu = null;\r\n\r\n        private void scriptTree_MouseDown(object sender, MouseEventArgs e)\r\n        {\r\n            RazorScript selScript = GetScriptSel();\r\n\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                m_ScriptContextMenu = new ContextMenuStrip();\r\n\r\n                m_ScriptContextMenu.Items.Add(\"Add category\", null, AddScriptCategory);\r\n\r\n                if (scriptTree.SelectedNode != null && scriptTree.SelectedNode.Tag is string)\r\n                {\r\n                    m_ScriptContextMenu.Items.Add(\"Delete category\", null, Script_DeleteCategory);\r\n                }\r\n                else if (selScript != null)\r\n                {\r\n                    m_ScriptContextMenu.Items.Add(\"Move to category\", null, MoveScriptCategory);\r\n                    m_ScriptContextMenu.Items.Add(\"-\");\r\n                    m_ScriptContextMenu.Items.Add($\"Rename '{selScript.Name}'\", null, RenameScript);\r\n                    m_ScriptContextMenu.Items.Add($\"Delete '{selScript.Name}'\", null, DeleteScript);\r\n                    m_ScriptContextMenu.Items.Add(\"-\");\r\n                    m_ScriptContextMenu.Items.Add($\"Open '{selScript.Name}' externally\", null, OpenScriptExternally);\r\n                    m_ScriptContextMenu.Items.Add(\"Copy to clipboard\", null, CopyScriptToClipboard);\r\n                }\r\n                \r\n                m_ScriptContextMenu.Items.Add(\"-\");\r\n                m_ScriptContextMenu.Items.Add(\"Reload all scripts\", null, ReloadScripts);\r\n                m_ScriptContextMenu.Items.Add(\"Hide script tree\", null, HideScriptTreeView);\r\n\r\n                m_ScriptContextMenu.Show(scriptTree, new Point(e.X, e.Y));\r\n            }\r\n        }\r\n\r\n        private void UpdateScriptWindowTitle(bool saved)\r\n        {\r\n            if (_selectedScript != null)\r\n            {\r\n                string append;\r\n\r\n                if (World.Player != null)\r\n                {\r\n                    append = $\"{World.Player.Name} ({World.ShardName})\";\r\n                }\r\n                else\r\n                {\r\n                    append = $\"Razor v{Engine.Version}\";\r\n                }\r\n\r\n                Text = saved ? $\"[{_selectedScript.Name}] - {append}\" : $\"[*{_selectedScript.Name}] - {append}\";\r\n                _savedCurrentScript = true;\r\n            }\r\n        }\r\n\r\n        private void HideScriptTreeView(object sender, EventArgs e)\r\n        {\r\n            scriptSplitContainer.Panel1Collapsed = true;\r\n        }\r\n\r\n        private void DeleteScript(object sender, EventArgs e)\r\n        {\r\n            RazorScript selScript = GetScriptSel();\r\n\r\n            if (selScript == null)\r\n            {\r\n                Script_DeleteCategory(sender, e);\r\n                return;\r\n            }\r\n\r\n            if (MessageBox.Show(this, Language.Format(LocString.DelConf, $\"{selScript.Name}\"),\r\n                \"Confirm Delete\", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n            {\r\n                try\r\n                {\r\n                    File.Delete(selScript.Path);\r\n                    ScriptManager.RemoveScript(selScript);\r\n                }\r\n                catch\r\n                {\r\n                    return;\r\n                }\r\n\r\n                RedrawScripts();\r\n\r\n                TreeNode node = FindNode(scriptTree.Nodes, selScript);\r\n                node?.Remove();\r\n            }\r\n\r\n            RebuildScriptCache();\r\n        }\r\n\r\n        private void RenameScript(object sender, EventArgs e)\r\n        {\r\n            RazorScript selScript = GetScriptSel();\r\n\r\n            if (selScript == null)\r\n                return;\r\n\r\n            if (InputBox.Show(this, \"Enter a new name for the script\", \"Rename Script\", selScript.Name))\r\n            {\r\n                string name = InputBox.GetString();\r\n\r\n                if (string.IsNullOrEmpty(name) || name.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                    name.IndexOfAny(m_InvalidNameChars) != -1)\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.InvalidChars),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                string newScriptPath = Path.Combine(Path.GetDirectoryName(selScript.Path), $\"{name}.razor\");\r\n\r\n                if (File.Exists(newScriptPath))\r\n                {\r\n                    MessageBox.Show(this, \"A script with that name already exists.\",\r\n                        Language.GetString(LocString.Invalid),\r\n                        MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                    return;\r\n                }\r\n\r\n                try\r\n                {\r\n                    Engine.MainWindow.SafeAction(s =>\r\n                    {\r\n                        File.Move(selScript.Path, newScriptPath);\r\n                        ScriptManager.RemoveScript(selScript);\r\n\r\n                        RedrawScripts();\r\n                    });\r\n                }\r\n                catch\r\n                {\r\n                    // ignore\r\n                }\r\n            }\r\n        }\r\n\r\n        private void MoveScriptCategory(object sender, EventArgs e)\r\n        {\r\n            RazorScript selScript = GetScriptSel();\r\n\r\n            if (selScript == null)\r\n                return;\r\n\r\n            List<string> dirNames = new List<string>\r\n            {\r\n                \"<None>\"\r\n            };\r\n\r\n            foreach (string dir in Directory.GetDirectories(Config.GetUserDirectory(\"Scripts\"), \"*\", SearchOption.AllDirectories))\r\n            {\r\n                dirNames.Add(dir.Replace(Config.GetUserDirectory(\"Scripts\"), \"\").Substring(1));\r\n            }\r\n\r\n            if (!InputDropdown.Show(this, Language.GetString(LocString.CatName), dirNames.ToArray()))\r\n                return;\r\n\r\n            try\r\n            {\r\n                string newPath = string.Empty;\r\n\r\n                if (InputDropdown.GetString().Equals(\"<None>\"))\r\n                {\r\n                    newPath = Path.Combine(Config.GetUserDirectory(\"Scripts\"), $\"{Path.GetFileName(selScript.Path)}\");\r\n                }\r\n                else\r\n                {\r\n                    newPath = Path.Combine(Config.GetUserDirectory(\"Scripts\"), $\"{InputDropdown.GetString()}/{Path.GetFileName(selScript.Path)}\");\r\n                }\r\n\r\n                File.Move(selScript.Path, newPath);\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.CantMoveMacro), \"Unable to Move Script\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n            }\r\n\r\n            RedrawScripts();\r\n\r\n            scriptTree.SelectedNode = FindScriptNode(scriptTree.Nodes, selScript);\r\n        }\r\n\r\n        private void AddScriptCategory(object sender, EventArgs args)\r\n        {\r\n            if (!InputBox.Show(this, Language.GetString(LocString.CatName)))\r\n                return;\r\n\r\n            string path = InputBox.GetString();\r\n\r\n            if (string.IsNullOrEmpty(path) || path.IndexOfAny(Path.GetInvalidPathChars()) != -1 ||\r\n                path.IndexOfAny(m_InvalidNameChars) != -1)\r\n            {\r\n                MessageBox.Show(this, Language.GetString(LocString.InvalidChars), \"Invalid Path\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n                return;\r\n            }\r\n\r\n            TreeNode node = ScriptManager.GetScriptDirNode();\r\n\r\n            try\r\n            {\r\n                if (node == null || !(node.Tag is string))\r\n                    path = Path.Combine(Config.GetUserDirectory(\"Scripts\"), path);\r\n                else\r\n                    path = Path.Combine((string)node.Tag, path);\r\n\r\n                Engine.EnsureDirectory(path);\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, Language.Format(LocString.CanCreateDir, path), \"Unable to Create Directory\",\r\n                    MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                return;\r\n            }\r\n\r\n            TreeNode newNode = new TreeNode($\"[{Path.GetFileName(path)}]\")\r\n            {\r\n                Tag = path\r\n            };\r\n\r\n            if (node == null)\r\n                scriptTree.Nodes.Add(newNode);\r\n            else\r\n                node.Nodes.Add(newNode);\r\n\r\n            RedrawScripts();\r\n\r\n            scriptTree.SelectedNode = newNode;\r\n        }\r\n\r\n        private void openScreenshotFolder_Click(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                var psi = new ProcessStartInfo { FileName = Config.GetString(\"CapPath\"), UseShellExecute = true };\r\n                Process.Start(psi);\r\n            }\r\n            catch (Exception ex)\r\n            {\r\n                MessageBox.Show(this, ex.Message, \"Unable to open directory\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Warning);\r\n            }\r\n        }\r\n\r\n        private void buyAgentIgnoreGold_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"BuyAgentsIgnoreGold\", buyAgentIgnoreGold.Checked);\r\n        }\r\n\r\n        private ContextMenuStrip m_AgentsMenu = null;\r\n\r\n        private void agentList_MouseDown(object sender, MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right)\r\n            {\r\n                Agent agent = (Agent)agentList.SelectedItem;\r\n\r\n                if (agent != null && (agent is OrganizerAgent || agent is RestockAgent || agent is BuyAgent))\r\n                {\r\n                    m_AgentsMenu = new ContextMenuStrip();\r\n                    m_AgentsMenu.Items.Add($\"Set alias for '{agent.Name}'\", null, OnAgentAlias);\r\n                    m_AgentsMenu.Show(agentList, new Point(e.X, e.Y));\r\n                }\r\n            }\r\n        }\r\n\r\n        private void OnAgentAlias(object sender, EventArgs e)\r\n        {\r\n            Agent agent = (Agent)agentList.SelectedItem;\r\n\r\n            if (InputBox.Show(this, $\"Set '{agent}' Alias\", \"Enter an alias for this agent\"))\r\n            {\r\n                string alias = InputBox.GetString();\r\n\r\n                if (string.IsNullOrEmpty(alias) || alias.IndexOfAny(Path.GetInvalidPathChars()) != -1 || alias.IndexOfAny(m_InvalidNameChars) != -1)\r\n                {\r\n                    MessageBox.Show(this, Language.GetString(LocString.InvalidChars),\r\n                        Language.GetString(LocString.Invalid), MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                }\r\n                else\r\n                {\r\n                    agent.Alias = alias;\r\n\r\n                    int sel = agentList.SelectedIndex;\r\n\r\n                    Agent.Redraw(agentList, agentGroup, agentB1, agentB2, agentB3, agentB4, agentB5, agentB6);\r\n                    if (sel >= 0 && sel < agentList.Items.Count)\r\n                        agentList.SelectedIndex = sel;\r\n                }\r\n\r\n            }\r\n        }\r\n\r\n        private void nextPrevAbcOrder_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"NextPrevAlphabetical\", nextPrevAbcOrder.Checked);\r\n        }\r\n\r\n        private void wyrmAnimationList_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            try\r\n            {\r\n                if (wyrmAnimationList.SelectedIndex < 0)\r\n                    return;\r\n\r\n                Config.SetProperty(\"WyrmGraphic\", _animationData[wyrmAnimationList.SelectedIndex].BodyId);\r\n\r\n                MobileFilter.Load();\r\n            }\r\n            catch\r\n            {\r\n                MessageBox.Show(this, \"Unable to find animation in file\", \"Animation Error\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n            }\r\n        }\r\n\r\n        private void filterWhiteWyrm_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"FilterWyrmGraphics\", filterWhiteWyrm.Checked);\r\n\r\n            if (filterWhiteWyrm.Checked)\r\n            {\r\n                MobileFilter.ApplyToMobiles();\r\n            }\r\n        }\r\n\r\n        private void setSound_Click(object sender, EventArgs e)\r\n        {\r\n            if (cliLocOverheadView.SelectedItems.Count > 0)\r\n            {\r\n                OverheadManager.SetOverheadSound();\r\n            }\r\n        }\r\n\r\n        private void fontIncrease_Click(object sender, EventArgs e)\r\n        {\r\n            foreach (Control c in Controls)\r\n            {\r\n                int size = (int)c.Font.Size;\r\n                c.Font = new Font(\"Segoe UI\", ++size);\r\n                c.AutoSize = true;\r\n\r\n                if (c is Button button)\r\n                {\r\n                    button.AutoSizeMode = AutoSizeMode.GrowAndShrink;\r\n                }\r\n            }\r\n        }\r\n\r\n        private void fontDecrease_Click(object sender, EventArgs e)\r\n        {\r\n            foreach (Control c in Controls)\r\n            {\r\n                int size = (int)c.Font.Size;\r\n                c.Font = new Font(\"Segoe UI\", --size);\r\n                c.AutoSize = true;\r\n\r\n                if (c is Button button)\r\n                {\r\n                    button.AutoSizeMode = AutoSizeMode.GrowAndShrink;\r\n                }\r\n            }\r\n        }\r\n\r\n        \r\n\r\n        private void subAdvancedTab_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (itemTree.Nodes.Count == 0)\r\n            {\r\n                RedrawItems();\r\n            }\r\n\r\n            if (doorTree.Nodes.Count == 0)\r\n            {\r\n                StaffToolsManager.LoadDoors(doorTree);\r\n            }\r\n        }\r\n\r\n        private void itemTree_AfterSelect(object sender, TreeViewEventArgs e)\r\n        {\r\n            if (e.Node.Tag != null)\r\n            {\r\n                artViewer.ArtIndex = (int)e.Node.Tag;\r\n            }\r\n        }\r\n\r\n        private void itemAdd_Click(object sender, EventArgs e)\r\n        {\r\n            //string command = \"[add static 7893 set movable False hue 0 light Circle225\";\r\n            ItemAddCommand(null, null);\r\n        }\r\n\r\n        private ContextMenuStrip _itemAddContextMenu = null;\r\n\r\n        private void itemAdd_MouseDown(object sender, MouseEventArgs e)\r\n        {\r\n            if (e.Button == MouseButtons.Right && e.Clicks == 1)\r\n            {\r\n                if (_itemAddContextMenu == null)\r\n                {\r\n                    _itemAddContextMenu = new ContextMenuStrip();\r\n                    _itemAddContextMenu.Items.Add(\"Single\", null, ItemAddCommand);\r\n                    _itemAddContextMenu.Items.Add(\"Self\", null, ItemAddCommand);\r\n                    _itemAddContextMenu.Items.Add(\"Multi\", null, ItemAddCommand);\r\n                    _itemAddContextMenu.Items.Add(\"Contained\", null, ItemAddCommand);\r\n                    _itemAddContextMenu.Items.Add(\"Area\", null, ItemAddCommand);\r\n                    _itemAddContextMenu.Items.Add(\"Region\", null, ItemAddCommand);\r\n                    _itemAddContextMenu.Items.Add(\"Online\", null, ItemAddCommand);\r\n                    _itemAddContextMenu.Items.Add(\"Global\", null, ItemAddCommand);\r\n                }\r\n\r\n                _itemAddContextMenu.Show(itemAdd, new Point(e.X, e.Y));\r\n            }\r\n        }\r\n\r\n        private void ItemAddCommand(object sender, EventArgs e)\r\n        {\r\n            \r\n            if (itemTree.SelectedNode != null)\r\n            {\r\n                TreeNode selectedNode = itemTree.SelectedNode;\r\n\r\n                if (selectedNode.Tag == null)\r\n                {\r\n                    return;\r\n                }\r\n\r\n                string command = itemRandomNumber.Value > 0\r\n                    ? $\"[add static {selectedNode.Tag} {itemRandomNumber.Value:F0} set movable {itemMovable.Checked}\"\r\n                    : $\"[add static {selectedNode.Tag} set movable {itemMovable.Checked}\";\r\n\r\n                if (itemAppendM.Checked)\r\n                {\r\n                    command = $\"[m {command.Substring(1)}\";\r\n                }\r\n\r\n                if (sender == null)\r\n                {\r\n                    World.Player.SendMessage(MsgLevel.Info, $\"Command: {command}\");\r\n                    World.Player.Say(command);\r\n                }\r\n                else\r\n                {\r\n                    ToolStripMenuItem item = sender as ToolStripMenuItem;\r\n\r\n                    switch (item?.Text)\r\n                    {\r\n                        case \"Single\":\r\n                            command = $\"[single {command.Substring(1)}\";\r\n                            break;\r\n                        case \"Self\":\r\n                            command = $\"[self {command.Substring(1)}\";\r\n                            break;\r\n                        case \"Multi\":\r\n                            command = $\"[multi {command.Substring(1)}\";\r\n                            break;\r\n                        case \"Contained\":\r\n                            command = $\"[contained {command.Substring(1)}\";\r\n                            break;\r\n                        case \"Area\":\r\n                            command = $\"[area {command.Substring(1)}\";\r\n                            break;\r\n                        case \"Region\":\r\n                            command = $\"[region {command.Substring(1)}\";\r\n                            break;\r\n                        case \"Online\":\r\n                            command = $\"[online {command.Substring(1)}\";\r\n                            break;\r\n                        case \"Global\":\r\n                            command = $\"[global {command.Substring(1)}\";\r\n                            break;\r\n                    }\r\n\r\n                    World.Player.SendMessage(MsgLevel.Info, $\"Command: {command}\");\r\n                    World.Player.Say(command);\r\n                }\r\n\r\n\r\n                if (itemCopyToClipboard.Checked)\r\n                {\r\n                    Clipboard.SetDataObject(command, true);\r\n                }\r\n            }\r\n        }\r\n        \r\n        private void itemTree_MouseDoubleClick(object sender, MouseEventArgs e)\r\n        {\r\n            if (World.Player == null)\r\n            {\r\n                return;\r\n            }\r\n\r\n            if (itemTree.SelectedNode != null)\r\n            {\r\n                ItemAddCommand(sender, e);\r\n            }\r\n        }\r\n\r\n        private void itemTile_Click(object sender, EventArgs e)\r\n        {\r\n            //[TileZ 0 static 7894 set movable True hue 0 light {light}\r\n            if (World.Player == null)\r\n            {\r\n                return;\r\n            }\r\n\r\n            if (itemTree.SelectedNode != null)\r\n            {\r\n                TreeNode selectedNode = itemTree.SelectedNode;\r\n                string command = $\"[tilez {itemTileCount.Value:F0} static {selectedNode.Tag} {itemRandomNumber.Value:F0} set movable {itemMovable.Checked.ToString()}\";\r\n\r\n                World.Player.SendMessage(MsgLevel.Info, $\"Command: {command}\");\r\n                World.Player.Say(command);\r\n\r\n                if (itemCopyToClipboard.Checked)\r\n                {\r\n                    Clipboard.SetDataObject(command, true);\r\n                }\r\n            }\r\n        }\r\n\r\n        private void doorTree_AfterSelect(object sender, TreeViewEventArgs e)\r\n        {\r\n            if (e.Node.Tag != null)\r\n            {\r\n                doorViewer.ArtIndex = ((DoorInfo)e.Node.Tag).BaseId;\r\n            }\r\n        }\r\n\r\n        private void doorWestCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo) doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"WestCW\");\r\n            }\r\n        }\r\n\r\n        private void doorWestCCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"WestCCW\");\r\n            }\r\n        }\r\n\r\n        private void doorNorthCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"NorthCW\");\r\n            }\r\n        }\r\n\r\n        private void doorNorthCCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"NorthCCW\");\r\n            }\r\n        }\r\n\r\n        private void doorEastCCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"EastCCW\");\r\n            }\r\n        }\r\n\r\n        private void doorEastCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"EastCW\");\r\n            }\r\n        }\r\n\r\n        private void doorSouthCCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"SouthCCW\");\r\n            }\r\n        }\r\n\r\n        private void doorSouthCW_Click(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                StaffToolsManager.AddDoor((DoorInfo)doorTree.SelectedNode.Tag, \"SouthCW\");\r\n            }\r\n        }\r\n\r\n        private void DoorFacingEnter(object sender, EventArgs e)\r\n        {\r\n            if ((DoorInfo)doorTree.SelectedNode?.Tag != null)\r\n            {\r\n                Button button = sender as Button;\r\n\r\n                doorViewer.ArtIndex = ((DoorInfo)doorTree.SelectedNode.Tag).BaseId + StaffToolsManager.GetDoorOffset(button.Name);\r\n            }\r\n        }\r\n        private void itemSearch_KeyDown(object sender, KeyEventArgs e)\r\n        {\r\n            if (sender is TextBox textBox)\r\n            {\r\n                if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)\r\n                {\r\n                    e.Handled = true;\r\n                    e.SuppressKeyPress = true;\r\n                    itemTree.Focus();\r\n                }\r\n            }\r\n        }\r\n\r\n        private void itemSearch_LostFocus(object sender, EventArgs e)\r\n        {\r\n            if (itemSearch.Text != string.Empty)\r\n            {\r\n                string search = itemSearch.Text.ToLower();\r\n\r\n                itemTree.SafeAction(s =>\r\n                {\r\n                    s.BeginUpdate();\r\n                    s.Nodes.Clear();\r\n\r\n                    foreach (TreeNode node in _itemTreeCache.Nodes)\r\n                    {\r\n                        TreeNode[] nodes = FindNodeByString(search, node);\r\n\r\n                        s.Nodes.AddRange(nodes);\r\n                    }\r\n\r\n                    s.EndUpdate();\r\n                });\r\n            }\r\n            else\r\n            {\r\n                RedrawItems();\r\n            }\r\n        }\r\n\r\n        private TreeNode[] FindNodeByString(string search, TreeNode parentNode)\r\n        {\r\n            List<TreeNode> filteredNodes = new List<TreeNode>();\r\n\r\n            foreach (TreeNode currentNode in parentNode.Nodes)\r\n            {\r\n                if (currentNode.Text.Contains(search))\r\n                {\r\n                    filteredNodes.Add((TreeNode) currentNode.Clone());\r\n                }\r\n\r\n                if (currentNode.Nodes.Count > 0)\r\n                {\r\n                    TreeNode[] nodes = FindNodeByString(search, currentNode);\r\n\r\n                    if (nodes.Length > 0)\r\n                    {\r\n                        filteredNodes.AddRange(nodes);\r\n                    }\r\n                }\r\n            }\r\n\r\n            return filteredNodes.ToArray();\r\n        }\r\n\r\n        private void playEmoteSound_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"PlayEmoteSound\", playEmoteSound.Checked);\r\n        }\r\n\r\n        private void showBuffDebuffGump_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBuffDebuffGump\", showBuffDebuffGump.Checked);\r\n        }\r\n\r\n        private void showBuffIcons_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBuffDebuffIcons\", showBuffIcons.Checked);\r\n        }\r\n\r\n        private void buffBarSort_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (buffBarSort.SelectedIndex < 0)\r\n                return;\r\n\r\n            Config.SetProperty(\"ShowBuffDebuffSort\", buffBarSort.SelectedIndex);\r\n        }\r\n\r\n        private void buffBarWidth_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBuffDebuffWidth\", Utility.ToInt32(buffBarWidth.Text, 100));\r\n        }\r\n\r\n        private void buffBarHeight_TextChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"ShowBuffDebuffHeight\", Utility.ToInt32(buffBarHeight.Text, 28));\r\n        }\r\n\r\n        private void useBlackBuffDebuffBg_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"UseBlackBuffDebuffBg\", useBlackBuffDebuffBg.Checked);\r\n        }\r\n\r\n        private void showBuffDebuffTimeType_SelectedIndexChanged(object sender, EventArgs e)\r\n        {\r\n            if (showBuffDebuffTimeType.SelectedIndex < 0)\r\n                return;\r\n\r\n            Config.SetProperty(\"ShowBuffDebuffTimeType\", showBuffDebuffTimeType.SelectedIndex);\r\n        }\r\n\r\n        private void defaultScriptDelay_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DefaultScriptDelay\", defaultScriptDelay.Checked);\r\n            \r\n            ScriptManager.ResetTimer();\r\n        }\r\n\r\n        private void enableHighlight_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"EnableHighlight\", enableHighlight.Checked);\r\n        }\r\n\r\n        private void disableScriptStopwatch_CheckedChanged(object sender, EventArgs e)\r\n        {\r\n            Config.SetProperty(\"DisableScriptStopwatch\", disableScriptStopwatch.Checked);\r\n        }\r\n\r\n        private void cooldownHeight_TextChanged(object sender, EventArgs e)\r\n        {\r\n            int height = Utility.ToInt32(cooldownHeight.Text, 28);\r\n\r\n            if (height < 1)\r\n            {\r\n                height = 28;\r\n            }\r\n\r\n            Config.SetProperty(\"CooldownHeight\", height);\r\n        }\r\n\r\n        private void cooldownWidth_TextChanged(object sender, EventArgs e)\r\n        {\r\n            int width = Utility.ToInt32(cooldownWidth.Text, 110);\r\n\r\n            if (width < 1)\r\n            {\r\n                width = 110;\r\n            }\r\n\r\n            Config.SetProperty(\"CooldownWidth\", width);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "Razor/UI/Razor.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <metadata name=\"m_NotifyIcon.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\r\n    <value>17, 17</value>\r\n  </metadata>\r\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\r\n  <data name=\"m_NotifyIcon.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        AAABAAEAICAAAAAAAACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAQAAAAAAAAAAAAAAAEAAAAB\r\n        AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYW\r\n        FgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAA\r\n        MwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm\r\n        /wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/\r\n        zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNm\r\n        ZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM\r\n        /wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYz\r\n        mQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbM\r\n        MwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkz\r\n        MwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnM\r\n        AACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwA\r\n        mQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZ\r\n        MwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/\r\n        zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9m\r\n        zADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/\r\n        ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKy\r\n        sgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//\r\n        AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK\r\n        CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCrcKCgoKCgoKCgoKCgoK\r\n        CgoKCgoKCgoKCgoKCgoKCgoK+QoKCgoKCgoKCgrSCgoKCgoKCgoKCgoKCgoKCgoKCgr5+QoKCgoKCgr5\r\n        sQoKCgoKCgoKCgoKCgoKCgoKCgoKCvn5CgoKCgoKsbEKCgoKCgoKCgoKCgoKCgoKCgoKCgoK+ZQKCgoK\r\n        CuPjCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr5sQoKCgpHsQoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgpq\r\n        Cgr5QbEKCgqxtwoKCgoKCgr5CgoK+QoKCgoKCgoKCuP5lPmUCgoKCrGxt7f5+fkKCvkK+fkKCgoKCgoK\r\n        CgoKFkH5lAoK+QoK+bcKCgr5t7cK+fn5CgoKCgoKCgoKCrdB+fkKCgoK0rext7EKCvn5Crf5+QoKCgoK\r\n        CgoKCgqx+UdBCgoKCgq3+fkKt5QK+fkK0vn5CgoKCgoKCgoKCgq3+UGUCgoKCvmxtwoKsbcK+QqUCvn5\r\n        +QoKCgoKCgoKCgr5F0f5CgoKCmqxCgoKavn5+eP5arexagoKCgoKCgoKCgqU+Wrj+QoKt7cKRmlq+Qq3\r\n        lJQXF+MWCgoKCgoKCgoKCvn5+flq4/kKCuvs7O0KCgoKCgoKCgoKCgoKCgoKCgoKCkfjCgoWRxaSku3s\r\n        7OwKCgoKCgoKCgoKCgoKCgoKCgoK+fkKCgr5bpKS7e3t7eztCgoKCgoKCgoKCgoKCgoKCgr5+ZQKCgqS\r\n        kpLt7e3t7e3tCgoKCgoKCgoKCgoKCgoKCgr54woK7++SkpLt7e3t7Ozs7fcKCgoKCgoKCgoKCrHjFkEX\r\n        FhZpku/3kpLt7e3s7Ozs7JIKCgoKCgoKCgoKR/n5+fn5+fkg7e+SkpLt7Ozs7Ozs7ZIKCgoKCgoKCgpH\r\n        QUFBQUcXahbt95KS7e3s7Ozs7Oztkvf3CgoKCgoKCgoKCgrs6+wKCpKS7e3t7Ozs7Ozt7ZL39+/vCgoK\r\n        CgoKCgoKCuzr6uzs7ZLt7ezs7Ozs7ZKS9+/v7+/vCgoKCgoKCgrr7JLrbeyS7ezs7Ozs7ZKS9/fv7wcH\r\n        BwcKCgoKCgoK7BLs7/fs7Ozs7Ozs7O2S9+/v7+8HBwcHBwoKCgoKCgoSbe8H7+zt7Ovs7O2Skvfv7+8H\r\n        BwcHBwcHCgoKCgoK7ezv7++S7O3v9+zs9/fv7+8HBwcHBwcH8fAKCgoKCuwS6+ztkvfv7+8HB/f3B7y8\r\n        vPDw8PDwvPP/8/////////////////f////3/v//8/n///Pz///z5///88////sc/u/4PAaf+GziP/Dw\r\n        ZH/h8SR/8PGVH/h5wA/8GQgP/AYf//5gD//+cAP//jgB//8wAD/4AAAf+AAAD/gAAAP/jAAB/4AAAP8A\r\n        AAD+AAAA/gAAAPwAAAD4AAAA\r\n</value>\r\n  </data>\r\n  <data name=\"scriptEditor.ServiceColors\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n    <value>\r\n        AAEAAAD/////AQAAAAAAAAAMAgAAAFdGYXN0Q29sb3JlZFRleHRCb3gsIFZlcnNpb249Mi4xNi4yMy4w\r\n        LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWZiOGFhMTJiOTk0ZWY2MWIMAwAAAFFTeXN0\r\n        ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2Vu\r\n        PWIwM2Y1ZjdmMTFkNTBhM2EFAQAAACJGYXN0Q29sb3JlZFRleHRCb3hOUy5TZXJ2aWNlQ29sb3JzBgAA\r\n        ACg8Q29sbGFwc2VNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxDb2xsYXBzZU1hcmtlckJh\r\n        Y2tDb2xvcj5rX19CYWNraW5nRmllbGQqPENvbGxhcHNlTWFya2VyQm9yZGVyQ29sb3I+a19fQmFja2lu\r\n        Z0ZpZWxkJjxFeHBhbmRNYXJrZXJGb3JlQ29sb3I+a19fQmFja2luZ0ZpZWxkJjxFeHBhbmRNYXJrZXJC\r\n        YWNrQ29sb3I+a19fQmFja2luZ0ZpZWxkKDxFeHBhbmRNYXJrZXJCb3JkZXJDb2xvcj5rX19CYWNraW5n\r\n        RmllbGQEBAQEBAQUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5EcmF3aW5nLkNvbG9yAwAA\r\n        ABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5E\r\n        cmF3aW5nLkNvbG9yAwAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAACAAAABfz///8UU3lzdGVtLkRy\r\n        YXdpbmcuQ29sb3IEAAAABG5hbWUFdmFsdWUKa25vd25Db2xvcgVzdGF0ZQEAAAAJBwcDAAAACgAAAAAA\r\n        AAAAlgABAAH7/////P///woAAAAAAAAAAKQAAQAB+v////z///8KAAAAAAAAAACWAAEAAfn////8////\r\n        CgAAAAAAAAAAjQABAAH4/////P///woAAAAAAAAAAKQAAQAB9/////z///8KAAAAAAAAAACWAAEACw==\r\n</value>\r\n  </data>\r\n  <data name=\"doorSouthCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgEBAgICBAQEBQQDBgQDBgUEBgYGBwYGBwcGCAcGCQcFCQcGCAgICQgGCQg\r\n        HCggGCQkICgkICwkHCgoKDAoIDAoJCwsLDAsKDAwMDgwKDgwLEAwJDg0MEA0LDg4ODw4NEA4MEA4NEg4\r\n        KDw8PEg8MEBAQERAOFBAMFBANEhEQFBEOFVENEhIREhISFlENFBIRFlINFlIPFBMSGFMOFBQUF1QQGFQ\r\n        QFlVUGlVQFlZWWlVRG1VQGFZUGFdVXFZQGFhYXVdSGlhWXFhTGllYWllZXVlUGlpaYFlTHFxcYVtUHVx\r\n        aXl1cY1xVX11bXl5eX19fZV5WZV5XYmBeZ19XYWFhY2JgaWFZY2Nja6NaZWVlbaRbZmZla6VfbaVcbqV\r\n        bZ2dmZ2dnaqhmcaddaWlpcqhea6qqs6lfa6urrKysr6yqra2tt6yhdK2leKyhd62ib6+vuK6jcbGxuq+\r\n        kd7Cne6+je7Cke7ClebGpc7OzvbGld7SxtbW1v/Omf/Ond7e3v/atuLi4ubm5urq6u7u7v/u4vb29v//\r\n        /wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wAPCRxIsKDBgwgPysFRRFDChxAj\r\n        Sjy0xsOVKBv+TNzIkSAWgmtW6OnTh82JQB1TRmSyw4rAkCNJAtojQqPKmwZnZLljBSbJPoAK+WEjwRDO\r\n        owIJiTgTZ0LMPjKm+CGZQwtSpIQiEIjxo06dIQjK/EyB5urRkG76KAkQQMKbn15UmMXpk2QbH1NJeoFh\r\n        dG7KukALvbiil6/fvyJ/BvWjh8OYvX0PbwS8mCQbCCoiS5ZIWShcECQ0b37YOW8fyGGAjI5YGq7hQ0es\r\n        rkbYunBkQQ1Ez6aYWKZn2wWfVNkNsndg05ANGmrgkHjt068NYkni3Hhl4AiXNx/9PPnD6au7R/9PaGiA\r\n        7qvizx90sUZy+o1ajhx+v/FPA7/0OVLgYzY/R+EqyUHIQP5xBIcJKbWggQgDFsiRfSktMccZIphh3W/Q\r\n        qbcRACqJMQcVDjx1XYZXHbAdR04s8IViGHqHVAZ5IIYEDSThIQQKW2B3FXsd+YRCE4BY0EQWI1Dh4lVA\r\n        hMFRXVFAoAYHP8XQgYYqQQHFRmQYV0IPdhTwlA1gHBbbRIYYUMdPRijw1hk0/nRDmHPVUJZEeVTwUxcD\r\n        vEVSECz81Mebc30gx0YYnHGca1zc4CegVzVgk0R/hEBHi4aBoaibcB4lAJUG/YGDniQKZOmimapEyAAp\r\n        RXqFHlKMd8iomOKUxAcFKnkaABHnwUoSoymBN5quf5a6EY+rAcsrmebtZqywEKFRA3GvXrorswklCW20\r\n        pE7k6LXYxgqRHB9wK6q0wUIkp7jjZovQgegOtCxCMLbrLrnHCuSsvAS9S1C8+M6r7iFk6NBvQe/+kcGA\r\n        A+dLrgdpfMBfwgRLe8UDc0Ic8Zk8uGAxQmAYwEACCG9s0CAXcGpQQAA7\r\n</value>\r\n  </data>\r\n  <data name=\"doorSouthCCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgEBAgICAwMCBAQDBAQEBQQDBgQDBQUEBgUEBgYGBwYFCAYECAYFBwcHCAc\r\n        GCQcFCAgICggGCgkICwkIDAkHCgoKCwsKDAsKDgsIDAwMDgwJDgwKDwwJEQ0KDg4ODw4NEA4MEA4NEQ8\r\n        NEBAQERAPFBAMFVAMEhEQFBEOEhISFlENFBIQFVIOFBIRFlIOFBMSF1MOGFMOFBQUGFMPGFQQFlZWW1Z\r\n        QF1dWW1ZRGFdWWFhYWlhWXlhSGlpaX1lTHlpVXFtbX1tWXFxcYVtUHVxcYFxXYVxXY11VXl5eZF1WX19\r\n        fZV5XZl9XYWBgZ19XYWFhY2FfYmJiY2JgaWFZY2NjZWNgZGRkZmRia6NaZWVlbaRbbaVcZ2dmZ2dnbad\r\n        gaqhmcKddcaddaWlpbKlncqhea6qqs6lfcKqia6urtKqgdaugba2ttqugd6yhca6rt62ib6+vua6icLC\r\n        wsbGxuq+kd7Cne6+je7Clc7OzvbGlfbKldLS0uLSxtbW1v/Omf/Ond7e3v/atuLi4ubm5vbm2urq6u7u\r\n        7v/u4vb29v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wAVCRxIsKDBgwgTKlzIsKHDhxAj\r\n        SpxIsaLFixgzatzIsWPEPHHoeKwYZ8kMEhoAANBA4oNKCyRULEkzMiEhLzYKkJgZJ89BP3HYmBQwQ0ug\r\n        mooSafmgYMeYQxETpfERQQMUqAsTiXToxYKPrRfzJLFQJVFCNgk4TDiqMI2FHWw3EhpiwctBNinu/FkT\r\n        Im7BOB9m+EEaaIcFmgPx6vnD2I4OvwKhkACLVJGfGT4EKmb8RxAiOH0HJrKRpPJBLSTMpFjMGA0iQH+y\r\n        wBA4x8EV0wilDCjDGQiBPYz1BFDkxECOB11wF8TbJkOWP0cewOGMJIgXBGcY10iuXNFmPSaMJP9gwpmL\r\n        i0RxLmTXzt30ZsaCyBwQw9i8WUVjXnD+s939as6eAUKEDH/YR1AXNezXX03vdfYaYz10cJ5BCCrYHkcN\r\n        BsiZB0pEgVCFnC24UYYP1sfBFnhM8WGCIV54EYmw1eeCISKcoQYOK1qYEYzlTXgIBg/wkRCI7L34H3wl\r\n        FjjhQ0Ty5yJEPMp4H0RNigjlkQ7GqOSUEVX55EJRbmmRlw+FaeBFZDJk5pIYpXkWlhpKyZGbBq3JpUZ0\r\n        JgZnkmd6lKedlbkJqGlkDopblUXsqWWfyjV5QhMA8slmd4o0uQIVWfZ4J6Vd6MeYGwzEKSaly20QA2Ny\r\n        NFDIopOS6t1qT0iJ8EMFVrC6KaXvrSHEG7a6SlCDX/CAqZy+ChQHB6z9IQQAK0gggx43oHArpTA8x1gL\r\n        C0z3hxIQ0AACVsUqEgQS8GERRnkj1HGGCOD6eggLbohqHxh1/LBEuAIFUkIfvSqCBQWQ+RpICG4QK9Ag\r\n        +BIUyAQ0vCBtwgol4sUYEFds8cUYZ6zxxhwTFBAAOw==\r\n</value>\r\n  </data>\r\n  <data name=\"doorEastCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgEBAgICBAMCBAQEBQQEBgQDBgUEBgYGCAYFCAcGCAgICggGCggHCgkICwk\r\n        HCgoKCwoJDAoIDAoJDAsKDgsIDAwMEAwJDw0LEA0LEQ0KDg4OEA4MEQ4KEA4NEQ4LEA8OEg8MEBAQFBA\r\n        MFBANExEQFBEOEhISFBIRFlINFlMQF1MOFBQUGFMPGFQRGlQPFlZVVlZWWlVRF1ZVV1ZWWlZTG1ZRGFd\r\n        WXFZRHFdSGFhYXVhSHlhTG1lXXFlXWlpaX1lTH1pUHFtbXFxcYVtUH1xYX11aXl5dY11VXl5eYl1ZYF5\r\n        bX19eX19fZl9YYWFgYWFhZ2BYaWFZZWJfY2Nja6NaaWRfZWVlbaRbZmZmbaVcZ2dnb6ZcaWhncaddaWl\r\n        pc6lfa6ursKqkdaugba2tt6yhc62neKyhca6qr6+vuK6jea6icbGxu6+jc7OzvbGld7OvvrKmdbW1v/O\r\n        md7e3vbauu7eyuLi4ubm5v/iwu7u7v/u2vb29v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wD7CBxIsKDBgwgTKlzIsKHDhxAj\r\n        SpxIsaLFixgzatzIsWNGOWnYeKzIpgkLERYAAIAgYoPKBSJENAnDZyRCPV9iENgwM42bg3TSpDEp4MQV\r\n        OhPl6Gm4ZQOBGF+WRiTzYwGEJlIZ6gHR4MAThWEW6BCJUU6TBVBqKtTjgcucNzyYHCRjgQVSjnqSLKCS\r\n        UA8MM3MCzwkidyAbESd+2sQzZMEXg2zB7MkjeHDhKxvS2CxIJ4YOtQKFIAm8R0zlIEd+/NiMcIsIPAMV\r\n        lBGsQIXgNQlOsE5IBkEWgVRyCG4zocYcMBW8EN5tkIwCGw9mCLwRRTAYAEoqzLbMfCAZE2/eFv8YMr36\r\n        2wFT6pwuvPt7+LcKwgykPofIizmT17cHL5jHV4I3aJCCYPkJtpxN7hnI3kBdSMFAZQUGdmBHCUq4oEBd\r\n        qFHGAU5ASJmCFPJnoUFJaFEGB3TQR+CHI2pUIXcG3UGBAnepSBqLMF704oQM2YgfjjxOtOOFPZp3o34U\r\n        DTmRjxHmCJGSFDEJJJELQVmRlEg2ZKVFWILI0JYXddkibyI6mZGYZhIEpkZoBinQmhu1eSGcHMnpXZlu\r\n        jmQnnXoa+eNpNOBJJWtiYtHBe2l2h6UXFyCaZ3d9SDlCFYLtMCikkfq5RwZuzQHEB5di6iMaEgBxARCJ\r\n        YlpeZXAU0WmqqtpxyIUPVmSpakEzrNAGEQaMEIALlclwxa0F8YFCCwwMOEcbEWAg2BgOEDuQsVrEwYGR\r\n        ZyzxIRcgSCtQGCTEYUSmHrbBgWLS6kFBD/P5aUcJ6Hp7R0EqmhuvtwfdEAIODtyL71xUwPbvwAQXbPDB\r\n        CCeMcEAAOw==\r\n</value>\r\n  </data>\r\n  <data name=\"doorEastCCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgICBAQEBgQDBgUEBgUFBwUEBgYGBwYFCAYECAcGCAcHCQcFCAgICggGCgg\r\n        HCgkIDAkHCgoKDAoIDQsJDgsIDAwMDQwMDgwKDwwKEAwJDg0MDw0LEA0LDg4ODw4NEA4LEA4MEA4NEQ4\r\n        LEg4KEw8LEBAQFBANEREREhEQExEPFBEOFVENEhISFlENFBIRFVMSFlMQFlMRGFMOFBQUGFMPF1QRGlQ\r\n        PGFVRFlZWV1ZVXFZQGFdWWVdVWFhYXVdSGllYXlhTHllUH1lTH1pUHFxcYVtUH1xZX11aY1xVXl5dXl5\r\n        eZF1XX19eX19fZV5XY2BcYWFgYWFhZ2BYYmJiaWFZZmJdY2NjbaRbbaVca6ZhZ2dnb6Zda6djaWhncad\r\n        daWlpc6lfa6urtaugba2tt6yhb6+vs6+quK6jea6ida+ocbGxu6+jcrKys7OzvbGlebKrvrKmdbW1v/O\r\n        me7Stt7e3vbexubm5v/iwv/mzu7u7vb29v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wD5CBxIkKAeJynEFFzIsKHDhxD1\r\n        iBiC5UQTiBgzajSYIsycj0QuDqSyZ6PJjRLP4PkIUqQXJilOyoS44cucPCtZhvSCpoyCmUAXrsHAsgsH\r\n        lnMycCkTok7QpwLrKGDJhkKMMm+SlDCAwClUqECeUMUAYMCMOW+EiPz6lMcUpEe0IA3JFqrbj1802MnZ\r\n        sm7bKWkqlLnJdw5dv0B1OLD5EefctYhN+vjwlqVjnZAjY7xShM9dy4UPa4ZoxsTAz41DZx690IIbgqgJ\r\n        P2bdUAyNhbEv96Vd0DXD3Kp5DwSTwyHw2bz3NLjz8Dhm3pwxOt892rf0yqmRR67TYON0w6u/bv/xYfK7\r\n        6Lo0FJbHLvt53T0CSp40H34mmRZA6bMtciWofoF7mDFTC2T8hZRu4PGxxwsdbKDHSdb5xx6CRCjxQhZx\r\n        9CDTAczZNWFhIPwQBxIzAVDXdGMwoMJMdxzg12dhuCCDGh8lwcJ5GrlhAWJuYVFBFVU8AAcWCVCnUWmR\r\n        pUDCGx/tAAUON7h3pGl+kbECkx9FEAYUBGiHEXdVXsnSEEPMwQYGNiA1wWsZ7RFAXVZiOccPLLD0BgRW\r\n        sFTDFhsJ8CBUcWJ2HBsK/JmRBHIAKuZuudERApsamSBgUIEaiRobMECqkQ98AlVpggXxMEQaXzwq03ie\r\n        LgrqQk4U4CCLLsp49CmOiEWo0az11eWEEybhKtwaHmzkq3B8cJjRsMTyhxGyxN7RgHwNMUssH8pGqyqt\r\n        zT7LkLTTCrSEFAtx262CyxEk7rh8RCfQuejyQSAf7LarhwVtKCAntu0SJMcCRkiZr0NLjPBRELn+S9AF\r\n        BBAQhcEaoTDpuAEBADs=\r\n</value>\r\n  </data>\r\n  <data name=\"doorNorthCCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgEBAgICBAMCBAMDBAQEBgQDBgUFBgYGBwYFCAcFCAcGCAgHCAgICQgGCgg\r\n        GCgkIDAkHCgoKDAoJDAsKDgsIDAwMDgwKDgwLDQ0NEA0KDg4OEA4MEA4NEQ8MEA8PEg8MEBAQERAOFBA\r\n        MEhEQFBEOEhISFlENExIRFBIRFVIPFlIOFBMSFBMTGFMOFBQUFlQSFlVTGlQPFlZWWlZSHFZQGFdWXFZ\r\n        RG1dTHFdSGFhYXVdSGlhWXlhSGllZWlpaX1lTHFpZX1pUHFtaXFtbYVpUHFxcYVtUHl1cX11aY1xVY11\r\n        VXl5eY11WX19eX19fZV5WZ19XYWFgYWFhZ2BYaWFYY2Nja6NaZWVkZWVlbKRabaRbZ2ZmbaVcZ2dncad\r\n        daWlpcahecqhea6urs6qhbKyrra2trq2ts6yldKyld6yhd62ib6+vua6ieq6ic7CtsbGxt7Cne6+je7C\r\n        kerGpc7OzvbGldLS0vrKmdbW1v/Omf/Ond7e3v/atu7i0ubm5u7u7v/u4vb29v///wAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wAHCRxIsKDBgwgTKlzIsKHDhxAj\r\n        SpxIsaLFixgzatzIsWNHPh45gjmwgASgkBjNlGijZ0uHkygfouAyUKUdPTjRtIAZc6EZD2TODLKJU0+f\r\n        QGFe9lz4B4MaMlJK3MSZJtAePVB8LF3Ih8MWBVWK4khwVY8cAlsXYlGgZYSMKyUWrCm6hEjahETt1BgA\r\n        Yy7OLikE3T1IFGefN2X1ABY8uGBhPXEmRDCwRXHgxo6lFu3DQ4meNiOKXMZcU7PhQBW+4LSjoQzp0lON\r\n        Wo3ioqidEmZePz5aFkgP27gx77ZatAsFIcBz3x2eeLET5KuDb2VefPTz5Eup/x0t8Hp05SG1W/9mTNC7\r\n        ntvgOYpfjNA8+o7ruR90Lz1jfPIJ6aeveN+h/ov9PfQfRQFCNGBEBUZ0oEMJSrSgQUgMAdtmxG2HH0UP\r\n        DsREDk3YMJRpsjUnn0UZCpQEHlSQACJv1V14UYmDJDHHAG5QKKKLGJVohgM12NgiSg/adEIUIf4Y04FE\r\n        qREAHRWOt5V5bRwgWGFtBBDDbxbeZV4CG7ABQmw0TLDHESPIwd5gTqywxQ4MCEJCZTipIBdOVzzwAY5L\r\n        ebHAByexcIVhQYhR3AcZsIEZHyGMMVAeF8jBooWAhDAFnh6NYUEdBdUhgh83athAFtlZ8AJPBN3BgRxZ\r\n        EvTHDw2AERIcIZhrgGlCdUBwwwok4MnHDBbsZ1EdL3TZ0B9WuLpQHSYgoAMYpEJkhhESWKBoSH94MUMB\r\n        IViRx7DWCmCCtnexAS0AAGwQwgtPpKtDCCEIAICyYFCaFhxsjJHuE16wwYa8r/Xr778AByzwwAQ/FBAA\r\n        Ow==\r\n</value>\r\n  </data>\r\n  <data name=\"doorNorthCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgEBAgICAwMCAwMDBAMDBAQEBgQDBgUEBgYGBwYEBwYFCAYECAYFBwcHCAc\r\n        FCAcGCAgICwkGDAkHCgoKCwoJDAoIDAsKDAwMEAwJDg0MDw0KDg4ODw4NDw4OEA4MEA4NEg4KEg4LEg8\r\n        MEBAQERAOExAMFBANEhEQFBEOEhIREhISFlENFBIRF1IOFlMQFBQUGFZUGlZSHFZQGFdWWFhYXVdRHlh\r\n        SGllYX1hSGlpaX1lSH1lTH1pUHFtbX1tWXFxcXlxaX11aY1xVYV1YXl5eY11WZF1WX19eY15ZX19fZV5\r\n        XZl5XYGBgZ19XYWFhaWFZY2Nja6NaZWVlaqRebaRbZmZma6VfbaVcbqVbZ2dnaGdnb6ZccKddcaddc6l\r\n        fa6urs6qhb6ypba2trq2tsK2qtqyhd6yhca6rt62ib6+vsq+sua6ieq6ic7CtsbGxu6+je7Cje7Ckc7O\r\n        zvbGlfbKlfrKme7OqtbW1v/Omf/Ondra2vbWst7e3v/atubm5vbm2u7u7v/u4vb29v///wAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wAJCRxIsOBALXMMKlzIsKFDhU0Q\r\n        eFDzsKLFiwLHKPjCZcQYjCBDDhzkgEeePHRSfBTJsiKMKBZOolTZsubCJ0UIIekhM+VKm0DHrBi4sydN\r\n        oDYxJCTK86RPpC3BwDBY1OlRqBgHYcCjsOrMn1grRgHC0OvTsA8HRfjT0OxVtAvHPnQLFm5BpRXp2jXY\r\n        J8JFvXsHTtGBEXDgFXXnNv0aeJCBQSENoxXKUjLBNzSeBBIJJEpLy4TGWHByA8RmkIhrSh6Tgs7JLx1O\r\n        X8SrevFZ1q5P+lljGmMCtjbp4pbpR5CeLxcwAoBqdsSG3HlelNFz8gQYi32xmjVR5eSPBV1kWv+3+IZD\r\n        WLMM2FwJkEYmFhQXKYelYUPmDSIxWLhvAdmiGhJhsZbDDHDAMYEbS2RwEhb8YZQdVMMNcQACYlAXQhUM\r\n        9nfRIAJA2JpMfABCXR5xPKCBhhgZIFtLw+lmnEwu7BAGGSJRwFVNLeZR3Ih5vFfCGTOGRAJFLH7oIo8Z\r\n        9vHBEBWsWJEOUxQJ3Y779deHD32EpEUNLOVI5YIN2hSIASJ5+SKYKNbEwRsgmYlkmEgpoQRGblYZ1hwY\r\n        xGekjmf2CCdWEWT5UJ1o2tXZoHt+6WeaWP0RAaMEEbpoYIQcupCkGVJKyB8UOJlRon1mqikhchWE6Z+U\r\n        qgXcp1OGiqqmpYaUBuqbkGoKw3Wn1qqpVlbMaueoC20xQBvEuarrqKxloSCftAJ76YdDzKCoqM6auqcM\r\n        aDRbrbXQJYFAA1AUui1BgxQA3Q8ILCFFCEyIUMGxyI4gExUEtHeSBEcYQcO4BQ0CARt81rFfEHYsgQO/\r\n        BM3xwR3GEiKEGRAgnDANcvxKiAp7SJzwB17QscSrGiesQQA4wGtXQAA7\r\n</value>\r\n  </data>\r\n  <data name=\"doorWestCCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgEBBAMCBAMDBAQEBQQDBgQDBgUEBgYFBgYGBwYEBwYFCAYECAYFCAcGCAg\r\n        ICQgHCggHDAkHCgoKCwoJDAoIDQsIDQsJDgsIDAwMEAwJDg0MEA0KDg4OEA4MEQ8NEg8MEBAPEBAQFBA\r\n        NEhEQFBEOFBEPEhISExISFBIRFBMSGFMOFBQUGFMPGFQRFlVUGlQPGVVQFlZWV1ZVV1dWXFZQGFdWXFZ\r\n        RGVdWXFdSGFhYWllYXlhTGllZWlpaXlpWX1pUHFxcYVtUIVtVYFxZXV1cXV1dXl1cY1xVYV1ZX19eX19\r\n        fZV5WZV5XZl5XYGBgZ19XYWFgYWFhZ2BYaWFZY2NjaqJZa6JZa6NaZWVlaWZjZ2dnbaZeb6ZcbKlmb6q\r\n        kc6lfa6urra2tt6yheKyhb6+vua6icbGxu6+jc7OzvbGlebKruLOvtbW1v/OmebWxt7e3vbauubm5v/i\r\n        wvbm0u7u7v/u2vb29v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wDxCBxIsKDBgwgLypGSsKHDhxAH\r\n        pnlRQEbEixgdpvFAZYyFJxlDityIxo0bLAjgiFwJkaRJNzmMdLjDsuZBlyan2MAThoXNnwJxutE50EcW\r\n        oDWFEh0oJ4McpCM9lMy5s2CVIFAzKq1a8M6Dp1lbSn259ODVsA+3NrwzQSVahGod9nx7cyxViHcI0KQr\r\n        0e5Qrg9ZhOEb1G9ZiFt0EI57Ec4DvowxZkgj8s6WF4PrTv27cskSkS9aUBmhxGDkjGVEZLzTY8pLIKX7\r\n        bj4c0jHGOym8zHnpBnbh2YBXAsD4goobO7tfKzm9MgHYh3AcvGTzgXeMC8CRTo4o58BLMhBcmP8EoyE7\r\n        0hNiLu5o8hKNgyRuDJghG9ymji0Ybbg2KSTCFw0vObFBWJ5lpJ9JNcBAhwBjqIHECr5BZVRI+pFXkhYN\r\n        MFCDSRECJZhIKChAxkt2rMFbhzZ1cEZIaXABBQe8IXdibDY94NZFLaoBAgn7mSSjcj8NlxEFTICQ3oEk\r\n        JschjSLJkUBIdfRQxkBI+qhkb0xqlQFQVR53JYoYncVlj17OKJIIUyLV5Y9LZlRHAnupSSabWGI0V1hr\r\n        fpllQ/e9laeZEDlH159AOnRGB4QR2mZDaBKGh6J1InSno5CCOdB2jgpU6Z6TZvronHoSdEcHlHlKJaiA\r\n        4iGmqafGGGobGcSHyaqmqL5WRAY3ztpqkrw1QIOuBxFaAxKWApsnEzAsCixBXb5hghqFLrtrFxIE8EOq\r\n        0uKxAQZXYEAFFRGI91IFpUqrBA9WNACtG2gscK1JN1SRbRQ8uEHEDD2qIaMaEeSqqwpYEEHTmnGUkF62\r\n        dYQQZ5Vq4HBwtsEOgcYYBkPc0BEDOPCwQwEBADs=\r\n</value>\r\n  </data>\r\n  <data name=\"doorWestCW.Image\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        R0lGODlhPQA9AIcAAAAAAAgICAwICBgQDBgUEBgUFBgYGBwYECAYECAcGCQcFCAgICggGCwkHDAkHCgo\r\n        KCwoJDAoIDAoJDAsKDgsIDAwMDgwKEAwJDg0MDw0KDg4NDg4OEA4MEg8MEg8NEBAQEhEQFBEOFBEPEhI\r\n        SFBIRFlINExMTFBMSGFMOFBQUFlQSFlVUF1VSGlVQFlZWWlVRF1dXXFZQGFdWWldUHFdSGFhYWVlYXlh\r\n        SGllYXlhTGlpaX1lTH1pUIFpUHFxcYVtUIFxZXV1cXl1dY1xVXl5dXl5eX19eX19fZl9XZ19XYWFgYWF\r\n        hZ2BYaGBYY2Nja6NaZWVlbaRbZ2dnbaZeb6ZcbKdicKZdcKddaWlpc6lfa6ursaynba2trq6tt6yhc62\r\n        nb6+vuq6icbGxu6+je7CjcrKyuLGqs7OzvbGldbW1v/Ome7Wvt7e3vbauvbexubm5v/iwv/mzu7u7vb2\r\n        9v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQAAAAAACwAAAAAPQA9AAAI/wDpCBxIsKDBgwgTKlzIsKHDhxAj\r\n        SpxIsaLFixgzatzIsePDN3I8bpwjgwABJSIxziHBRA2aHEZSWrRRRY1NNTxiCiyDYY5MhnNWMIkD5ybO\r\n        mGem/BDyc6ETGjbjmCFzk4eNKWg6gGmq8MSTmxYyoLGZBUGUDly4KoTS4iYaDxGS3LhgpUEQtQtltLQ5\r\n        ZgYBFGNs5sSrUK/RLUWr6iR80HBZCgS+GB3MuHGPC17UZImQWPDiygPPRAjscsCazkdBh+ZAWs2PG2qI\r\n        Tv5M+Azrm0hQ3JStuLLt1kwg7I2KmrLa3zeZyKBjeHdx2imR21Q+sDnx2U2lq6FO0Hrs5zK1c/8v6J23\r\n        Z5HilyMsD55j+rzDv2PX+J4h+/kX6ze839uifof8nUfRfw8FmJpEBEJkoHEOJRjRgtAl5KBEEA7kBA4+\r\n        GTThRBUaQcMQJmh423TqbbQgCDmoAUSGqwFXIkcGKnDFigVtiFGATRxARI0jbveiSPdFcQEaxsnhVXI/\r\n        plReGw58dWANApA2HlfWJaECAFT0p0EJVNCQZFOGxYACGiJ4YNQLUNAxBwwFHKHaCgwMwVcEHNzkRQKh\r\n        VSBGZWlUAMJwYbCQWBYTECTHB0uw2BQUG7DBXHxEoRFCWgTNUcQDUjSlRQU6hCSQd26oQKlBbNTwgBYi\r\n        gbFBCmcY1JykXSxqlEYKG2xF3wgf7LleBztIMOpCYnxgQA1aKAoRFzosUMGvCHFxRBoRvSFFCgGM4ISj\r\n        DLEBBbUjQIEtV1z4sAAAAGzwgQtHpFvDBx+Qu4AOxao2kBhgYJHuEVKAYau8/Pbr778AByzwwBcFBAA7\r\n</value>\r\n  </data>\r\n  <metadata name=\"$this.TrayHeight\" type=\"System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\r\n    <value>63</value>\r\n  </metadata>\r\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        AAABAAIAICAAAAAAAACoCAAAJgAAABAQAAAAAAAAaAUAAM4IAAAoAAAAIAAAAEAAAAABAAgAAAAAAAAE\r\n        AAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAMDAwADA3MAA8MqmAAQE\r\n        BAAICAgADAwMABEREQAWFhYAHBwcACIiIgApKSkAVVVVAE1NTQBCQkIAOTk5AIB8/wBQUP8AkwDWAP/s\r\n        zADG1u8A1ufnAJCprQAAADMAAABmAAAAmQAAAMwAADMAAAAzMwAAM2YAADOZAAAzzAAAM/8AAGYAAABm\r\n        MwAAZmYAAGaZAABmzAAAZv8AAJkAAACZMwAAmWYAAJmZAACZzAAAmf8AAMwAAADMMwAAzGYAAMyZAADM\r\n        zAAAzP8AAP9mAAD/mQAA/8wAMwAAADMAMwAzAGYAMwCZADMAzAAzAP8AMzMAADMzMwAzM2YAMzOZADMz\r\n        zAAzM/8AM2YAADNmMwAzZmYAM2aZADNmzAAzZv8AM5kAADOZMwAzmWYAM5mZADOZzAAzmf8AM8wAADPM\r\n        MwAzzGYAM8yZADPMzAAzzP8AM/8zADP/ZgAz/5kAM//MADP//wBmAAAAZgAzAGYAZgBmAJkAZgDMAGYA\r\n        /wBmMwAAZjMzAGYzZgBmM5kAZjPMAGYz/wBmZgAAZmYzAGZmZgBmZpkAZmbMAGaZAABmmTMAZplmAGaZ\r\n        mQBmmcwAZpn/AGbMAABmzDMAZsyZAGbMzABmzP8AZv8AAGb/MwBm/5kAZv/MAMwA/wD/AMwAmZkAAJkz\r\n        mQCZAJkAmQDMAJkAAACZMzMAmQBmAJkzzACZAP8AmWYAAJlmMwCZM2YAmWaZAJlmzACZM/8AmZkzAJmZ\r\n        ZgCZmZkAmZnMAJmZ/wCZzAAAmcwzAGbMZgCZzJkAmczMAJnM/wCZ/wAAmf8zAJnMZgCZ/5kAmf/MAJn/\r\n        /wDMAAAAmQAzAMwAZgDMAJkAzADMAJkzAADMMzMAzDNmAMwzmQDMM8wAzDP/AMxmAADMZjMAmWZmAMxm\r\n        mQDMZswAmWb/AMyZAADMmTMAzJlmAMyZmQDMmcwAzJn/AMzMAADMzDMAzMxmAMzMmQDMzMwAzMz/AMz/\r\n        AADM/zMAmf9mAMz/mQDM/8wAzP//AMwAMwD/AGYA/wCZAMwzAAD/MzMA/zNmAP8zmQD/M8wA/zP/AP9m\r\n        AAD/ZjMAzGZmAP9mmQD/ZswAzGb/AP+ZAAD/mTMA/5lmAP+ZmQD/mcwA/5n/AP/MAAD/zDMA/8xmAP/M\r\n        mQD/zMwA/8z/AP//MwDM/2YA//+ZAP//zABmZv8AZv9mAGb//wD/ZmYA/2b/AP//ZgAhAKUAX19fAHd3\r\n        dwCGhoYAlpaWAMvLywCysrIA19fXAN3d3QDj4+MA6urqAPHx8QD4+PgA8Pv/AKSgoACAgIAAAAD/AAD/\r\n        AAAA//8A/wAAAP8A/wD//wAA////AAoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK\r\n        CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK\r\n        Cgq3CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCvkKCgoKCgoKCgoK0goKCgoKCgoKCgoKCgoK\r\n        CgoKCgoK+fkKCgoKCgoK+bEKCgoKCgoKCgoKCgoKCgoKCgoKCgr5+QoKCgoKCrGxCgoKCgoKCgoKCgoK\r\n        CgoKCgoKCgoKCvmUCgoKCgrj4woKCgoKCgoKCgoKCgoKCgoKCgoKCgoK+bEKCgoKR7EKCgoKCgoKCgoK\r\n        CgoKCgoKCgoKCgoKCgoKagoK+UGxCgoKsbcKCgoKCgoK+QoKCvkKCgoKCgoKCgrj+ZT5lAoKCgqxsbe3\r\n        +fn5Cgr5Cvn5CgoKCgoKCgoKChZB+ZQKCvkKCvm3CgoK+be3Cvn5+QoKCgoKCgoKCgq3Qfn5CgoKCtK3\r\n        sbexCgr5+Qq3+fkKCgoKCgoKCgoKsflHQQoKCgoKt/n5CreUCvn5CtL5+QoKCgoKCgoKCgoKt/lBlAoK\r\n        Cgr5sbcKCrG3CvkKlAr5+fkKCgoKCgoKCgoK+RdH+QoKCgpqsQoKCmr5+fnj+Wq3sWoKCgoKCgoKCgoK\r\n        lPlq4/kKCre3CkZpavkKt5SUFxfjFgoKCgoKCgoKCgr5+fn5auP5Cgrr7OztCgoKCgoKCgoKCgoKCgoK\r\n        CgoKCgpH4woKFkcWkpLt7OzsCgoKCgoKCgoKCgoKCgoKCgoKCvn5CgoK+W6Sku3t7e3s7QoKCgoKCgoK\r\n        CgoKCgoKCgoK+fmUCgoKkpKS7e3t7e3t7QoKCgoKCgoKCgoKCgoKCgoK+eMKCu/vkpKS7e3t7ezs7O33\r\n        CgoKCgoKCgoKCgqx4xZBFxYWaZLv95KS7e3t7Ozs7OySCgoKCgoKCgoKCkf5+fn5+fn5IO3vkpKS7ezs\r\n        7Ozs7O2SCgoKCgoKCgoKR0FBQUFHF2oW7feSku3t7Ozs7Ozs7ZL39woKCgoKCgoKCgoK7OvsCgqSku3t\r\n        7ezs7Ozs7e2S9/fv7woKCgoKCgoKCgrs6+rs7O2S7e3s7Ozs7O2Skvfv7+/v7woKCgoKCgoK6+yS623s\r\n        ku3s7Ozs7O2Skvf37+8HBwcHCgoKCgoKCuwS7O/37Ozs7Ozs7Oztkvfv7+/vBwcHBwcKCgoKCgoKEm3v\r\n        B+/s7ezr7OztkpL37+/vBwcHBwcHBwoKCgoKCu3s7+/vkuzt7/fs7Pf37+/vBwcHBwcHB/HwCgoKCgrs\r\n        Euvs7ZL37+/vBwf39we8vLzw8PDw8Lzz//P////////////////3////9/7///P5///z8///8+f///PP\r\n        ///7HP7v+DwGn/hs4j/w8GR/4fEkf/DxlR/4ecAP/BkID/wGH//+YA///nAD//44Af//MAA/+AAAH/gA\r\n        AA/4AAAD/4wAAf+AAAD/AAAA/gAAAP4AAAD8AAAA+AAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAA\r\n        AAAAAAAAAAEAAAABAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgI\r\n        CAAMDAwAERERABYWFgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW\r\n        7wDW5+cAkKmtAAAAMwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABm\r\n        ZgAAZpkAAGbMAABm/wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM\r\n        /wAA/2YAAP+ZAAD/zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz\r\n        /wAzZgAAM2YzADNmZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPM\r\n        ZgAzzJkAM8zMADPM/wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYz\r\n        AABmMzMAZjNmAGYzmQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZ\r\n        zABmmf8AZswAAGbMMwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkA\r\n        mQCZAMwAmQAAAJkzMwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZ\r\n        mQCZmcwAmZn/AJnMAACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwA\r\n        AACZADMAzABmAMwAmQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxm\r\n        zACZZv8AzJkAAMyZMwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/\r\n        MwCZ/2YAzP+ZAMz/zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9m\r\n        MwDMZmYA/2aZAP9mzADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/M\r\n        zAD/zP8A//8zAMz/ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaG\r\n        hgCWlpYAy8vLALKysgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD/\r\n        /wD/AAAA/wD/AP//AAD///8ACgoKCgoKCgrt7O2SAAAKCgoKCgoKCgoA7Ozs7O2SAAoKCgoKCgoAkpKS\r\n        7ezs7ZIACgoKCgoKAJKS7e3t7e3tkgoKCgoKAJKSkpLt7e3t7e0KCgoKCgDt95KS7e3t7e3sCgoKCgoA\r\n        AO33kpKS7e3t7AoKCgoKCgoA7/eSku3t7OwKCgoKCgoKAPeSku3t7OzsCgoA7QoKCu33ku3t7ezs7AoK\r\n        7Ozs95LskpLt7Ozs7OwKkuzt623skpLt7Ozs7OzsB23r75Ls6+zt7ezs7OztkuwS7O/vkuzs6+zs7Ozt\r\n        kvfr7O8H7+3skpLr7O2Skvfvkvf395Lt7ffv7+3t7+/v7/8PAAD/AwAA/gEAAP4AAAD8AAAA/AAAAP4A\r\n        AAD/AAAA/wAAAO4AAADAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAA=\r\n</value>\r\n  </data>\r\n</root>"
  },
  {
    "path": "Razor/UI/SoundEntry.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Drawing;\nusing System.IO;\nusing System.Windows.Forms;\nusing Assistant.Filters;\n\nnamespace Assistant\n{\n    /// <summary>\n    /// \n    /// </summary>\n    public class SoundEntry : Form\n    {\n        private Button btnOk;\n        private Button btnCancel;\n\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.Container components = null;\n\n        private int _soundId;\n        private string _soundName;\n        private ComboBox _soundList;\n        private CheckBox _playInClient;\n        private Button _playSound;\n\n        public delegate void SoundEntryCallback(int sound);\n\n        public static SoundEntryCallback Callback = null;\n\n        public int Sound => _soundId;\n\n        public SoundEntry() : this(0, string.Empty)\n        {\n        }\n\n        public SoundEntry(int soundId, string soundName)\n        {\n            _soundId = soundId;\n            _soundName = soundName;\n            //\n            // Required for Windows Form Designer support\n            //\n            InitializeComponent();\n\n            //\n            // TODO: Add any constructor code after InitializeComponent call\n            //\n        }\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                if (components != null)\n                {\n                    components.Dispose();\n                }\n            }\n\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.btnOk = new System.Windows.Forms.Button();\n            this.btnCancel = new System.Windows.Forms.Button();\n            this._soundList = new System.Windows.Forms.ComboBox();\n            this._playInClient = new System.Windows.Forms.CheckBox();\n            this._playSound = new System.Windows.Forms.Button();\n            this.SuspendLayout();\n            // \n            // btnOk\n            // \n            this.btnOk.Location = new System.Drawing.Point(107, 92);\n            this.btnOk.Name = \"btnOk\";\n            this.btnOk.Size = new System.Drawing.Size(52, 35);\n            this.btnOk.TabIndex = 4;\n            this.btnOk.Text = \"&OK\";\n            this.btnOk.Click += new System.EventHandler(this.okay_Click);\n            // \n            // btnCancel\n            // \n            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;\n            this.btnCancel.Location = new System.Drawing.Point(12, 92);\n            this.btnCancel.Name = \"btnCancel\";\n            this.btnCancel.Size = new System.Drawing.Size(52, 35);\n            this.btnCancel.TabIndex = 5;\n            this.btnCancel.Text = \"Cancel\";\n            this.btnCancel.Click += new System.EventHandler(this.cancel_Click);\n            // \n            // soundList\n            // \n            this._soundList.FormattingEnabled = true;\n            this._soundList.Location = new System.Drawing.Point(12, 12);\n            this._soundList.Name = \"_soundList\";\n            this._soundList.Size = new System.Drawing.Size(147, 23);\n            this._soundList.TabIndex = 6;\n            // \n            // playInClient\n            // \n            this._playInClient.AutoSize = true;\n            this._playInClient.Location = new System.Drawing.Point(41, 70);\n            this._playInClient.Name = \"_playInClient\";\n            this._playInClient.Size = new System.Drawing.Size(93, 19);\n            this._playInClient.TabIndex = 8;\n            this._playInClient.Text = \"Play in client\";\n            this._playInClient.UseVisualStyleBackColor = true;\n            // \n            // playSound\n            // \n            this._playSound.Location = new System.Drawing.Point(22, 41);\n            this._playSound.Name = \"_playSound\";\n            this._playSound.Size = new System.Drawing.Size(127, 23);\n            this._playSound.TabIndex = 7;\n            this._playSound.Text = \"Play Selected Sound\";\n            this._playSound.UseVisualStyleBackColor = true;\n            this._playSound.Click += new System.EventHandler(this.playSound_Click);\n            // \n            // SoundEntry\n            // \n            this.AcceptButton = this.btnOk;\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\n            this.CancelButton = this.btnCancel;\n            this.ClientSize = new System.Drawing.Size(174, 142);\n            this.ControlBox = false;\n            this.Controls.Add(this._playInClient);\n            this.Controls.Add(this._playSound);\n            this.Controls.Add(this._soundList);\n            this.Controls.Add(this.btnCancel);\n            this.Controls.Add(this.btnOk);\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\n            this.MaximizeBox = false;\n            this.MinimizeBox = false;\n            this.Name = \"SoundEntry\";\n            this.ShowInTaskbar = false;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\n            this.Text = \"Select a Sound\";\n            this.Load += new System.EventHandler(this.SoundEntry_Load);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n        \n        private void okay_Click(object sender, EventArgs e)\n        {\n            if (_soundList.SelectedIndex > 0)\n            {\n                SoundMusicManager.Sound sound = (SoundMusicManager.Sound)_soundList.SelectedItem;\n\n                _soundId = sound.Serial;\n                _soundName = sound.Name;\n                DialogResult = DialogResult.OK;\n                Close();\n                Callback = null;\n            }\n        }\n\n        private void cancel_Click(object sender, EventArgs e)\n        {\n            DialogResult = DialogResult.Cancel;\n            Close();\n            Callback = null;\n        }\n\n        private void SoundEntry_Load(object sender, EventArgs e)\n        {\n            Language.LoadControlNames(this);\n\n            int selectedIndex = 0;\n            \n            _soundList.BeginUpdate();\n            _soundList.Items.Clear();\n\n            int index = 0;\n            foreach (SoundMusicManager.Sound sound in SoundMusicManager.GetAllSounds())\n            {\n                _soundList.Items.Add(sound);\n\n                if (sound.Name.Equals(_soundName))\n                {\n                    selectedIndex = index;\n                }\n\n                index++;\n            }\n\n            _soundList.SelectedIndex = selectedIndex;\n            \n            _soundList.EndUpdate();\n        }\n\n        private System.Media.SoundPlayer sp = new System.Media.SoundPlayer();\n\n        private void playSound_Click(object sender, EventArgs e)\n        {\n            sp.Stop();\n\n            if (_soundList.SelectedIndex < 0)\n                return;\n\n            SoundMusicManager.Sound sound = (SoundMusicManager.Sound)_soundList.SelectedItem;\n\n            if (_playInClient.Checked && World.Player != null)\n            {\n                Client.Instance.SendToClient(new PlaySound(sound.Serial));\n            }\n            else\n            {\n                Ultima.UOSound s = Ultima.Sounds.GetSound(sound.Serial);\n                using (MemoryStream m = new MemoryStream(s.buffer))\n                {\n                    sp.Stream = m;\n                    sp.Play();\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UI/SoundEntry.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "Razor/UI/SplashScreen.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System.Threading;\r\nusing System.Windows.Forms;\r\n\r\nnamespace Assistant\r\n{\r\n    public class SplashScreen : System.Windows.Forms.Form\r\n    {\r\n        private static SplashScreen m_Screen;\r\n\r\n        public static SplashScreen Instance\r\n        {\r\n            get { return m_Screen; }\r\n        }\r\n\r\n        public static void Start()\r\n        {\r\n            if (m_Screen == null)\r\n            {\r\n                Thread t = new Thread(new ThreadStart(ThreadMain));\r\n                t.Name = \"Razor Splash Screen\";\r\n                t.Start();\r\n                while (m_Screen == null)\r\n                    Thread.Sleep(1);\r\n\r\n                m_Screen.CreateControl();\r\n            }\r\n        }\r\n\r\n        private delegate void CloseDelegate();\r\n\r\n        public static void End()\r\n        {\r\n            if (m_Screen != null)\r\n            {\r\n                if (m_Screen.InvokeRequired)\r\n                    m_Screen.Invoke(new CloseDelegate(m_Screen.Close));\r\n                else\r\n                    m_Screen.Close();\r\n            }\r\n        }\r\n\r\n        private delegate void SetMsgDelegate(SplashScreen screen, string arg);\r\n\r\n        private static void SetMessage(SplashScreen screen, string msg)\r\n        {\r\n            //screen.message.Text = msg;\r\n        }\r\n\r\n        public static string MessageStr\r\n        {\r\n            set\r\n            {\r\n                try\r\n                {\r\n                    if (m_Screen != null)\r\n                    {\r\n                        if (m_Screen.InvokeRequired)\r\n                            m_Screen.Invoke(new SetMsgDelegate(SetMessage), m_Screen, value);\r\n                        else\r\n                            SetMessage(m_Screen, value);\r\n                    }\r\n                }\r\n                catch\r\n                {\r\n                }\r\n            }\r\n        }\r\n\r\n        public static LocString Message\r\n        {\r\n            set { MessageStr = Language.GetString(value); }\r\n        }\r\n\r\n        private static void ThreadMain()\r\n        {\r\n            try\r\n            {\r\n                using (m_Screen = new SplashScreen())\r\n                {\r\n                    Application.EnableVisualStyles();\r\n                    Application.Run(m_Screen);\r\n                }\r\n\r\n                m_Screen = null;\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        public SplashScreen()\r\n        {\r\n            try\r\n            {\r\n                InitializeComponent();\r\n            }\r\n            catch\r\n            {\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            System.ComponentModel.ComponentResourceManager resources =\r\n                new System.ComponentModel.ComponentResourceManager(typeof(SplashScreen));\r\n            this.SuspendLayout();\r\n            // \r\n            // SplashScreen\r\n            // \r\n            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);\r\n            this.BackColor = System.Drawing.Color.White;\r\n            this.BackgroundImage = ((System.Drawing.Image) (resources.GetObject(\"$this.BackgroundImage\")));\r\n            this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;\r\n            this.ClientSize = new System.Drawing.Size(435, 331);\r\n            this.ControlBox = false;\r\n            this.DoubleBuffered = true;\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;\r\n            this.Name = \"SplashScreen\";\r\n            this.ShowInTaskbar = false;\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\r\n            this.Text = \"Razor Splash Screen\";\r\n            this.TopMost = true;\r\n            this.TransparencyKey = System.Drawing.Color.White;\r\n            this.Load += new System.EventHandler(this.SplashScreen_Load);\r\n            this.ResumeLayout(false);\r\n        }\r\n\r\n        #endregion\r\n\r\n        private void SplashScreen_Load(object sender, System.EventArgs e)\r\n        {\r\n            this.Activate();\r\n            this.BringToFront();\r\n            this.Focus();\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/SplashScreen.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\r\n  <data name=\"$this.BackgroundImage\" type=\"System.Drawing.Bitmap, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        Qk1yPwYAAAAAADYAAAAoAAAAswEAADkBAAABABgAAAAAAAAAAABgDwAAYA8AAAAAAAAAAAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////lJSTlJSTlJSUlJOTlZSUlZWV////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////lJSTlJSTlJSTlJSUlJOTlZSUlZWVlZWVlpWVlZSU////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////lJOTlJOTlJSUlJSUlZSUlpSVlZWVlZWVlpWVlZSUlZWUlpaWl5aW////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////fXx7kI+PlJOT\r\n        lJOTlZSUlpWVlZSVlZSUlZSUlZSUlZWUlpaWl5aWlpWVl5aVlpaW////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////fXx7fXx7fXp7goCAioiIkpCRlpWVlpWU\r\n        lZSTlZSUlpWUlpWVlZSUlpSUlpWVl5aVlpaWmJeXl5eXl5aX////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////gH18gH18fXt7e3l5e3d4fXh5g4CAioqKk5KSlZWVlpWVlpWV\r\n        lpSUlpWWl5aWlpaVl5aWmJeXl5eXl5aXmJeXmJeXmJaX////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////fXl5f3t7f319fHt5fHp5fHl5enl4enh3e3h3hIGBjIqKk5KSlpWVl5aWl5aWlpaW\r\n        lpaWl5aWl5aXl5eWmJeXmJeXmJaXl5aWl5aWl5aW////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////fXl5\r\n        fXl5fnp6gH18gX59fnx7fHp6enh4e3l4e3h5fXl5fHl4e3h3g4GAjIuLlZSUlpaWl5aWl5eXl5aWl5aW\r\n        mJeXmJeXmJeYl5aWl5aWl5aWmJaWmJaXmJeY////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////gX59gX59f318f3t7f3x7\r\n        gH19f3x8fXt7fXp6fnp7fXp6end4eXZ2eHZ2eHZ2fHl5hoOCjoyNlpaXl5eXl5WWl5aWmZiYmZiZmJiY\r\n        mJeXl5aWmJaWmJaXmJeYmZiYmZeYmJeX////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////hoSEhIKCg4GAgoCAgH9/gX5+gn9+gH19f3t8\r\n        fnp7fnt7fHp6fnx8fnp6fnp5fHl5fXh4fXh4fXp6hYODjo2NlpWVmJeXmZiYmZiYmJiYl5aXmJaWmZiZ\r\n        mZiZmZiYmZeYmJeXmpmZmpmZmpiZ////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////hoSEhoSEhYOChYOChYODhIODgoCAgX19gX5+f31+fnx7f3x7gX5+gH19\r\n        gXx8gHt7fnp6fXl5fXl5e3h4end3e3h4gH19iIaFkI6OmZiYmZeYmJeXl5eXmZiYmpmZmZmZmZmZmZiZ\r\n        mpmZmpmZmpiZmZeXmZiYmZmZ////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////h4aGhoOEhoSEhYKChIGChIGBg4GBgn9/g4CAg4CAgH59gH19gX19f3x7f3t7gHx8f3x7fnt6\r\n        fHl5e3h4enh4fHl6f3x8fXp6enh4f3t7iYaFkI+PmJeXmZmZmZiYmZiYmZiZmZmZmZiYmJiYmZiYmZeX\r\n        mZiYmZmZm5mZmpmam5mZ////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////h4aGh4aGh4aG\r\n        hoSEhoOEg4CAhYKChoSDhIGCg4CAhIGAhICAgn9/gH19gHx9g4B/gn9+gH19gH18gX18f3t7fnp6fnt6\r\n        fXt7fnp7fXp6fHh5e3h3e3l5f3x8iIaGkY6PmZeWmZeXmJeXmZiYmJiYmJiYmpiXmpeWmpiXm5mZmpma\r\n        m5mZm5mZm5manJub////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////iYeIiYeIh4WFh4WFiIWGh4OEhoSD\r\n        hoODhYGChYKDhYKChIGBg4GAgX9/g3+AhoKBhYKAgn5+hIB/hYGAg39+gHt7gXt6f3t6gHx8gH18gHx8\r\n        fnp6fXl5e3d4eHV2d3R1fXl5h4WEkpCQmJeYmZiYmZiZmpiYnJeWm5eWmpiYmpmZm5mZm5mZm5manJub\r\n        nJycnJubnJub////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////jYiHioeGiIaFiIaGioeHiYeGh4WEhYGChYKDhoODh4WE\r\n        hYSEhYKChIGBhIGAh4KCiIODhYGBhICAhYGAgn9+gHx8g317hX98gX17gHx7gX18gn19gHx7fHl4eXd3\r\n        eHV1e3d3eXZ1eHV0gX18i4iHk5GRmZiYm5eWnJmXm5iYmZmZmpmZmpmZm5manJucnJycnJubnJubnJyc\r\n        nZ2cnJub////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////jYiHjYiHjIiIi4eIiYaGioeHioeHiIWFh4SEhoODhoSEhoSEhoSEhYKChYKBhoOC\r\n        iYWEiYSEhYGBhIB/hIGAg4GAgn9/hH9+hH99gn59gHx8gXx8gX18gH18fnt7fXp6fHl5fHl5enh4eXd3\r\n        fHl5fnl4gHl3hH99i4iHlZKSm5mZm5qZmpmYmpiYm5qanJubnJycnJubnZycnJycnZ2cnJubnJubnZuc\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        j4qKj4qKj4uKi4iIioeIiYaGiYWGiYaGiIaGiIaFh4SDhoODhoODhoSEhYKChoOChYOChoODhYKChoSD\r\n        hYKCg4CAg4GAg4B/hX9+hn9+g35+gX19goB/gH5+fnt7fnp6fnt6fXp6fXp6fnp6fXt6fHl5fnl4f3t6\r\n        e3l4eXZ1gH18ioiIlZOTmpiZm5qanJqanJubnJubnJqbnJucnZycnJybnJubnZucnpycnpycnJyc////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////ko+Pko2Nj4uLjYqK\r\n        i4iJioeIiYWFioaFiYaGiYaGiIWFiIWFiYeGiIaGhoODhIKChIKChYKCh4SEhoWEhoOChICAg4CAg4B/\r\n        iIF+i4WBhYF/gX5+goB/g39+g358gX59gH19f3x8fnt7fXp6fHl5e3h4e3h4fXt6fXx7end3enZ2end3\r\n        end3gX9/jIqLl5aWnJubnJubm5qanJqbnZycnZycnZucnZybnpycnpycnJycnZycnpycoJ6e////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////ko+Pko+Pk4+PkY6OjYuKi4iJioiHjIqJi4iH\r\n        iIWFhoOEiIWFioiHi4iIioiHh4WFhoODhYOChoKCh4ODiIWFh4ODhoOChYKChH+Ai4SCjYiEhoGAf3t8\r\n        gX5+hoF+iIJ/gn9+gH5+gH19gX59fnt7fHl5fXp5fXl6fXp6fnt6fXp5fXp6fXt6fHh4e3d3enZ3enZ2\r\n        g4CAjouMl5WWnZubnJybnZubnJucnZybnp2dnp2dnZycnZycnpycoJ6eoZ6fn52dn52d////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////kY6OkY6OkY6OjouMjYuLjouLjouLjoyLj42NjYqLiYaGiIaFioeH\r\n        ioeHi4iIi4mIioiHiYeGiIWEiIWFiIWGiISEhoKChoKChH9/ioSCjIWDhoKBgX9/g359h398hoF/hIGA\r\n        g39/gn5/gX59gH18fnp6fnt6fXt7fHl6fXl6gHx9gH59fnx7f3t8f3t8fnt7fHl5e3h4e3d3end2hIKB\r\n        joyMl5aWm5ubnZucnp2dnp2dnpycnpycnp2doZ+eoZ6fn52dn52dn56dn56en56e////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////ko+Oko+OkpCPkI2NkI2Nk4+PkY6OkI6OjoyNjoyLjYqJjYuKjImKjIiJioeHioeHioiH\r\n        i4mIi4iHi4iIioaHiYWGiIWFhoODhoGAhoGAiIWEh4WEh4SDhYGAhn9+iYOCiIKBhoKCg3+AgX19gX19\r\n        gX59fXt6fnt7fnp7fnp7f319fnx8fXp6f3x8f35+fXp7fXp7fXp6f3t6fnp4end2enZ2fHl5hYODkI6O\r\n        mpmZnZycnZycnpyboJ6doZ6eoJ6fn52dn52dn56dn56en56en56eoZ6doZ6e////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////lJGQ\r\n        lJGQlJGRlpKTlpOUlZOSkY+Pj4uMjYqKjYqJkY6Nj42NjImKi4iIjIiIjIqJjImJjIiIiYaGioaGi4iI\r\n        i4iIi4eHiYWFh4ODhYKCiISEjoaFi4SChYOEhoOEiIOChoKAhYKChYKCf3x8fnp6f3x8gH18gX59gH19\r\n        f3t8f3t7fnt7fXp7f3x9fnx8fHl5fHl5fnt7gHt7gHt6fnp5fnt7fXt7fHl5fHh4e3h4hIKCkI6OmpmZ\r\n        np2cnp2cnp2dnp2dn56dn56en56en56en56eoZ6doZ6en56dn56foJ+f////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////lJGQlpKSlpOUlZOT\r\n        k5KRkY+PkIyMkY2Nko+PkI6PjoyMi4mJi4iIjYqJj46MjouLjYqKi4iIi4iIjImJi4iHjIaGjoaFjYaE\r\n        iIOCi4SDkoWCkYaCi4WEhoOEhIGBg4B/hIGAhYKBgn9/f318gX5+hICAhYKBgn9/gX19f3x7gH19gX5+\r\n        gX5+gH19fnt7fXp6fHl5fXt6fnt7f3x8f318fnx7fXp6fnt7fHl5end3e3d3fXp6hIKDkY+PnZucn56d\r\n        n56dn56enp2dnZydn52dop+eoqGfn56dn56foJ+foqCfo6CgoJ6f////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////lJKSlJKSkpCPj4yMko+Oko+Pk5CQlpST\r\n        lpSUkI2OjouLjoyMjIqJjouKjoyLjYuLjoyLjoyLjYuKj4uKjomIjYeGkIeFkIWCjISCi4WEj4aEk4aC\r\n        koaCioSDh4SEhoKBhICAhYKBiIWEiYeFiIWFhoODhIKChIKBgX9+gn5+hIGBg4B/gH18gn5+gX9+gH59\r\n        fnx7fnx8fnx8fHl6fXp6fnx6fnt7fnx8f318fnt7fXp6e3h4eXd3fHl4gn58i4iHlJKSnpycn56dnp2d\r\n        npycoZ+eoqCgoJ6dn52en5+eoqCfo6CgoJ6foZ+foZ+foKCf////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////lJKSkY2Nko2Nk4+Pk5CRlJKSmZeXlZOTkIyMj4yMj42M\r\n        jouLj4uLjouLjImJjouKjouLj4yMkIyMj4qJjYiHjomHj4iGjYaFjIiIi4eHjYaEkIWCjYWEiYeGiYaG\r\n        h4SFh4SEiIWEiIWFh4WFhYOEg4KChIKCg4GBgX5/g4B/goB/gH19f3x8gX5+gX5+gn9/gn5/gH19fXp6\r\n        fHp6f359f319fnt8f3x8gH19fnt6fHl5e3l4fHl5end3eXZ3e3d3fnt7iYeHlJKSnpycoJ6eoqCfoJ+f\r\n        n5+foZ+eoZ+doJ6eoJ6eoZ+foZ+foKCfoaCgoZ+foaCg////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////mJSUmJSUl5WVlZOUkpCRk5CQlpOUlpOTkY2NjouKjouLjouLkI2NkI6NjoyL\r\n        jouLkIyMkY6OkY6NjIiJi4iHjoqJjoqKjoiIj4uKjIqKiYaGi4aGi4aFioaHi4eHiYaGhIOCg4KChIKD\r\n        hoODhIKChIGChIGBhYODgYB/fXt6gn9/hYKDgX5/gH5+gn9/gn9/gn9+gn9/gH5+gH5+gX9/gX9/gH19\r\n        f3x9fnx7f3x8f3x8fnt7fHp6fHp6e3d4enZ2eXd2d3V0dnR0e3l5iYaGlpSUoZ+foaCfn52enpubn56d\r\n        oJ+goaCgoZ+goJ+eoaCgoZ+foaCgoqGho6KipKKi////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////mJSUmpiYlpSUlpOUlpKSlJGRk5CQkpCPkI6NkY6NkY6Oj42Nj4yMkY2NkY6OlJGRlZOTk5CQ\r\n        kIuLjYmJj4uMj4mJjoiIjoqKjYqJjIiIjYmJj4yLjoqJioeGh4ODhoSEhoaGiIiJiYaHiYWFh4OEh4SE\r\n        hoSEhIOCgX9+hYGBiISEhIKBhYKCg4GBg4GAg4B/gn+AgX9/gn9/g4CAhICBg4CAgH5+gH5+gX19gn5+\r\n        fnx8fXp6fXp6fnp6fnt6fXt6end3eHV1eHV1eHV1enh4gH19i4iIk5GSnZucoJ+foqGgoaCfn56en52d\r\n        oZ6foZ+goaCgoqGho6KipKKioqCgo6ChoqCh////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////mpeYmpeY\r\n        m5mZmpiYmJaVlZKSk4+PlZKSlZKSk5CPkpCQkY+PkY6OkY6Oko6OlZOTl5WVlJKSko+PkY2NkYyKkImI\r\n        jImIjouLjomJjIiIjImKj4yMj4yLioeGh4SEiIaGi4qKiomJioeIjIiIjomHi4eGioeHiYaGiIWFiIaF\r\n        hYOChIGBhYOChYKChYGChIGBgH5+gn9/hICAgoB/g4GBhIGBg4CAgoCAgX5+gn9/gn+Af3x9fnx7fnx7\r\n        f3x8f3x9fnt7fXt6fXp5e3h3e3h4fHh4e3l4e3h3fnt7ioiIl5aWoJ6en52doaCfoqGhoqGhoqCgoqGi\r\n        pKKjo6GhoqCgo6ChoqChoqCgoqGho6Ki////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////mpeYmpeYm5mYmZeWmZaVmZeW\r\n        lZKTlZCQmJWVl5aWk5GRk5CQlJGQk5CQlJCQmJSVl5SUkI2NjouLkY+OlI+Oj4mKjIqKjouLj4uMjImJ\r\n        h4SFhYOEioiIjIqKi4qKjIuLjouLjYqJioiIjImJjoqIjYmIjImJjYmKjImJi4mJiYaGh4SEh4WEh4OD\r\n        hoOEgoCAgX5+g39/hYKChIGBhIKChYKCg4CAg4B/gn9/goCAhIGBg4GAgoCAgX9/gH5+gH1+f3x8fnt7\r\n        fnt6f3x6fnt7fXt6fXt7e3l4e3d3eXV1eXZ2gH19jImJmpiYo6Kio6Gho6ChoaChoqChoZ+foJ+eoqCg\r\n        oqGhoqCgoqGho6KipaSkp6ampaSk////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////mpiXmpiXmpeXmJWUmJaVmJaVlpOTmZSUoZ+en5+e\r\n        l5SUlJGQlJKRlZKRlJGQl5SUl5WWk5CQko6NkY+OjoyMkI6Oko+QkY6OjouLjImJioaHioiJiomKjoyM\r\n        j42Nj42NjouLjImJi4mJjIqKjYqKjImJjImJi4mJjIqKi4mJioeIiYaGioeHioaGh4SFhIGBhICAh4OD\r\n        h4SEhYODhIGChoODhoOCh4OChIGBgH1+gX19g4CAhYODg4GBgX9/f3x8gHx8f318f319f3x7f3x8fnx7\r\n        fXp6fHp5fXt7fXp7end3eXd3eXd3enh4goCAj42Nm5iZoqCgoqGhoqCgoJ+foqCgoqGho6GhoqCgo6Gi\r\n        paSkp6ampaSkpKKio6Ch////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////m5iYnJmYnJmZm5mYmZaWmZaVl5STmpeXnZybm5qZl5SUl5WUlZKRlJGR\r\n        lJGQlZOTmZeWmZaWlJGRjouMiomKk5GQlZOSkI2NjIqKioeIjYuLkY+PkY6OkI2NkY6OkI2NjYqKi4mI\r\n        jIqKjYuLjYuLjYuLjImJi4iIi4mJjImJiYeHioiIjImJi4iJioaHiIWGiYWFioeGiYaGhIODhIKChYKD\r\n        h4SEhoODh4SDhoKCg4CAgH5+g4GAhIOCgH5+gH18gX59g4CAgoCAgn9/f319fXp6fnp6fnt7fnx8f318\r\n        fHp5end3e3h4e3h4eXZ3d3V0eHV0goB/kI6OnJuboqCgoaChoqKhpKOio6GgoZ+fo6GhpaSjpaKjpKKi\r\n        o6Cho6GhpKOkpaSj////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////m5iYm5iYnJmZnZubnZqanZmZnpqanZqZl5WVlZOTl5OUmZWWl5SUl5SUlpOTlZKSlpOSl5STmJWV\r\n        lJGRjoyNjoyOkpCQkI6Oj4yNjoyNjYyMjYyMkY+Pko+Pko+PkY6Oko+PkI2NkI2NjoyMjYqKjouLj42N\r\n        joyMjYqLjYqLjYmJjYqJjIuKi4qKioiIi4mJjIqJjImJjImIi4iJiYaHhoWEh4WFhoSEh4WEiYaFiIeG\r\n        hIKDg4CAhYKChIKBgn5+goB/hIGAhICAhIGBg4GBgX9/f3x9f3x9fXp6e3h5fXp5fnx7fnp7fnl5fHl5\r\n        end3d3R0eHR1e3h4enl4enh4hIKCkI+OnJubo6Kio6Kio6GhoqChoqCgoqCgo6Kho6Cgo6GhpKOkpaSj\r\n        paOjpKOjpKSj////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////rKqpq6morKqpq6ioqaamqKWlp6Wk////////\r\n        ////////////////////////////////////////////////////////////////////n5ycnpycnZub\r\n        nZqanJiYnZmZoJ2cn5ycmZaWlpKSnJiYnJmZmJWVmpiXmJeXlJGRlZGRl5OTmpeXmpiYlpOTlZKTkpCR\r\n        kI2Ok5CQlpSUlJKRk5CRkpCQk4+Pko6PkpCQkpCQk5CRk5GRko+Pj4yNkI6Oj46OjoyMj42Mj42NjouM\r\n        jYmKjYqLi4qKjYuKjIqKi4mJi4mJjIqJjouLjYqKioiIiYeHioeHioiHiYeHhYOEhYKCh4SEh4SFhYKC\r\n        h4ODhoOChIKBhIGBgn+AgYCAgoB/gn5+fnt8fnt6fnp6fnt7f3x9gH1+fnx7fHp6fnt7fHh5fHl5e3h4\r\n        e3h4e3h4enh4eHZ1eHV0hYKClJGRn56do6KhoqCgoqCgo6GhpKGipKKjpaSkpaOkpaOjpKOjpKSjpKOi\r\n        pKKipaOj////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////qqemq6iorKqpq6morKqpq6ioqaamqKWlp6WkqKWmqKampqWk////////////\r\n        ////////////////////////////////////////////////oqCfn5ycn52bn52cnpqanpubnZmZm5iY\r\n        mpeXmZeWmpiXnZuanZuamZeWmpeXmpiYlZOSlZORmZaWnZucnZubmJWVmJSUmZeXmZaVm5eXmpeXmJWV\r\n        lpSUlZSTlJGQk5CQko+Qk5CQk5GQk5CRkpCQkpCQkI6PkI6OkI2Mj42MkI6Ojo2NjIqLjYmKjoyMjoyL\r\n        joyMjImJjImJjIqKi4mJi4eIioiHi4iIjImIi4iIiIaHh4WFiIWFh4WFhIGChoODiIaFh4SEhoSDhoSE\r\n        hIKCg4GBhIKBgn9+gH19gn9/gn9/f319gX5+g4CAgn9/fnt7fnt7gH99gH59fHp6e3h5fHp5end2enZ2\r\n        eXV2enZ2eHZ1enZ2hoKCkY6Pn5yco6Kio6KipaSkpaSkpKKjpKKho6Kio6KipKOipKKipaOjpqSkpqSj\r\n        pqSj////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        rKqpqqemq6ioq6iorKqprqurrKqqq6ioq6iop6SlqKWmqKampqWkqqemqKalpqOj////////////////\r\n        ////////////////////////////o6KhoqCfnpycnpuboJ2dpKGgoqCgn5ycnZqZnZuZnJqam5iYnZmZ\r\n        nZqZm5iYmZaWmpeXmJaVmpiXmpeYmpeXmJaWlpWVmJWWnZqanZuam5eXmZaWmZeXmZeXl5SUlZOSk5KR\r\n        k5GRlJGRlZOTkY+PkpCPlJGRk5CRk4+Pko+PkY6OkY+Pj42NjouMj4yMjoyLjYqLjYqKi4mJioeHjIiI\r\n        ioiIioiIi4iIi4mJioiIioiIioiIi4iHioiHiIaGh4WFiIaFiYeGiIWFh4WFh4WFiIaGiIaFhoSDhIKC\r\n        hICAhICBgoCAgH59gH59hIGBhIGBgn5/f3x8goGAf3x8fHl6fHp6fXp5fXl5fHl5fHp5eXZ1eHZ2eXV1\r\n        fHRzfHV0e3l4iIWFk5GRoaCfpaSjo6Kio6GhpKKipqOjpaSkpKOjpaOipqSkpqSjpqSjpaOkpqOkp6Sk\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////raqqrKqprKmorKmorKmp\r\n        rauqr62srKqprKqprqurrKmpqaampqSkp6SkqqemqKalpqOjpKKio6GhqKWk////////////////////\r\n        ////oZ+gnJyfo6KhpaOio6GgoZ2dpqOiqqiopaOkoJ2doJ6dnpubo56do5+en5ycm5mZmZeXmZaXmJaX\r\n        mpiYm5mZnZqanJmZm5iYmZeXnJmZn5ycn52dnJuamZeXmZWXmZaXmZeWlpWUlZOTlZKSl5SUlZSUk5KS\r\n        lJGRlpOUlZOTlZOSk5GQko+PkY6PkY+OkY+Oko+PkI2NjouLjoyLjIqKjIqJjouKjouLjImKjouLjoyM\r\n        jYyLi4qKi4mJjImIioiHiYeIi4mJjYqJioeGiYaGiYaGh4SFhoSEiIaFiIWFh4SEhYOCg4GBg4KBgYB/\r\n        gX9+gn9/hIKChIKBgn5/goCAgH1+f3x8fn19fnt7fHl5fXp6fHl4end3eXZ3fHd3gnl3gHp3enh3end3\r\n        enZ2e3h4h4WFlZOUoqChpqSkp6Wmp6ampqSkpKOjpqSjp6WkpqSkpaOkpqOkp6Skp6WkpqSkpqSk////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////raqqraqqraqqr6ysr6ysrauqr6ysr62srquqrquq\r\n        sK2trKmpqaWlqaamrKmpqqioqqioqKampKKio6GhqKWkrqyrrKmorauq////q6eopKGhoZ+gnJyfnZ2g\r\n        pKKipqOio6CfqKalrauspqOkoZ2doZ6doJ2dpJ6epaCfn52dmZqbmZmanZucn52dnJqanZqbn5ycnJqa\r\n        mZaWmpaWnpqaoZ6eoZ6fn52empmZl5SUl5SUlpWVmJWVl5WVl5SUlZKSlZKTlZOTlpOUlZOSlpSUlZSU\r\n        lpSVlJKRkpCPko+Pk5GQk5CQko6OkY6OkY6OkY+PkI2Nj42MjoyLjouMjouMjoyMjYuMj42NjoyMjouL\r\n        jImJioeIi4mJjImJi4iIioiHi4iHh4WFiIWFioeGiIWFhYODhoSEhoOEhYKCg4GBhIGBhYKChIGBg4GA\r\n        goB/g4GBhYOChIKCgX5/fnt7fXp5fnt6fXp5enZ2e3d2fXh4fnt5fXp5fHh4e3h3fXp6fHp6e3h4fHp5\r\n        fnx7iYeHmJaWpKKipqWkpaSjpqSkp6SkpqSkpqOkpqSkpqSkp6WkpqSkpqSkpqSjpqWjpqWk////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////tLGxrqursKyssa6ur62sraqpr6ursK2tr62tr62tsa6tr6yrq6inraqq\r\n        rKqpq6iorKmqrKqqp6WlpaOjq6morqyrrKmorauqrKmoq6eopKGhoqGhoaGjoqGjpKOjo6Ghop+fpaKh\r\n        pqSko6GhoZ2cop6eop+fo5+foJ2bnZubm5qbnp2doJ6eoJ2enJmZnpuaoJ6dm5mZmZWWnJmZn52cop+f\r\n        op+fn5ydnJqamZeXl5aVmJaXmJWWmJaVm5iZnZqamZaWl5WUlZOTlZOTlpKTlZGSlJKSlZSTlJKRlJKS\r\n        k5GRk5CQko+Pko+Pk5CQlJCQkY+Pj42NkI2Nj4yNkI2Nj42MjoyMkI6OkY+Oj42Nj4yMjIqKioiIi4iI\r\n        i4iIjImIjImJioiHiYaHi4eIiYaGhoSEhoODhIGBhIGCg4KCiISDioWEhoGCgn9/goB/g4CAhoSEhYOC\r\n        gX5+f3t7gHx8gH18gH19f3p6fnh3fnp5fXt6fnt7fnl5fXl4fnt7fXp6e3d2fHh3enZ2end3end3fHp5\r\n        ioiHl5aVpKKipqSjpqSkpqSjpqSkpqSkpqSkpqSkpqSkpqSjpqWjpqWkpaOjo6KhpaOj////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////tLGxtLGxs6+vtLCwsa6ur6ysrqurrquqsq6usa6usK6us7Cvsq6urqyqrq2sraqqrqursK2trKqp\r\n        qqenqKamq6moraqpqqemq6iorKmoqqampqSjqKamqaenqKaloqKioqGipKKipKKhoZ6eoZ6dpaGgpKGh\r\n        o6CgoZ+en5ybnZqaoZ+fpaOio6CgoZ6enZubn5ybn5ybnZqaoZ6eo6Gin52dnZqan52doZ+enpubm5mZ\r\n        m5mZnJqampeYmJaVnZyboZ+gnJqal5WUl5OUlZKTlJOTk4+Qko+PlJGSl5OUlpOTlZOSk5GQlJGRk5CQ\r\n        kpCPkY+OkY+PkpCQk5CRlJCQk5CQlJGRkpCPkY+PkI6Oj42Nj4yMjoyLjYqKjYqKjIqKjImJjImJiYaH\r\n        iYaHioeIiYeHiYWFiIWFhoSEhYODhYODioWEjYeFi4WDh4KBhIKBhYKChYGCg4CAgX19gX59gH18gX5+\r\n        g39/hX99gHp5f3x7gX9+gH19f3t7fnt7f3x7fXp6fHh4e3d3fHl4fXl5e3h4eXd3eXd3d3V0fHl5ioeH\r\n        mpeXpqSjpqSkpqSkpaSjpaOjpqKjpqSipqWkpqSjpaOjo6KhpaOjpaOipaKipqSk////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////s7Cws7CwtbOz\r\n        s7Gwsa+usq+vsa+ur6yssq+utLCwsq+usq+vsa2tsq+usK+urqursq6vsa+urquqraqqrKqqq6mor6yr\r\n        sq+vr62trKmprKmprKmpqqamqqinp6SjpaKio6KjpaKjpqOjp6SjpaGhpaKhpKGho6CfpKGhoZ6eoJ2d\r\n        o6GhqKalqaamqKampKKin52cnZmaoZ6epqSjo6Ginpucm5mZoZ+eo6Cgn52cm5iYnJmZnZqanJmZm5mZ\r\n        nZybnZucmpeYmZaWmJSUlpOTlZSUlpSUlZKSl5OTl5OUlpSUlZKSlJGSk5GRlJGRkpGQkpCQk5GRk5GR\r\n        lJKSlZKSlZOSlpKSlJGSk5CQk5CQkI6Oj42NjoyMjouLjouLjoyMjoyNjIqLioeIi4iIjIqKioiIioiH\r\n        i4mIi4mIh4SEiIaGioeGjIeFjYeFioWEh4SEhoSEhYODhICBhICAg39/g39+gX19g39+hX99gn59gn9+\r\n        gX5+gHx9gH19gX9+gH19f3x8fnt6fXt7f318gH18fHp6fHl6e3h4eXV1enZ1eHR0d3V0fXp6ioiHmJaW\r\n        paOjpaSjpaSjp6Wkp6WkpqSjpaSkpKSkpaSjpaOipaKipqSkp6amqaenqain////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////s7Gxs7CwtLKxs7Cws7Cvs7Gws7Gw\r\n        sa+usa+vtLGxsrCvrqyrsa+utbKxsa6urqussa6usa6trqyrsK+vrq2trqursa6utbOzs7Kxr62trqyt\r\n        rqusqqeoqaamqaemq6ioqaampKGhqaemr66tqqmppKGhpaKhqKSjp6OjpKGhoqCgpaOip6Wjp6WkqKam\r\n        p6Wlop+goZ6fpKKjpaOjoZ6eoJ2doaCfo6Kho6GhoZ+foJ6en52cnpycnJqanJqam5mZm5iYm5iYmpeY\r\n        mpeXmZaWmZaWmJaWmZeXmZaWl5WVlpSVlpOUlJGRlJGRlJOSlJKSlJGRlZKSlJKSlJKSkpCRkZCPk5CQ\r\n        k5CRk5GQlJKRkZCQj42Oj46OjoyNjoyMkI2NkI2OjoyNjYyLjYuLj4yMjYyMi4qKi4qJi4iJioiIioiI\r\n        iIaGh4SEioeGi4iHioaHhoKChoSDh4aFhYODhoKChYCAgX19f3x8gn9/g4GBgn9+gHt7gX19g4B/gn9/\r\n        gX5+gH19gH19f3x9f319f359gH1+f3x8fnt6fHl5fXl4eXZ1d3R0d3R0dnNyd3NyfXl5i4mJm5iYp6Wk\r\n        qKWkp6Wlp6amqKempaKhop2cpJ+epaSkp6amqaenqainp6WlqKalp6am////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////s7Gxs7Gxs7CwsrCvtrKytbKxs7CwtLGxs7Cwsq+vs7GwtLGx\r\n        sa6us7CvsrCvrqyrr6yssK6tr6ysrqyrsK6ur62traursKytsK6usK2trqqqraurr62srayrq6iorauq\r\n        sa+vrqusqaanq6mosbCvrKqrpaKiqKalqaemp6Ojp6SkqaWmqKWlp6WlpaKipqOkpaKjp6SkqKamqaeo\r\n        qaanp6WlpaKjop+goZ6fpKKipaSkpaOjpaOjoJ+fnZubnJqanJmZnJmZnZqanJqam5iZm5iZm5iYm5iY\r\n        mpeXmZeXmJaWmJaWmJWVl5SUl5WVmJaVlpSUlZKSlZKSlpKTlJGRkpCQkpCQlZOTkpGQkI6OkY+PkI+P\r\n        kI6OkI2OkY6Pj42NkI2Oj4yNkI6Ojo6Nj42MkIyNj42OjYyMi4mJjImKjYuLioiIiIWFiIaFiIaGiYeG\r\n        iIWFh4ODh4WEiIaFh4WFhoSDhoOCg4CAgn5+gX5+hIGBgn9+gn9+hICAg4B/gX5+gX19gX5+gn5+gn59\r\n        gH59gX9/gn+AgX5+fnt7f359fXt7end3eXZ1eHV1eHR0eXd2eXZ2d3Rzd3V0f318jouLnJubp6Wlp6Wl\r\n        pKKipaCfqKSip6Wlp6Wlp6Wlp6Slp6WlqKalp6amqaeoqqioqqeo////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////sq+vtbSztbGxtbGyuLa1uLW1tbOytbKyt7S0tLGwsq+vtrKzuLW1tbOysa6usK6t\r\n        sa+ur62trayrrqysr6ursK2sr62ssK2tr6usr6yssa+ur62tsK6usa+uraqqrqqqsa6tr62tq6mqq6io\r\n        rKioqqenqKWlqqioqqioqKWlqqenrqqqq6ioqqeoraurq6mpqKWmqaeorKurrKmqrKmqqaiop6WmpKGh\r\n        o6CgpaKjpqOjp6SkpqOkoZ6fnZubn5ycnZubm5qZm5mZm5iZmpiYm5mZnpubnZuampeXmZeWmpeXmZaX\r\n        mZiXmZeXmpiYmZaXmJaWl5WVmZaWmZaWlZOTlZKSmJaVl5aWk5KSko+Pk5CQko+Pko+PlJGQkpGRkpCQ\r\n        kI6PkI6Pjo2Oj42NkI2Nj4yMjouLjYuLjYyLjo2MjouKiYeHioeHi4eHioeGh4WEhoSEh4SDiIWFioaG\r\n        ioeHh4WFhYODhoSEhoSDhoKBh4OChIGBg4CAhYKBhIGBg4CAgX59gX19gn5+g39/gn9/goCAgH9/fnt7\r\n        f318gH9+fXp6end3e3h3e3l3eXd3enh4fHl4fHl4enh3eXZ1eXRzenV0gX19kI2Nn5ycqaalqKalp6Wm\r\n        p6anp6WlpaWkp6alqainqKeoqaeoqqioqqeoq6mpq6qqqqmp////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////sq+v\r\n        sq+vuLa1uri3u7i4vbq5ure3uba2t7S0t7W0tbKytbGyuLW2ube3trS0srCws7Gws7CwsrCvsrCwsq+v\r\n        sq+vsa6tsK2tsK2tsa6usa+vsa+vsK6ur6ysr62srqursKurr6urraysraurr6ussa6ur6ysr6yssK2t\r\n        r62trKqqraqqrqurrqyrrqyssK2trqysrKqqrqyrraurraqrq6ipqKenqKemqqioqainqaamqaamqaen\r\n        p6Wmo6CgoJ2dn5ycn5ycnZqanZmanJmZm5mZnJqZnZubnZqampiYm5iYm5mYm5eYmpeXm5mZmpaXmZWW\r\n        mZaWmpiYm5mYmpiYl5WVl5WVmZeXmJaWl5WVl5SVmJSVlpOTlJGSk5GRkpGRkpCQlJGRkpCRkI6Pj42N\r\n        kY+OkI6Pj46NjouLjouLjYuLjYmJi4iHi4iIjYmJi4iIiYWFiIWFioeHioiIi4eHioWFiISEh4SEiYeG\r\n        iYaGioWDioaFh4SEh4ODhoOChoKChIKChIKCg4B/gn9/f3x9e3p7fHt8fXx8fXp6e3l5e3l5enp4fHp5\r\n        fHp6fXp6fHh4e3d3eXd2eHZ3eXd4eXV1f3d1gXh1fHZ1eHZ1e3d3hIGBkY+Pn52eqKenp6enp6amqKan\r\n        q6iorKqpqainqKanqaenq6mpq6qqqqmpq6qrq6mq////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////vLi4vLi4vLi4v7y8wb6+\r\n        wLy8v7y8vLm5uba1t7S0uLW1ube2uLe2trS0tbGytLGxs7GwtbGxtrOztrW0tbOzs7Cwsa+vsK2tsa2u\r\n        sq+vs7GwsbCvrqysraqrrqqrsK2tsKysr6usrqysrayrrampr6yrsrCvtLKytLKysK6ur6yssa2ssK2s\r\n        raurrqyssKytsK2usa6usK6tr6ysrqusrqysrKurqqioq6ipraurq6ioqqioqqiqqqipqKampKKioJ2e\r\n        n5ybn5ydoJ2dn52cnpybn52cnpycnZubnJmam5mZnJmZm5iYmpeYm5iYnpqZnZmZnJiZmpiYm5mYm5iY\r\n        mZeYmJaWmpeXmpiYm5qZnJqamJaXlZOTlJGRlZKTlJKSk5GRk5GRk5GRkI+Oj42NkI2OkI6Oj42MkI2N\r\n        kY6OjoyMi4eHi4eGjYmJjYuLjYuKjIiIi4iJjImJjYqKi4mJiYeGh4ODiISEiYaGiIWFiIWFiYaGi4iI\r\n        iYaGhoODhYGCh4ODhoOCgX9/hIGAhIGBfXt8fXx9goCAgH19fHl5e3l5f3x7fXt6fHt7fHp7fXt7e3h4\r\n        dnNzc3Fyc3BxeHR1gXp5gXl2e3V0end3e3h4e3l5eXZ2eHRzgH19kZCQoJ+fqaioqqiorKmoqqinqKan\r\n        qKanqaioqqmpq6uqq6qrq6mqqaioqKamqaeo////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////vru7vbq5u7e4vbu7wcDAwL69v7u7u7i4ube1\r\n        u7i3vLq5vLu6uba2trOytLGxtbGxtrOzt7S0t7S0tbKytLKysrCvsrCvs7GxtLGxtbKysrCwsrCwsq+v\r\n        sa+vsq+vsq+vsa+vsrCvsK2traurq6moq6ems7CuuLa2tbOzsrGxsK6vsa2usa2tsa6usrCwsK2trqqq\r\n        sKyssa2ur62ur6+vsbCwrqytrKiprKiprKqqq6inqqWmqaanqaenqqeoqKempqSjpaGhop6fn5ydn56d\r\n        oaCfoZ6eoJ2en52coZ6enZubnJqanJmZnJiZnZmZnpubnZuam5mYm5iYnJmanZqbmZeXmJWVmJWVm5iY\r\n        nJuampiZmJWWl5SUlpSUlZOTlpOTlJGRlZKSlpSUlJKSkpCQk4+QkY6PkY6Pko+PkpCQj42NjYqKjYqJ\r\n        joqKjouLjYuKjYmJjImJjYuKjoqKjIqKioiIiYaFh4SEiYWFh4ODiISEiYaGioiIiYeHh4ODhoODh4SE\r\n        hoODg4GBiYWDjYeEh4OBg4CAhIGBgX9/gH19gn9+gX5+gH59f318f3x8fXt7fXp7fHp6fXp6eXV1dnR0\r\n        eHV1e3h3fXp6f3t8fXp6eXZ2eHR0eXRycW5tcnBwdXNygX5+kpCQo6CgqqioqqioqaenqKamqaenqqmp\r\n        q6urqqmqqaioqKamqaeoqqmpq6mqq6mp////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////vru7vru7wsDAwb6+wb+/wcDAwsDBwLu7vLi3uLW1vrq6wL++vbu7u7e4\r\n        uba2t7W0trSzuLW1ube2trSzs7Cxs7Cwsq+us6+wtbKztrS0trS0tLGxsrCwsbCvsq+vtbKysrCwsa6u\r\n        sa6usa2ttrOztLSzsK6ttrKxuLa2trOztLKxs7CwsK6usK6usa+vs7Gwsa+vsKyrsa6utLKysq+wsK2u\r\n        r62trqussKytr6usraqqrauqrquqq6moqaanp6Smqaamq6ioq6iopaKjoZ2eoqCfo6Kio5+goJ2do6Cf\r\n        pKGhn52dm5iYnZmZoJ2doJ6enZucm5mZm5mZmZaWm5eXnpucnJqbmJWWm5iYnJmZm5iZmJaXmJWVmZWU\r\n        l5WVl5WVmJWWmJWVl5SUl5SVlZKTlpKTlZKTlZOSk5CRkY6PkI6OkY6Ok5CPkY6Oj4yMkI6NkIyMj4uM\r\n        jYmIi4iIjIiIjIiJjYqKi4iIioeHi4iIioeHiYWFiYeGiYaHiISEiYWFi4eHiYaGh4SEiIWEiISDioWD\r\n        iYSDh4ODhYKChIKBhIGBhIGBgX5+gH19gX59f3x8fXp6fHl5fnt7gH9+f319fHh5fHp6fHl5e3h4fXp6\r\n        fnt7fHl5fnp5fHd2eXZ1dXJzb2xtdHFxenh3d3RzhoOClpSTpKKiqqenqqipqampq6qqrKusq6qrqqio\r\n        qaenqqmpq6mqq6mpqqmorKqqraqq////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////wb6/wb6/xMPCx8XFx8TFxcLDw8DBwr+/vry7vbq5wL6+wb+/vLm5ura3u7i5ube3uLW1t7S0\r\n        uri3uLa1tbOztLGxtLCwtbKytrOztrOztLKys7Cwsq+us7Cwt7Szuba2tbOzsK2tr6urs6+uuba2u7q5\r\n        ube3uba3trOzt7S0t7S0tbKysrCwsrCws7Gxsq+vtLGytLGxs7Gxs7GxtbOztLGxsa6vr62trqysrqys\r\n        rqysr62tr62srqysqqmqqKanqaanrKqqq6qpqKWmpqOjpKKhop+fop6eop6foqCgoZ+fn52dnpubn5yc\r\n        oZ+eoJ6eoJ2dn5ycm5iZmZeWmpiXoJ2doJ6gnpydnJqZm5iYnJiZnZycmpiYl5OUmZaWm5mZm5manJqa\r\n        mpeYl5SVmZaXl5WVl5WVmJaWlpWVkpCQk5CRlZOTl5SUkpGQkY+PkY6NkI2NkI2Nj4yMjouLjYqKjYqJ\r\n        i4eHi4eHjIqKjoyLjImJjYqKjIqJjIiIioaFioeGjYmJi4iIiYaGiYaFh4SEhoKDh4ODhoODhoOChIKB\r\n        g4GBhIGCg4CAgn5+gn9/gn9+fnt6fXl5fnp6gH5+f319f3x8f3x8f3t7fnp5f318gH19fXt7fXp6fXl5\r\n        f3x7e3h3cW1ub2tsdnR0enh3end4eXZ3eXd3hoSEl5WVpqSkrKurraysrKyrqainqKWmqqeoqqioqqmp\r\n        qqmorKqqraqqrKqqrKipq6io////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////wb6+wr6/\r\n        xMLCxsTEx8TEyMTExMLBw8LCwsHBwb++wL6+vru7vLi4u7e3u7e4u7m4uba2uLS0u7e3u7m4uLW1t7S0\r\n        t7S0t7W0t7S0tLCxtbGxtLGxs7Cwt7KyvLm4vLq6t7a2s7Cwsa6usrCvtLGwu7a3vLq7ube4trOzt7S0\r\n        t7a3tLOzs6+utrGxtrS0tbKytbOztbO0srCws6+vtbKyt7SztbKys7GxsK6ur62trqysrKqqrKmqr6us\r\n        rqusq6mqraurrKurq6mqqaanqKWmo6GioZydop2dop+goZ+foJ6dpKCfpKGhpKKhoqCgoZ6eop6eo6Cg\r\n        npubn5ycoZ+eoZ6eoqCgoJ+fnJmYmZaWnpqaoJ+enZycm5ianZubnZuanJubnZucnJqbm5qZnZubm5iY\r\n        m5iYnJqbmJiYl5aVl5SVmpiYmJeXlpSUlJKRko+Pj4yMkY+Oko+Pko+PkpCQkI6Ni4eHioeFjYuKjYqJ\r\n        jImJj4yMjouLjImJjouKjYqKjYqJjYmJioeHiIaFiYaGiISFiISFiIWEhYOCg4GAg4GAhYKChoODhYOC\r\n        hYKChIKBgX9/gH19hICAgn9/f3x8fnx7fnt7gX18g4B+gn9/g4CBf3x8end3fnt7fnx7f3x7fHl5cm9v\r\n        b2xse3h4eXd3eXV2d3Z2cW9wc3Bwe3h4iIWFmJaWp6WmqKamqKamq6qpq6qqqqmpqqmqqqmprKmqrKqq\r\n        rKipq6iorausrausrKmq////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////wb6+wb6+x8PDyMXFx8TFx8TEyMbF\r\n        x8XExcTExcPEw8DBvru8vrq6wLy8vru7vLm5vbq6u7q4ure2vLm4vLm5ure3t7S1uba2ure2uba2trKy\r\n        ubW1u7m5ube3uba2u7i3u7m3trW0tbKytrOzsq+wtLCwuri2vbu7uba2t7W0uLa1t7a2tbKzs6+utrGx\r\n        uLW1uLa1t7W0trO0tbOztLKxtLGxtbCxtrGytbKytLKzsa6vr6usrqysrqysrqurrqqrr62tr66trqur\r\n        rKmqrKmqq6ipqKampaKio5+gop+foqCfo6Ggp6OiqqWjqaWlpqOkop+fop6eo6GgoZ+eo5+fo6CgoZ6e\r\n        oqCfoZ6enZmanZqan5ycn5ydnpubn52enpycnZqanpubnpydnpucnJqampiYmpeYnZqam5mZmJaXmpiY\r\n        m5iYmZeWmZeYl5WVmJaVlpSUkpCQkI6NkY+OkY6Ok5CQkY6PjouLjoqJkIyLjoqLjYqKj4uLjoqKjYqK\r\n        j4yMjoyMjYmKjoqKjoqKjIiJioeGiYWFioeGi4mIiYaGhoODh4SDhYKBh4SEiIWEiIWEhoODhYKChYKC\r\n        hYODg4GBgoB/gn9/gX5+hIGAg4CAgn5/gn9/gX59f3x7gX9+gX5+gX5+gYB/enh4dXJyeXZ2eHV1eXV1\r\n        e3l4dHFydHBxeHV0dXNzcm9wdXFxi4iIm5iZqaenq6mpqqmoqqenqqeoqqmprKqqraqqraqqrausraus\r\n        rKmqqaenqaioqaen////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////xsTDxsTDyMXFysfIysjIycbGyMXGycXGyMXGx8XGx8XF\r\n        w8HBwr+/wb++wL2+vry8vbq6vru6vLm4vLi5u7m4u7i4u7i4u7i4ure2ube2vbm4wb69w8HBv729uri4\r\n        u7i4u7i4trOztrOzt7S0tbKytLGxuLa0ube3ubW2u7m3vLq5uba3tbKytrOzuLW2uLa3uLa2uLW1ubW2\r\n        t7W1trS0trSztrS0tbGytbKytLGys7Cxsq6vs7Gxs7GxsK+ur62tsK2ur62trqyssK2tr6ysr62trqyt\r\n        rKqqqaamp6SlpKKioZ6fpKCfq6ajq6inpKKjn5ycoZ6epKKhpKGhop+foJ2doZ6doqCfo6GgoqCgoZ+e\r\n        oZ+en52doJ2doZ6foJ6fnpycnpubnZubnpubnJiZmpaXmpeYmpiYmZWUmpSUnZqZm5qZl5SUlpOTmJWW\r\n        mZeXmZeXlZOSkpCPkI2NkI6NkI2NkY6OkY2NkY6OkY6OkI2OkIyMj4uLj4yMj42MkI2NjYuLjYqKjouL\r\n        kI2Nj4uMjYqKjIqJjIqJjImJioeHioeHi4iHiYaFiIWEiYWFiYeGioiHh4ODhIGBhYOChoODhoSDhYOC\r\n        hIGBhYOChoODg4CAg39/goB/g4GBgX5+gn9/g4CAg4CAgH5+fHt6eHZ1d3R0enh3gH17fnt6eHV1eHR1\r\n        e3h3e3l5dHNzeHZ1fHp6f3x8jYqKnJqaqKemqqioq6morKqqrausrKurq6qpqqioqqioqaenqaioqaen\r\n        qqiprKmqraur////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////ysjHycjHycbHysbHyMbFyMbGysfIycbGyMTFyMXGysfIx8bGxMHBwb6+wb6+\r\n        wsDAwL29v728vry7v7u6vLm5u7m4wr+9wb69uri4u7i4vru7wsC/w8DBwL29vLu6vLq6ure3uba1t7Oz\r\n        tbCwt7a1trW1s7CxtLCxuLW0vLq5vbu6vLm5ura3uri4u7i4ube3uLa2uLa1uLW1tbKytrOyuba2ubm4\r\n        uLe2t7S0trS0tLOzs7GxtLCwtLKxsbGwsa+wsK2urqytsK6usa6usa6tsa6usK6vrqysrKuqq6ioqKam\r\n        pKGhpKChp6WkpqSjo6GhpKGhpaKio6CgpKGhoZ+foJ6doZ6do6CfoqCgoqCfop+go6CgoqCgo6Gho6Gh\r\n        oJ6fn56en56en52dn5ybnpubnZuanZ2dnZqanZaUnZiWm5mZmpiZmpeYmZaWmJSUmZaWmJaWmJWVlpSU\r\n        lZKSk5CPk5GQko+Pk5CQlJGRk5GRkY6OkY2MkIyMj4yMkI2Nj4yMkI2Mj4yLjouMjoyMj4yMkI6NkI6N\r\n        joyMjouLjYmKi4iHioeHioeGioeGjIiIjImKioiIioeHiYaHiYWGh4SEhYKChIKChYSEiIaGiIWFhoOD\r\n        hYOChoODg4CBgX5/gX9/hIKBhYKCgX9+fHp6fnx7fnt7fXl5f3t7f3x8f319fnp7eHV2cXBwc3Jxenh3\r\n        fnt7fXp6fHl5fXp6gX5+j4yNnZubqqeoq6qqq6qqq6ioqaeoq6iprKqqq6qqq6qpqqiprKmqraurraur\r\n        raurrKqq////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ysjHysjHzMrJycfIycfHysjIycjIycfHx8TFyMXFycbGyMXHx8bGxsTDxMHBxcPCxsXFw8HAwL29v7y8\r\n        v7y7vLq5vru7wb69wLy8uri4vLm5wb69wr+/wb6/v7u8u7m5uri4vLm4vbu6u7e3t7Ozu7i4vbu8tbO0\r\n        s7Cwuba2v729vr28vbu7vru7vbu7vLu6u7m5u7m6ure3ura1uLSzt7S0uLa2uLe2t7W0tbKytbKztrW0\r\n        tLKytbGytLGxsrGvsa+vsa+vr6ytsK6usK6ur62sr6urr6usr62trqysrqysraqpq6enqqenp6alpKKh\r\n        qKWkqqiopKKio6CgpKGgpKGgoZ6dpKCgpqOjpaOjpKGho6GhpKChpKCgpKKho6KioqCgoZ+foZ6foJ2e\r\n        oZ6eoJ+foJ+fn56eop+epKCdoJ2dmpmZnJiZn5ycnJqZmZaWmJWWmZWWmpaXm5iYmJWVlZKSlZKSlZGR\r\n        lpOTmZaXlpOTlJCQko6OkI6NkI2Nj42MkY2NlJCPk4+Pj4yMjoqKjouLkY6OkY6Oj42MjIqJjYmJjYuK\r\n        jYuKjYqKi4iHi4iHiYeHioeHjYqJjoyLioeHiIWFiIWFiYaGh4WFhoSEhYOChYOBh4WEiYaGhYKCgn9/\r\n        gn1+g4CBgoCAfHh4fXl5hYODhYOCg39/f3t7gHx8gX5+eXh4bWxsa2ppcW5ufHp4f3x8gX9/gX9+fXp6\r\n        fHp6fXt7fHp6gH19j42Nnpycq6mpq6ipq6mqraurraqqrKqqq6qqraurraurraurraurrKqqrqyrsKys\r\n        r62s////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////zsvMzsvMzMnLysjI\r\n        zMrKzs3MzMrKycXGycXGycbGyMXFxsPEyMXGycjIyMfGysfHysjIxMPDv7y9v7y8wL29vru7vbu6vbq6\r\n        vbm5vru7wb6+w8C/wb69wL29vru8u7a3vLi4vru7vbm4v7u7vbu7vbq6wL29v729uba2uba1vbq7vru7\r\n        vru7vr28vr29vby7vbu7vLm6vLi5vbq5vLq5ube4uba2ube0t7Szt7S1t7W1uLW1tbOzs7GytrOzt7S0\r\n        tbSzsrGxsa+vrqurrqytr66tr62tr6yssK2tsq+wsa+vr6ysramqrKipqKWmqKWkq6inqaeoo6GipKGg\r\n        paOipaKipKGgpKGgpaOkpqSlp6Skp6alpqSlpaKipKOjpaSkpqOkpKKjo6Cgo6CgpKKipKOjoqCgn5yc\r\n        npubn52dnpydnpucn5ycoJ2dn5ubm5eXmpeYmZiYm5qZnJuam5iWmJKSmZWWmZiYm5mZmZaXlpOTlJKR\r\n        lZKRlZKSk5KSkpCQko+Pko+Oko+OlJGQk5CQjoyMj4yLkpGPj4yMjImJjoqKkI2MkI6Nj42Ni4iJi4eH\r\n        jYmIjYqJjIqKi4mIiomHiYaGiYWGioaGiYaGhYODhYKCh4SDh4WFh4aFh4WEiIOEhIGBg4GAgoCAgX5+\r\n        gHx9hIGBhYOChYOCgoCAgX19fnt7dXN0cm9weXZ1fHh4fnp6gH19gn9/gn9+gH19gH1+f3x8fHl4fHh5\r\n        fHl6fHp5gX9+kI6On52erKqqrKqqrausraurraurraqqraurraysrayrrqyrsKysr62ssK2tsa+vsa6u\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////ysjIz8vMzcvLzcrLz8zMz87OzszMzMjJ\r\n        zMnJzMrKysjIysjIycbHycfHycjHysjIyMXFxMHBw8HBwb+/vru8v7u7wLy7v7y8wr+/x8TExsTEw8DA\r\n        xcLCxcPDwb+/vbi5vru6wb+/wLy8wr6+wcDAwb/Aw8DAxMLCwcC/vry8vry7vrq6vru7vry8vry8vru7\r\n        vbq6vbq6vbq7vbq6vLq6vbu7vLq6ure3uba2uLe2uLa1ube2uLa3trS1t7W1ure2uba2t7S1trKzs7Cw\r\n        sK+vr62trqysraurrqyssK6vsrCwsbCwraqrp6Okp6OkqKWlqKalp6Wlp6SkpqOiqKamp6amo5+go5+e\r\n        pqOhqKWlqKWlp6ampaSkpqOjpaKjpqSlp6WmpqSlpKKio6GhpKOjpaOjpaKipKGhn5ydmpiZnZqZnZqb\r\n        nZubnZqanZqampeXmZeXnJqanJqZnJqam5iYnJiXnZuan52empmZlZKSlZGRlZSTlZKRl5OTl5WUl5WV\r\n        lZOTlZKSlZKRlJKRkpCQkY2Oko+Pk5GQkY2NkIyMko+OkY6NkI2NkI2OjouMj4uKko2MjouLioiIi4eI\r\n        i4iIjImKi4eGioeGioeHh4OEhYGCiIaGiYeGiIaFiYeGh4SEhIOCh4SCiIWEhYKCgn9/gX5+g4CAgHx8\r\n        gn9/g4CAfnx7e3h4gHx9h4OChYKCgn+Agn+Agn9/gX18gH59gX9/gX5+fnt6fnp6fXp6fHh4fHl5fHp6\r\n        fHp6g4GBlJGRo6KirqysraurrKqqraurrqyrrqysr62tsK2tsK2ssK2tsa+vsa6usK2tr66tsK6u////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////ysjIysjIzszLz8zN0M3O0M3OzszNzsvLzsvKzszLzczMzcvMzcvK\r\n        y8jJysjIy8jJycfHyMbGx8TEx8XFxMLCwLy9w7+/x8TDx8XEycjIysfIyMXFxsTDyMXFx8XFxcLCw8HB\r\n        wb+/xMHAxcPCw8DAxMPDxcTFw8LCwcC/wsDAwsDAwL28vry7vry8wL2+v7y8v7y7vru6vru7vbu8u7m5\r\n        vbm6v729vLq6ubW2u7m5uri4t7Oyure3uri5uLe3t7W0uba2uba3ubW1uLS1t7a1trS0tLCwsq6vsK6u\r\n        raysrqyrsa2tsbCxr62trqqnrKinqqioqqenramoraioqqenqainqqiopqOlqKSirKekqqemp6WmpqOk\r\n        pqKjqKSlqKWlp6SlqKanqKampqOko6GhoqCgpKKjp6ampqSln52doJybop2cn5ybnZqanZqanJqanJmZ\r\n        m5eXnJmZnZubnZman5ydnp2dn52coJydnJmalpOTmJSVmZaXlpOTlpKSmJSTmZaWmZaWmJWVl5WVlJKT\r\n        k5CQlJCQk5CQkY6Pk5CPlJGQkpCPk5CPkY2NkI6OkY+PkY+Oj4yMj4uMjoyMjouLjoqLj4uMj4yMioiH\r\n        i4iIioeHioeHioiIiYeGioeHioeHh4SEhoKCiYaFiYaFh4SDhoOCg4GAgn1+g319hYGAhoSDhIOChIKB\r\n        hoKChoKCh4SEhoODhYOEhIKChIGBgn9/gX5+gX9+gX59gHx9gHx8gX59gX5/f3x9fXp6fn19fnt9fHh5\r\n        hYOClZOTo6Cgrqurrqusr6usr62trqurrquqr62tsa6usK2tsK2tr66tsK6usK6tsKyssKyu////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////zMnJzMnJzcrJ0c7O0tDP0M7OzsvMz8rKz8vJz8zLzczMzMrKzcnJzsvLz8zNzcvMy8nJ\r\n        zMnJzMnJycfIyMbGx8PEyMXFysnIzMzLy8rKx8TFxsTEycfHycfHx8PDx8XFyMfGxcPDxMDAxsPDxsPD\r\n        xcLDw8DAwb+/wL29v7u6wb69v7y9v7y8wL29wr++wr+/wb+/wL6+vrq6vru6vru7wL2+wL6/u7i4ura1\r\n        vLm5vbq6u7e2vLq6vLq6uri3ure3uLW2uLa2uLa2uLS0uLW1uLa2uLW1t7S0trS1s7Gwsq6tsK2sr6ur\r\n        s6+utrOwsrCur6yssa2usq6tsKysrqusrKmpqqiorKqrrKqpramorKmpqqmpqqioqKWmqqamq6ioqqip\r\n        qKanqaanp6SlpqSkpKKipaOjp6Wlo6Ghop+epqKhpqKhoZ6doZ+eoqCfoZ6eoZ+fn5ycnpqboJ2doZ6f\r\n        oZ6foJ2dn52doZ6en5ycnZqam5mZnJmZmpeXl5SUmJSUm5eYm5eXl5WUlpSTlpOTlpOSlpSTk5CQkpCQ\r\n        lZORlZKRk5CQlJGRlZKSk5GQk5GRkI6OkI2Nko6OkY6OjYyLjouLkI2Nko+PjouMjIiJjo2Mj42Mi4iJ\r\n        iYWGioeHioeGioaGioeHioeHhoSEhoSEiYSEh4GBhYGAiIWEiYaFhYKChoOCiIWEiIWEg4GBg4GAhYKB\r\n        hoOCiISEiIWGhoOEhYGAhIKBg39/g39/gX5+g4KBhIKCgX5/gH19gH1+fnt8fHl5fHp6e3h4fHh4hoKD\r\n        lZKTpKKirq6trqurraqqrqyrraurrqussK2tr62tr62tsK6tsKyssKyusK6usa6usa2t////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////zcvL\r\n        zcrKzcrL0c/O0tHQ0M7O0M7O0c7O0MzMz8zMzszMzsvLzszMz83Nz8vNzcrLy8nKzMrJzsvLzcvLzMnK\r\n        zMjJycbGysfIy8nIyMXExsPDxsbFysjJy8jIycbGyMXGyMfGxsXDwsDAwr6/x8TEw8DAv7u7wb6+wr+/\r\n        wLy8wb69w8DBwb+/w769wr+9w8HBuLa+kpGwraq3op+0w8C/wr+/wL2+v7y8vru6v7y7v7y9vru7vLu7\r\n        vru7vru6vLm5ure3ube3u7m5ube1uLS0uLW2uLi3ubi4uLa2trKytLCws7Gwsq6ttLCusrGwsK6usa2u\r\n        s7CxsrGxr66tr6ytr6ysraurrayrq6mpqqenraqqraurq6qqqqmoqaamqqenqKenqKamqKWmqaeoqaen\r\n        p6ampaKjpqOkpqOkpqOjpqSjop+hop+gpKKipqSjpaKipaOjo6Ghop+fo5+go6Cfop6eoJ2dn56eoaCf\r\n        op+eoJ6enpycnZuanpubmJWVmJWVm5iYm5qZmJaWlpOTmJSTl5STl5WUlZOSl5STmJWUlpOTlZKSlZKS\r\n        lZKSlpSUko+Pko+PlJGQlJGRkY6Oj42NjouLj4uLkY6Oko+Pj4uLkI6Nj42Mi4eIi4mKi4mIi4iHi4eI\r\n        jIqKioeGh4SFh4SFjISDjYSCiYWEiYeGiIWFhoOCg4CAhoKCiIWFh4SEhIKBhoODh4OBiIOAh4ODh4SE\r\n        iIWEiIWFhoKDg4GAg4GBg4GBg4KCgoCAg3+Ag35/f3x9fnx8fXt6fXp5fXp5gHx8fnx7fHl6h4SFmJWV\r\n        p6Wlrqyrrauqrqusr6ysrqurr62sr6ysr6ysr62ssK6usa6usa2tsbCvsa+usq+v////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////zcvLzcvL0c7P0c7P0tDQ0tHR\r\n        z83Nz83M0c/O0M7O0M3O0MzO0M7Oz87Oz8zNz8zNzcvLzMvLzcrKzcrKzszMzszMy8fIysjIy8jJysbG\r\n        x8HAxcDAx8XFysjJycfHyMXFyMTFx8XExcPDwsHAwb++xcPDw7/AwLy8w8DAxcTExcPDxMHCxMLDxMLC\r\n        w8DAxMHBw8LCiIiuBweEExOIUVGdwb+/w7+9wsC9wcDAv729vry8vry9vbu7urm4vLm6vru8vrq7vbu6\r\n        vbq7vbm6vbq6uba2uba2uba3ube3uLW2trO0t7S0t7OztbOysa+usK6usq+wsa+wsa+vsq+vsbCwsK6t\r\n        sa6usK+vq6mpqaWmraqqrqysqqioqaamqqmoq6ioqaamqaamqaenq6ipq6ipqqioqaanpqOkp6WlqKan\r\n        qKamp6WlpKGipKGipqSkpaOjqaampqSkoZ+eoZ6epKGipKGgpqKhpKGhoJ2doJ6epKOioqGhnZubnZqa\r\n        n5ydnZmZmZaWmpeWmpiYmpmZmpiYm5eXmZaWl5SUmJaWmpeWmJaVlpOTl5OTlpOTlJGRlJKSk5CQk4+P\r\n        lJKSk5GRkpCPkY+OkI2OkI2Nko+PkpCPj4yMkI2NkI2Nj4yMj42NjYyLjImIjYqKjoqKjImJiIaGioaG\r\n        j4eGkIqHioeGiIWFiIWFiYaGiYeHh4SEiIWEi4eHioeGiIaGiISEiISDh4ODhoKDhoODiIWGh4SFhoOD\r\n        hYODhoSFhYKDhIKBg4CAgn5/gH59gH19gn5+gn9+gX9/gH5+fn19fnx8f319fHp6e3h4hoSDl5WVp6am\r\n        r6ysr6urr62tsK6ur62sr62ssK2tsK2tsa+vsbCvsa+usq+vtLKytbGy////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////z8zMz8zM0c7O0MzN09DQ0c/QzMrKy8jIzsrK0M7N\r\n        0tDQ0M3O0M7O0M7O0M3N0M3Nz83Nz87Oz83NzsvLzsvLz8zMzcrLzMnJy8jIysfHzMjIy8fHzMfJysfI\r\n        yMbGysbGycfHycfHyMbGxsTExMLBxsPDxcLDw8DBw8DBxsPDxsPExsTExsPEx8XGxsPEw8DBwb6/bWyk\r\n        BQSEAACDGhqKsa66w767xMG9wsC/wr/AwL29vLm5vLm5vr29wL6/wb6/wL29vr28v729v7y8vru8vLq6\r\n        u7q6u7i6ubW3uba3uLa3uba2ubSztrOys7Kxs7GxtLGysbCwsK6usa6usa6vsa+usK2tr62tq6iorKio\r\n        r6ysr66urKqqramqq6ipq6iorKuqrausq6mqrKurr62srqqprKmpqaipqaeoqKWmqaeoq6ipqqmpqaem\r\n        qqalqqeoq6qpqaiopaOjpKKipqOkpaKjpaOiqKSkpqGgpaGhpaSkoaGgnJqanZqaoJ2dn5ycnpubnJmZ\r\n        m5mZm5mZnJmZm5iZm5iYmpaXmZaXmZaWmJWVmJWVmJWUl5SUlJKSmJSUmZaVlZKRlJGRlZKSk4+PkY+O\r\n        ko+PlJCQk4+Qko6OkI6Nko+Pk5GQk5GQkY6OjouLjoqJjouKjoyMi4iIioaGi4aGjIiIi4iIi4iIioaG\r\n        i4iHjYqKjImJioiHiYeGi4eHjIiIioeIiIWFiYaGioiIioiIiIaGiIWFh4OEhIGChoODiYaGiIWFhICA\r\n        g4CAg4CAg4GAgn9/gn5/goCAg4GBgn+AgH5+gH9/fnx8e3h4fHh4e3l3e3h3fnt8i4mJmJaXqKamsK6t\r\n        sK2tr6yssK2tsa+vsrCwsa+vsrCvs7KxtLKytbGysrCwt7a2uLa3////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////08/Q0c7N0M3N0c7N1dPS09HQzcrKyMbFzMjI0c7O0dDO0tDP0c/P0c7O\r\n        0c/O0c/P0tDP0tDP0c7Oz87Oz83N0c7Oz83NzszMz83Nz8/P0NDPz83Mz8zMz83MzMvLy8nJysjHysjH\r\n        zMvLy8rKyMXGxcLCxcPCx8XFyMTEyMXFyMbHx8bFx8XEyMbGxsTExMHBxMHAd3WpAgKDAACDFRSJsa67\r\n        xcLAxcPBxMHAw7/AwsC/v728wL29wsHBw8HBwb++wL29v729wL69v768vry7vry8vry8vbq7vLm6uri3\r\n        uLW1uLW2uri3trOzsa2us7Cxs7Kysa+vsa6tsrCwsrCxsq6usa6tsK2tsK2urqurr6yssa6usK2trqyr\r\n        rqurrampraurrKurqaanqqenr62tsa6tr6ytrausq6ioq6inqaenqqeoqaemqqenrKmorKuqqKinpqWl\r\n        p6amp6amqKampaKjo6GgpaOipqOjpaOipKOjoZ6enpubn5ycnpqan5ybn5ycnpybnZqanZuanpuanpub\r\n        nJmZm5eYmZeXmZaWmZaXm5iYm5iXmJaVl5SUl5SVmJWWlZKSlJGRk5CQkpCQkY+QlJGRl5KRlpGRk4+P\r\n        kI6OkI2NlJGRlJGSkY6OkI2NjoqKj4yMkI6OkIyMjomHjYmIjYqKjouKjYmJi4eGi4eHjImJjYqKj4mJ\r\n        jYeHi4aGi4iIi4iJiYeHioiIjIqLi4qJioiHioeHiIWFhIGBhIF/h4SCh4SEhYODhIKBhYKChYKChYOD\r\n        g4GBg4GBg4CBgX19gHx9gX5/gH19f3t7fnp6fHl5fXp6f3x8gH1+fnt7fXp6jIqKnZqaqaemsK6tsrGw\r\n        srCwsq+vsq+wtLKxtLKxsq6vsrCwt7a2uLa3tLOytLOytrSz////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////08/Q08/Q1NHR09DQ09DP1NHQ09DP0M3Ny8jHzcnJ09HQ1NTS1NPS09HQ0s/Q09HS0tHR0s/N083L\r\n        0czLz87P0M7P0M7Oz87Oz83Nz83Mz87Nz87Oz83Nz8zM0MzNz83NzMvKzMnJzcrKzczMzcvLy8jJyMXF\r\n        yMXFy8rKy8rJy8nIy8nJycfHx8bFyMbFx8XFyMXFyMfGbGuoAACDAACDGRmLvbvAxsTExMTDxMLCxMDB\r\n        wsHAw8HBw8HCw8HCwsC/wb69wL29wb6+v729vby7vry8v728v7y8vLu7vry8vLu6ura3ura4uri4t7S0\r\n        tLCwtrKztbO0tLGytLGxsrGxsq+vsK6tsbCvsrCwtLKysrCwsKyssK2tr6ytr62tsK2tsK6usK2ur62t\r\n        q6ipqqeorKqpraqrrausrq2trKmoq6inrKqqqqinqaamqaanq6ipqainp6WlpqSkpqOjpaKipqOjpaSk\r\n        oqGgoqCgop+fpKCgpKKhpKGio5+foZ+doJyboJycoJ2doJ2doJ2cn5ycoJycnpybnZqanJmZnJiYm5aX\r\n        mZaWmZiXmpeXmZaWmJWWmZWWmJWVmJWUl5OSlpSTk5GRlJGRl5OSm5WTm5WSmZKRk4+OkpCQlJKSk5CR\r\n        ko6Pk4+PkI2Nj42MkY6Ok42MkYqIjoqJkI6Nj4yMjouLjYqKjYqJjImIjouKj4yMj4uLjomJjYmIjImJ\r\n        i4iIjouLjoyMjIqKioeHi4iIiYeGiYeGiIWFh4SDiISEiISFh4WFhYKDhoKDh4SEh4WEhYODhYKCgn9/\r\n        gX1+gX5+gX9+gX5/gn9/g4CAgX9+gH19f3x8f3t7fnp6fnt7f3x8gX9/j42Nn52crqyrsrCwsa+vtLGy\r\n        tLKxsK6trqursrCvtbOztLOytLOytrSzt7SztLKys7Cw////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////1tLT1tLT1tPU\r\n        19XU1dLS0M3O0c3O0s/P0M3Nz83M1NLS2NbW1dLS09DR09HR1NDR0s/P09DP1NDP0czNz83O0c7P0dDQ\r\n        0M7O0MzMz8zMz8zM0M3N0M3NzsvLz8vLzsvLzcrKzsvLz8zMzsvLzszMzcvLzcrLzMrLy8rKy8vKysjI\r\n        ycbHx8XGxsLDx8LDysfHysjIyMfHV1WgAACDAACDCQmGl5a1yMfHx8XGw8HBwr/Awr+/w8DAxMPCwb+/\r\n        wr6/wr6/wr+/wb++wL6+vbu8vru6v728vru8vrq6v7y7v729vru8vry8vbu7ure3ube3t7W1uLa2trW1\r\n        tbO0trOztLOysrCwsq+vtbGytrO0trSzs7GxsrCws7Cxsq6wsq+wsK6vsK6vsa+wsK6uraqprauqrqyu\r\n        rqytr62tq6moqaenq6iprKioqqenqqioqKamp6Sjp6Skqaamp6WlpKGgpaGhpqSkpaOjpKGhpKGho6Cg\r\n        o6CgpaKipKGhop6eop+eop+foZ+fop+eoJ2coJydoZ2doJ2cnpucnpybnJqanJmZnJmYnZubm5iZl5SV\r\n        mZWWm5iYm5mZmZaWmZeWmZeWl5SUlZKSmJaVl5OTmpWTm5WUmZSUlZKSk5KRk5CRlpGRl5OTlZKSkY6O\r\n        ko6OlI+Oko6NkY6NkIyLjYqKj4yMkI2Nj4yLj4yMj4yMj42NjouLjYmJjYiIjYqKjYuLj4uMj4yMj42N\r\n        joyNi4iJjIiIjIqJiYaHiIWFiYWFiYWGiYWGh4SFhYSEh4WEhoSEhoOEhoSEh4WFhYKCgn9/gX5+goCA\r\n        hYKBhIGChIGBgoCAgX9/f3x8fXp6fnt7gX5+gn9/f35+f319hIGBko+PoJ6fsa2us7Cxsa+urqusr6yr\r\n        sa+us7Gxs7GxtrOyt7SztLKys7CwtLCwtbGxs7Gx////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////09DQ1NHR1tPT1dPS1tTU1NHR0c7O\r\n        z8vMz83Mz8zLzcrK0c/O1tTU1tPT09HS09DQ09HR1dTU1tTV1NHR0c/P09DR09HS0c7P0M3N0c7P0tDQ\r\n        09DQ0s/P0MzN0M3Nz83Oz8zN0M3Nz83Nz83Nzs3NzcvMz83NzszOzMrKy8rKy8jJx8TExsPDx8PEycXG\r\n        ycbGycbHycbHYWCjAACDAACDAgKEnp65x8bHx8XFxcPCw8HBxMHCxMHCxcPDw8HBw8DAw7+/wr6/wr+/\r\n        wb+/wL6+wb28wb69v729v7q5v7u7vru8vbu7vby7vry8vLq6u7i5uri4ubi3t7W1t7S1u7i5ubi4tbS0\r\n        tbKztrKzt7S0tLSztbO0trS0t7S1tbK0s7Gysa+wr62tsq+vsa+vsK2sr62sr62usayts6+vsK6uq6mp\r\n        rKioraiprKipq6ipqqenqaWlqaemqqmoqqiopqOjpKGhpqOjpqOjp6Slp6SkpKKho6CgpaGipKGho6Cf\r\n        oZ6fop+fop6eop6eoZ6eoZ6doZ+en52dnpycnJqanZubnJqanpubn5ubnZubm5qZnJqZnJqZnJmZmpmZ\r\n        mZiYm5eYmpeYmZeXl5WUlpOTlpOTmJaVmZWWl5KTlJGRlpSTl5SUl5WVlpOTlI+PkY2NkY6PkpCRk5CP\r\n        kYyLj4uLko6OkI2NkIyMkIyNkI2NjouKjYqKjYqKj4yMj4yNjoyMjouLjouLj42NjoyMjImJjIiIjIiJ\r\n        ioeHjImJioaHh4SEiISEioWGiYeGiIWFiIWFhoODh4SEiIeGh4aGhIGBhICAhIGBhYKCg4CBgn9/g4GA\r\n        g4GBgH5/f3x8gX9+gn9/g4GBgX5+fXt7fXt7gn9/goGBgYCAkI2NoZ6esK6tr62sr62tsq+vsq+vsq+u\r\n        tLKxtrS0tbKytLCwtbGxs7GxtrOztrKyt7W0////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////09DQ09DQ1tPT19XU1tTT2dbW19TU0MzMzcnJ0M7Nz8vKx8LD\r\n        y8nJ2dnZ2dfX1dTU1dPU1tXW19bW1tTU1dLT1dLS1NLS1NLS0tDR0tDR1NPS1dTU1NLR0s/P0s/P09HR\r\n        0tDQ0tDQz83OzcvMz83Nzs3NzcvMzszNzsvMzcvLzcvLzszMzcrJysfGzMrKzMvLysfIysfHy8nJZGKl\r\n        AACCAACDCwuHiIaxwr/AxMHAyMXEyMXFyMbGx8bGx8TExsPExMHBwr6/w76/xMHBw8LBwsC/wr6+w7+/\r\n        wsC/v729v729vbu7u7i4vLm5vLm6vbq6vLm5vbu7uri4t7S0ubW2u7m5u7m6uba3ube3trS0tLKytLOz\r\n        trS0t7S1t7O0trKztLKys7Gys7Cxsq+usa6usK2tr6ysrqqqsayss7CwsrCwrqurrquqrqyrraqrrKmq\r\n        rKmorKmprKqpq6moqaanqaanqKalqaWkpqOjpqOjp6SkpqSjpaKipqKipqOjpqOjpaGhpKCgo6Cfo6Cf\r\n        o6CfoZ6eoJ6dn52dnpubn5ubn5ycnpycnZqanZqanZubnpycnZubnpuanZmam5mZmZiYmZeXnJmZm5iX\r\n        mJWUmJWVmJWUl5STl5SUlpKSlpOSl5SUmJWVlJOTlJGRlZGRk5CPkY6Ok5CQk5CPkY6Nk4+Pko+Pko+P\r\n        kIyMkIyMkIyMkIyLkIyMkY2NkI2OkY+Pj4yMj42NkI6Nj4uLjouMjoyMjYuMjImJjYqKj42NjoyMioaG\r\n        iYWFioeHioeHi4eHioeHiIaFhoSDh4SEh4SEiIWFh4SEhoKDhIKChIKCg3+AhICAhIGBgX9/gn9+g4GB\r\n        g4GBgX5/gX5+f3t8f3x8gX9/goB/fXt7fXt7fnx8hIGAkpCPn5ydsK2tsa6usK+usrCvtbOzt7S0trOy\r\n        tbKxtbOztrOztrKyt7W0uLa1trOztbGx////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////2tna2tna2tjY2dfW2tfW29jY19TU0c3N0s3N19TT1NLRzMjIzcrK19bW2dfX2NbW\r\n        19XV1tTV1dPT1NHR1tPT19XV1tTU09LR0s7O08/P1dPT1dTT09DR0c7P09HR1NHS0tDQ0dDPz83NzMnK\r\n        zsvMz8zOzszNzczMzcrKzcrLzsvNz83Nz83Nz8zNz87Ozs3NzMvLzcvLzMnJS0ucAACCAACCAACDeHes\r\n        xsLCx8TDycfHycbGyMbFyMbGyMbGx8TFxsPDxMHBxcHCxcLCxcPDw8HBwr/Aw7/AwsDBwb/AwL+/v729\r\n        v7y8v7y9wL29v7y7vru7vbq7vLm6u7i5uri4ubi4uri4ura3uba2uLa2trO0trS0trS0trO0t7OztbGx\r\n        s7GxtLGytbKzs7Cwsq6usq+vsK2tsK2tsK6tr66traqqrqqrr6yrr62sr6ytr6usrqqqrKqprKmqrKmp\r\n        rKmprKmprKmpqqemqaalqKakqaamqKWlpqOjpqOiqKWkqKWlp6SjqKSkpqOjp6SjpKGhoZ6eop6eop+e\r\n        op6eo5+fop+foJ6dn52dnpucnZucnJmanZqan5ybnpubnJmZnJmZnJqZnJmYmZaVl5SUmpaWmpeWmJWU\r\n        lpSTmJWVmJaVmpaXmpWWl5OUlZKSl5WUl5WVl5SSlpORlZKSko+Pk5CPlJGQlJGRkY+OkY2Nko6OkY2N\r\n        kY6OkY6OkY2NkY6Pko6Oko+Pk5CQkY+PkI2OkY6OkI6NkI2NjouLjoyMjYuKjoqKjYqKjIuKi4iIi4eH\r\n        i4iHi4mIiIWGh4OEiYWFioeHiYeGh4OEhYODhYKChYKDhYGChIGBgoB/gn9/hIKBg4GBgH1+gH19g4CA\r\n        hYKChIGCgH19f3x8gX5+hIGChIKCgoGCgYCAhIGCkpCQo6GgsrKxsrCwtLCwt7Ozt7WztrS0trOztrOy\r\n        t7a1uLa1trOztbGxt7S0uLW1ubW2////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        3drb3tzd3Nra2tfW2tbW29nY2dfW1dPS1tPT2NXW2tjY19XU0MvM0s7O2NbW2dfY1tTU1dLT09DQ0tDP\r\n        19TU19XW19XV1dLT0MvL0s3M1dLS1NHS0s/Q0s/Q09DR09DR0c/P0c/P0c7P0s/P0c3O0M3O0M7OzszM\r\n        z8vL0MvM0M3Oz8zNzcvLzszMz8zMzsvMzszMzszLycbKTUydAACCAACCAACCcG+py8rLy8rJycjHysfH\r\n        ysbGycbGyMbGyMXFx8TFx8TEx8XExsTExcLDxsPExMLCwsHAw8HBw8DBwsHAwb++wb6+wr/Aw8HBwb+/\r\n        vry8vru7vry8v76+vry9vLq6u7m4uri4ube4uLa3ube3uLW1uLW2uLa2uLa2tLGxsq+wtLKytLKys6+v\r\n        s6+vtbKxtLKxtLGxs7CwsKysrqyssK6tsa6tsKysr62tr62ssKysrqqqrKipraurrauqraqqq6ioqqen\r\n        qqinrKmoqqWlqqenqqenqKWkqKSjqKSkqKWlqaWmqaWlqKSkp6Skp6OkqKSkpaKhop+fop+fop+foZ6e\r\n        o6CgmZacnpycnZubnpuan5ycnZubnJqanpqanpubm5iYmpaWmZaVmpaWm5iYmZWVmZWVmpeXnJmZnZmZ\r\n        npmZnJiWmpeXmJaWmZaWmpWUmpaVmZWVmJSUlZKRlJCQlJGRlJGRlJCRk5CQko6OkY6NkpCPko6Oko6O\r\n        k4+Pk5CQkpCPkY+PkY6Pko2OkY2LkY2MkI2NjImJioeGi4eHjomKjoyMj42MjoqKjYuLjIqKioaHiYWG\r\n        ioeIiYeHiYWFiIWEh4SEiISEh4ODh4OEhIKCg4GBhIKChICAhICBg39/hICBhIGChYKCg4GBg4GBg4B/\r\n        g4CAhYKChYOEhIKCg4CBgoCAgX9/gX9/h4SFk5CSn5ycs6+vt7W1t7OztLGxtbOztrS0tbKytrKytrSz\r\n        t7S0uLW1ubW2uba3u7i5ube3////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////3drb3drb3tzc3Nra29jZ\r\n        29jZ29nZ2tjX2NXV2tfX29jZ29nZ3Nva2NXU0c3N1dPT2dfY2NfX2NfW1tTU1dLS19XU19XU19XU19TV\r\n        1NHQ1dLQ1tPT1NHS09HR1NDQ1NLS1NLS1NLS1NHR1tPT2NbX19XV1NHR0tDQ0c/P0c/P0tDP0c/P0M3N\r\n        z8zMz83Nz83NzcrLzsvLz8zMycfKUlKfAACCAACCAACCUFCey8nKysfIycbGycfGysjHy8jHysfHx8XE\r\n        xsPEx8XFyMbFyMXFxsTExsTDyMXFxsXExsXExcLCw8HBxMLBwsDAwb6+wb6/wr/Awb2+wL69v769v72+\r\n        v729vbq6vLq6vLq6urm5uri4ure4ure4uri4urm5uLa3t7S1trKztLOytbKytLCwtLGwtLKytLGytLGx\r\n        t7OzuLOytbOys7Kxs6+vs7CwsLCvsK6tsKussKyssKysr62srqurrampq6ioqqamq6inq6ioqqenq6eo\r\n        rKmoqqemqaamqqenqqioq6ioqaamqKWkqaalqqemp6WlpaKjo6Cfo6Cgo5+foZ6emJWbXVyKMTB7goCT\r\n        n5ucnpucnpubnZqZoJycnpucmpeXmpaVnZmYnJmZnJqZnJmYm5eYmpeXmpeWnZqaoJybn5uYm5iXmpeX\r\n        mJWUmJSUmJWVmpeXmZaWl5SUlZGRlpKSlpKRlJCRk5CQk5CPk5CPlJGRlJCPk4+Pk5GQko+Pk5CPlJGP\r\n        lZKRk5CQko2Nko6PkI6OjImIioeGi4mIjImKkIyMkI2Nj4uMjoyNjoyNjYqKjImIioeHiIWGiYWFiIWF\r\n        ioeGiYaFiIWFiIWFiIWGhYKDhYKChICAhIGBhYKCh4SEh4OEhIGBhIKChoODhYODg4GAg4GAg4CAhYKC\r\n        hYODg4GCgoCAgn9/gH1+fnt8fHl5hIGBl5SVqKSltrOytrS0tLCwtLCwtrS0t7W1t7W2ube3ure3uba3\r\n        u7i5ube3uba2ure3u7m3////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////zs3N39zd3dvb3Nra3Nra3Nva3Nvb3Nra29jY\r\n        3NrZ3dvb29nb3drb3dvb1tPTz8vL0tDQ2dfX2djX2NfW2NbW19XW2NXV2NXV19PT2NTU2NbW1tXV1NLS\r\n        09HQ0s/P1tTT2dfX19XV1tTU1tTU2NbX19XV3tra3NnZ2NbW1NLS0c/P0M7O0M/O0M7O0M7O0M7P0MzM\r\n        0c7O0c7Oz8zMVVWgAACBAACCAACCQUGayMXJysjIysfHysfIysjJy8nJysjHyMbGycfHysjJysbHycfH\r\n        x8bFxcLCyMXFx8TFxsHCx8TExsPExcPDxMLBwr++wr+/xMHBxMLDwb/Av729vbq6vLm6vry8vry9vLq6\r\n        ure3vbq7vby7vLu6vLq7u7q7ubm6ube3uba2uLW2ubW1uLS0trOzs7Cxsa6utbKyubW0u7ayuLSztbO0\r\n        tbKytbKytLKyr66usKytsa2tsa2tr6ysrqursKurr6urraqprKiorKmprKinrKmoqqemqqemrKioraqq\r\n        raurq6ioqaamqaalqqenp6SkpqOip6OjpqOjpKGhpaKilpOcREODEBByAABtGxt1jImYop+foZ+foZ2e\r\n        oJ2dn52dnZqanZmZnZmYnZqZnpubn5ubnpqanJqZnpuan5yboJ6dnpycnJiZm5iYmpaWmJSTmZaWmZaW\r\n        l5WVlpOTlpOSlpOTlpOTlZGSlJGRk5CQlI+PlJGQlZGRl5OSlJKSkY6QlJCOmZWQmZWPlpGPk4+Pk4+Q\r\n        kpCQkY6NkY6NkI2MjouLj4uMkIyNjouLjYuLj4yMkI6NjoyMjImJi4aHioeHiYeHiIWFiIaFiIaFiYaH\r\n        ioeHiYWFhYKChIGBhIGChYODhoOChoKDhoWFh4WFh4SEh4SEh4WFg4GAgn+Ag4GCgoGAgX5+gn+BgoCA\r\n        gH9+gX9+gH5+f35+gH5+gX1+iYaFmJaXp6SltbCwuLS0uba3uba2uba3u7i3vLi4vLm6ure4uba2ure3\r\n        u7m3u7i3u7m5u7q5////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////zs3Nzs3N393e3trb3dnZ3tvb3tzd3dzc3dzc3t3d393d3dzb2tjW2NTU\r\n        2tbW2dbW0c3Mz8zL09LR0c3N08/P29nZ29na2tjY2NXV19PU2tfW2tjY2NbW19TT1dPT1tPU1dHT0M/P\r\n        zMvM1tTU1tTU////////3tra3NnZ2NbW3Nrb2NXW1NLS09LR0s/P0c/P0c7P0s/P0tDQ0tDPzsvMVlWg\r\n        AACBAACBAACBMTCUv77HzMrKzMrKzcrLy8jJzMnKzMnJy8jJy8jIy8fHysfHycfHxsPDxMDBxsTDyMbG\r\n        yMbGyMbGycbGyMbGxsTExMHBxsTDxsTDxcTDxcTExMLCwcDAwL6/wr/AwsDBv76+vLq6wL6+wsC/v7y7\r\n        vru7vbu9vLy9vLu8vLm5vLm5uri5uri4uba1t7S0trOzuLW0ure2ure3uba3t7W2t7S0uLSyt7OzsrCw\r\n        sK6usrCvs6+vsq+vsK6tsKyrr6yrr6ysr6ysrqurrquprampraqprKmorKiprKmprqyrrKmpqqioq6ip\r\n        rKipqqemp6Sjp6OjpqKioZ6hfXqWMTB+AABuAABuAABtAABtHBx2eXeTo6CgoZ2en5ycoJ2do5+foZ6d\r\n        n5ycn5ycnpubn5ubn5uboJuboZ6doZ6eoJydn5ucnJmZnpuanJmYmpaWm5eXm5mYmJWVmJSTmpWVmZaW\r\n        mJWVl5SUlZGRlZCQlZCQlpKSlZKRlpOTlJGRk5CRl5OSmpSRmpaTmJWTlpWVlJKTk5GRkpCQlJGRk46P\r\n        kY2NkY6OkIyNj4yMkIyNkI2Mj4yMjouLi4iIi4iIjImJjIiJi4eHiYaGiYaGiYaFiYeHiYeGh4SEhYOD\r\n        h4SEiISEhoSDhYKChoODhoODhIGBhoODiIWFhoSDhIKDhYKDhIGAgn9/g4CAhYKDg4KBhIKChIKCg4GB\r\n        gX5+gH19goCAgH9+f319iYaHm5iZrKmqt7W1uLa2u7e3vLm5u7e3uba2uri4vLq7u7m5u7i3u7m5u7q5\r\n        u7i4u7q5vLq6////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////4N7d4N7d4N/f39zd4Nvb4N7d393d39zd3tvb29rZ3dzc3tra3NjV2dXU19PV3NrZ1tPSz8vK\r\n        0s7O19TU2tfY29na29jY3NrZ2tjY19TT2dXU29fY2tjY2dbW19XV2tfY1dLTtrS0zMvM////////////\r\n        ////////////////3Nrb2NXW3Nra19TU09DQ0s/P0c3O0M3O0c7P0c7P0MvMY2ClAACBAACBAACBKimQ\r\n        x8bKzszMz8zMz8zMzsvLzsvLzszMzcrLzMjIy8jHzMnJy8jIx8TFxsXFyMbGysjHysnJycbHyMTEyMTE\r\n        x8XFyMbHycbGx8TDxMLCxsTExsTDxMLCw8HCwsDAwb/Avr2+vrq7wL28wb+/wL29vbq6v7y8vru9vbu8\r\n        vLm6u7i4ube4uLW2ura2ure2vLi3vLi4ure4uba3t7W1ube2uri3uLa1t7OztrKys7Gws7GwtbGxtbKy\r\n        tLGxsa2tsq6usq6usK2sr6yrr6yrr6yssa2tsKysrKmprKioraqqraurq6mqrKmprKmorampq6ioqKWl\r\n        pqKkYV+PIB95AABvAABvAABuAABuAABuAABtFxZ1c3KTo6GgoJ2dpKChpqSjpKGhoZ+eo5+eoJybn52d\r\n        n5ycoJuboJ2coJ6en5ydnpqanZqanpybnpuanJmZnZqZm5iXm5eWm5iWnZmYnZmZm5mZl5SUlZGQlZKR\r\n        lpOSlpOTmJWUlpSUlZKRl5SUmJWUmZWUmJaXmJeXlpOUlpOTko6Oko+PlZGRk4+QkY6Pko+Pko+Pko+Q\r\n        k5CRkY6OkY6PkY6Pj4yMjYqJjYqLj4qKkIyMjoqLi4iJioeHioaGiYeHiIWGi4iJjYyLjIiIiIaGhoSE\r\n        hoKCh4ODhYKDhICBh4SEiIWFiYWGiIWFhoODhYGChoKDhoKDhYODg4GBgoCAg4GBhIGCg4GCg4KCg4KB\r\n        g4GAgoCAgH1+f3t8iYaGnJmZr6urubW1uLa2ube2ura2u7i5u7i5u7m5vLq6u7m6u7i4u7q5vLq6ube2\r\n        u7i3uri4////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////zs3O4N7e\r\n        4N/f4d/f4d/f393d393c39zc3tra2dbV3NjZ39vb39zb3tzc3Nna393d2tjY19TU2NXU29nY3Nna2tjY\r\n        29jY3NnZ2tnZ2NXU2tXU2dXW2NbX2NbX2dbX2NbW2tjYtrS0////////////////////////////////\r\n        ////////3Nra19TU1NHR1NDQ0M/Pz87P0M3O0s3N0M3OU1KfAACAAACBAACBFRWJt7bE0M3O0c7Oz8zM\r\n        zszMz83Nz8vLzsrKy8nJy8nJzMvKzszMzMnJy8jHzcrIzMnJysfHycfHx8TDx8LBycXEycbHyMXGx8TE\r\n        xsPDxcPDxsPCxcHBw7/Awb+/v7y8vbu8v729v7y8vr29wL6/v7y8vbq6vbu8u7m6vLi4vbi3vbi2uLW1\r\n        uLW1u7a2ura2ube4ure4uba2t7S1uLa2u7m5uLe3trOztbKytbKyt7OytrKytrOztLGys7CwtLCvs7Gw\r\n        sa6usa6usK6ur6ysr6yrsK2tsa6ur6ytr6yssKyrsKurraqpq6iorKmpq6ipmJWiSEeIAQFwAABwAABw\r\n        AABvAABvAABvAABuAABuAABtAABtXV2MpqKjqKWlqaiopaOjpKCfpqKhpaGfop+eop+foZ6eop+foZ6e\r\n        npubnZqanpubnpubnZqanpubnpuanJiYnZmYnpuanJmZnJiYm5iYm5eXmZaWl5STl5OTmZaVmZaWlpOT\r\n        mZWVm5iWmZaVmJWVmJWWlpSUlpOUmJaVl5WUlpOTl5WUlpOTlZKRk5KRkpGQkpCQlJKRk5CQk5CQkY+P\r\n        kY6Pko+PkI2OkI2NjouMjYqKjYqKjYqKjYqKjYqKjouMj4yMjIqKi4iIioeHh4aFiIaGiYeHiYiIiISF\r\n        iIeHiIWHiISFh4SEh4SFiIWFhoODhoODhoGChoKChIGBg4CAhYKDhoOFhIKDhIODhYODhIODg4KCgX5+\r\n        gX19f3x9gH5+jYqKnpubsK6uure4vLe5u7i5vLu6vbu7u7i5ure4u7i5uri4ube2u7i3uri4u7i4vrq5\r\n        vrm5////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////zs3Ozs3O4N7f4uDg4+Hh4uDh4N3d\r\n        4N3d39zc3trb3trb39zc39zd3t3e397d39zd3tzd3dvc3tzc3NjX1tHQ08/P2NbV29jY2NXV1dPT1NLR\r\n        1tPS2dXW2tfY29jY19TVy8jJuLe3uLe3////////////////////////////////////39zb39zb2dfW\r\n        1tPT1NHR09LS0tLS09DQ08/P0dDQZWSnAACAAACAAACBAACBn5y70czN09DP0M3NzszN0M3Oz8zL0MzL\r\n        zczLy8rKzczLz83Nz8zLzcjFzMjFzMnJycbHycfIycfHyMXFyMXEycXGyMbGyMbGyMbFxsTDx8LDxsLD\r\n        xMDBxcHBwr+/vry9wb+/wL6/v76+wb+/wb69v7y8v76/vry9vLi4wbu6w726vru5uba3ubW2uba1uba2\r\n        uba2uba2uba3uLa3uba3uLW2t7S1t7S0t7KyubSzuLOztbKytLKys7Gxs7CwsrCwsq+wsq+vs6+wsK6u\r\n        rqyrsq6ts7CxsrCxsq+vtK2ss6yrsa2tr6ytrqurgX6bNjSCAABxAABxAABxAABwAABwAABvAABvAABv\r\n        AABuAABuAABuCwpwU1KJm5mhp6Slp6Slp6SjqqenqKSjpqKgpKGhpKGhpaGgpaCgop+foZ+foJ2cn5qb\r\n        nZqan5uboJycnZqanpubn5ycnZqam5eXnJiYnZqanZqam5eXm5aWnJiYm5iYmZWWmpaXmpaVl5SSmJWU\r\n        mZaWmZaVmJaVmpmYm5qZmpmZmJaXl5OUlpKSlpWTlZOTlJKSlJKRlJCQkYuMjImJjYuLko+PlJGRkY+P\r\n        jo2NjYqKj4uKkY6OkI2Oko+QmpiYnpqblJGRkY6OjouLioiIjImKjYqKjIqJjImJioiIiYiJiYaHiYaH\r\n        i4mJioeHh4SEhoOEiIOEh4OEiISFhYKDhYKDhIKCg4GChIGDg4GChIKDhYSEhIKBgn5/gX6AgH1+gH59\r\n        gH19fnx8jYuMoZ+ftLCxvLq7vLq6vLm5vLi4u7i4vLi4u7i4vLi4u7e4u7i4vrq5vrm5uri3ura2////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////4N7e4N7e4d/g4+Hh4+Dg4d7f4d/e4d/f4t/f4N7f4t/g\r\n        4uDg4N7e3dvc3NrZ3dra3dnZ4Nzb4d/d3drZ1s/P0szL09DP09HQ09DP19TU09DQ0M3M2dfX3t3d3dra\r\n        1NHSsK6vuLe3////////////////////////////////////////////39zb29nY1NLT1NLT1NHR1NHS\r\n        1NPT1NLS1NLSbmyqAACAAACAAACABgaCoZ680c3N0s7O0c7P0c7P0c/P0M7O0c7O0M3OzsvLzsvLz8vM\r\n        zsrKzsrJzcnHzcvKy8nJysfHysjIycjIycfHysfIycfHx8XFyMXFyMXGyMXFx8PDxcLCxcLCxMPCw8HB\r\n        xcLDxMPDwsHAwr6+wb29wL6+wL6/wL6/wLy7w8C/xcG/w727v7u7vLm6vbq5vbi4u7e3u7i5uri4uba3\r\n        uLW1ubW2u7e3ure3uba2uLW1uLS0tbGytbOytLKxs6+ws7CxtLCwtLCwtLCwsq+vsq+utrKxtbGwsq6v\r\n        tLCwtK+ttK+usq+vsa2ur6ytJyZ/AAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABvAABuAABu\r\n        AABtOTh/mpWcp6OkqqenrKqprKemqaOip6KhpaKhpaKhpqKhpqSjpKGhop+foJ2doZ6doJybnpqZnpub\r\n        npycnpycnZmZnJmZnZmZnpqbnJmZm5eXnJiYnZmYnZmYnZmZm5eXmJWUmJSTmZWVnJmam5mZm5iXmZaX\r\n        mpiYmpiYmZaWl5OUl5SUmJaVmJaWlpSVlpOTl5OTko6OjouKj4yMkI2OkY6Ok5CQkY+PkY+Qko6Pk4+Q\r\n        jYqLi4mKmpiYnpqblJGRqaWlnpubk5CRjoqKjoqJjYmJi4eIjIiIi4mIi4mJjYuLjo2NioiIiISFiYaH\r\n        iIaHhoOEh4OEh4SEg4CAg3+AhIOChYKDg4CBgn5/g4CBg4GBg4CBhICBgn9/gH1+gX5/f319gH9/gX9/\r\n        gH5+j42OoZ+ftLGxvbq6vbm5vLi3u7i3vLm4u7i4vLm5vrq7vbu5uri3ura2ura3uri3vLq5////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////2NbW5OLh5eLj4+Dg4d7e4d3d4d7e4d7e4+Hh5OPj4d/f4N3d4t/f4N7e3dra\r\n        3tra3tnY4NzY4eDd4eDg29fX1c7N0s7M0c7O1tPU3tvb1NLRzcnJ2dfV39/e3tzd1tTUsK6v////////\r\n        ////////////////////////////////////////2tnZ2tnZ1tXV1dPU1NHS1NDR1dPT1dLS1dPTZmWn\r\n        AQF/AACAAACACAiDh4Wz0tHQ0c/P0s/Q09HQ0c/P0M3Oz83N0c3O0M3O0M3Nz8vKzcrKz83Oz83NzcvK\r\n        zcvLzcnJysfHycfHysjIy8jJysbHx8TEx8PCyMbHycfGyMXDyMTExsTEw8HBxcPDyMbHx8bGxMLBwr+/\r\n        wsDBwL6+wLu6wr28xMHAxsTDxsLBxL68wry7wL29v7y7wLu7v7y7vry8uri4uLW1ure3u7i5u7e4u7e3\r\n        uri5ubi5uLa3t7S0trOzt7SztrKytrKytrOxtLGwtLCwsq6utLCwt7OytrKxsq+vtLGxtbGwtLGwsa6u\r\n        rqursKytWFeQAABzAAByAAByAAByAABxAABxAABxAABwAABwAABvAABvAABvAABuAABuAQFuJiZ6gX6W\r\n        qKOkq6emrKinq6alqKOipaKipaKipqKipaKipKKio6Cgop+foZ6eoZ2dn5ubnpuanpqanJqZnpqanZqZ\r\n        nZmZnZiYnJmYm5iXnJqYnJiXnJiWnpqZnJiXm5eXmpiXm5iXnJmZnJqam5iZmZaXmpaXm5eYm5iYnJqZ\r\n        m5mYmpiYmJWWmJSVmJaWmpiXlZSTlJKSlpOUlJKTkI6PkY6Pko+PlJGSk4+QkY2OjYqLi4mK////////\r\n        ////qaWlrKmpl5SVjYmJjoqKjYqKjIuKjImJjIiIi4iIjImJioiIiYaHiYaGi4mKiYiIh4SEiIWFh4WF\r\n        hIGBhH+AhoOChYOChoOChIGCg4GBg4GBg4GAhIGBhIGBhICCgoCAgX9/gH5+goCAgn+AgoCAgoCAgX5/\r\n        ko+PpqOjtrSyvLm5vbq5vbu7vLm6u7m5u7m5uri3ura2ura3uri3vLq5ure2uba1u7i4////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        2NbW2NbW5eTl5eLi5OHh4uDg4N7e4d7e4Nzc4d7e5OLi4N7e3dra4eDf5OPi4d7f393d4N7d4d3b4Nzb\r\n        4N/f393c2tbV2NXU2tjX3dra3NnZzcvLysbG29jX3dvb1tTUysjIysjI////////////////////////\r\n        ////////////////////////3tvc3tvc1tTV1dPU1dLT1dPT1tPT1dLT09HTbm2rAgKAAAB/AACAAACA\r\n        eXet1dPS0tHR09HQ1NLR0tDQ0c/P0c/O0M7O0c7O0c/Oz8zMzsvL0M7N0M7OzcvKzcrKz8vMzcnKzMnJ\r\n        y8nJzMnJysbGyMXFyMTEyMXFyMbFycbFy8jIycfHxcLCxsPDx8bFx8TEw8DBwsDBw8LDw8DAw767xb69\r\n        xMC/xsHBxcHAxL+9wry7vrq6vru7v7u7wL28vry8vLm5uba1u7i3u7i5ure4vLi4vLe3urm5uLe3uLa2\r\n        uba1ura2ure2ubW0t7SztLKxtLGws7CvtbKytrOztLGxtLGxs7GxtLGxtLCws7Cwsa6usK2tko+jBgZ1\r\n        AABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABvAABuAABuExNzgHyYqKSlqaamqqal\r\n        qaWkp6SkpqOkp6Ojp6SkpqOjpaKio56eop6eo6CgpKKioqCeoZ2coJycn5ycn5ybnZqanZmZnZqZnZqZ\r\n        nJiYnZqZnpuaoJ2cnZuanJmZm5iXmpeWmpeWm5iZnpqbnZybnJqbnZmbm5mam5qZnZubmZiYl5SUmJWV\r\n        mpeXmZeWmJaWk5GTlJGSmZeWmJeXlJKTk5CRlZGQkY6KkY2O////////////////////////rKmpl5OT\r\n        j4uMjouMkI6PkZGQjoyMjoqLj4uLjIiJiYWGiYSFi4eHi4iHi4iIioiIi4mIi4iIh4WFh4WFh4SEh4OD\r\n        h4ODhYODhIKChYODhoSEhoSEhYODhYODhIKDgX+Ag4GBhYOEhYOEg4KChIKCg4CBgH5+gX9/goCAlJGR\r\n        p6SkuLa2u7i5uri3vbi4vLm5vbq6vbq6vbi4ure3ure2uba1u7i4vLi4vLq6vbu7////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////5eLj5eLj5ePj5OLi\r\n        5OHh5OLj4+Lh4+Dg4d7f4t/f5OLi5OLi4uHh4+Lh4+Hh4uDh4d/g4d/f49/d4Nza3tra39zd4N7e4N7e\r\n        4N7d393d3NnY09DP087O4Nzc2tjXure3ysjI////////////////////////////////////////////\r\n        ////////3dna3dna1tPU1tPT1dPU1tPU1tPT1dPT1NLTgH6xAAB/AAB/AAB/AQF/VlSg1tLT1dPT1NTS\r\n        09DQ0c3N09HQ09HR0c/Pz8zLz8zK0MzM0M3O0M7Oz8zMz8zLz8zMz8zL0M7Oz8zNzsvLzcrKzMnIysjH\r\n        y8jIy8fHysfHy8nJy8rKycbIx8PFyMXGycbGyMTFxMHCxMHCxcPDxsPDxcLBx8LBx8HBxL/Aw8DAw7+9\r\n        wb28vru7vru8v7y8v7y8v7y7vbq6vLi4u7i4vbq7v729paKyv7q5vLq5vLm6u7m4u7m4uba3uLW1uLW0\r\n        uLW1uLS1trOytrOytrOytLKxtbKyt7S0tbKytLGws7CwtLCxtLCxsa6urqurQ0KKAABzAABzAABzAABy\r\n        AAByAAByAABxAABxAABxAABwAABwAABvAABvAABvAABuAABuDAtyZGOQn56kqaamqaalqKWlqaamqqip\r\n        qqmoqqimqKalpqGhpaGfp6Wlp6Skp6ShpqOhpKCfoZ2coJ6doZ6doZ2dnpybnJmYnpqZoZ6dop+foZ+e\r\n        n56dnpycmpeYm5eWoZ2cop+foZ6en52cnpubnpubnJqanpubnZmbm5eYmpeXm5iYnJmZnZmanJiYlJGS\r\n        kI2OlZKRmZeWl5WVl5OVmpWSkIyIkIyI////////////////////////nZuanZuakpCQjouLkIyNkY6P\r\n        kI2Nj4yMkY6NkIyNjYmKjImKjYqLjYqJi4iHi4iIjIqJjYqKi4iJiIaGiIWFiYSFiYaGh4SEh4SFh4SG\r\n        h4WFh4SEh4WGhoWFhIODhIKCg4CBgX9/gn+Ag4CBg4GAhYKCg4CBgX5/fnx8f3t8gX5+g4KClZOTqKSj\r\n        uLS0vbq6vru6vbq6vbi4ura2ubW2ura2u7e3vLi4vLq6vbu7vry8vru7vru7////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////29jZ5eLi5OLi5OLi5eLi5uPj5eTk5OLh\r\n        4+Dg4+Dh5OHh5OLi4+Dh4+Dh4uDg4eDg4+Dh49/g5OHg4+Hf4d/f4uDg4d/e4N7e4t/g4N3d3dra3tzb\r\n        4N7e393dz8zMure3////////////////////////////////////////////////////////4d/g3Nra\r\n        2NbW1tXV19XV19TV19TV1tTU1tTUfXuxAwN/AAB/AAB/AAB/REOa2NXV1tTU1dPT1NDO083N1NHS09DR\r\n        0c7P0MzMz8zLz83M0M7O0M/P0M7P0M7N0c/Nz83M0M7O0M7OzsrLzcrJzcvLzcvMzcrLzszMz83LzcvK\r\n        ysjIyMXFycfHysnIysjIycXHxsTFxsLCxsLCxsLCxsLCx8TDx8TExMPCwsHBwr+/wr6+wb69wL29wsDA\r\n        wb+/wb++wsC/v7q5rKixhYOqUE6YHx+Fk4+rvrq4vrq6vbu7vbq7vbq7u7m6uri3ure3vLi4ure2uLW1\r\n        uba2t7S0t7W1uLW1tbGxtrGxtLGxtLCxs7Cws7Cvsq+vkI6jBgV2AABzAABzAABzAAByAAByAAByAABx\r\n        AABxAABxAABwAABwAABwAABvAABvAABvAABuBgZwSEiGqqWorKioqqenqaamqaemqqenqqanqqamqqal\r\n        qaWkp6SjqaWlqqakqaWkpaGho5+fop+fo6GgoqCfoJydoJycoZ6do6Cfop+fop+foJ6dn52doJ6fn5yc\r\n        pKGfqaamqKWlpKChpqKip6Skqaamraqqqaeno6Khn5ydnpqaoZ2eqKSlq6emoZ+dmJaVlZOTl5WVlpSU\r\n        lZGRmpWSmpaVmpaV////////////////////////oZ+goZ+gkpCRj4yMkY2Nko+PkY6Pj4yMkY6Ok5CR\r\n        kY+Pj42NkI6PjYyMjImIjIiIjYmJjImJioeIiYeIioeHiYWGiYaHi4qJioiIiIWHh4WFh4WGiIWHiIeG\r\n        h4aFiIaGhIKCgX5/g4CBgoCAgn+AhYGCgoCBfnx7fnx7f3x8gn6AhIGBg4CAgn+AhoWFl5SVqKWluLW0\r\n        ure2u7i3vLm5vrq6vbm5vrq6v728wL29vry8vru7vru7ure3tbOztLKx////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////29jZ29jZ5ePj5OLi5eLj5+Tk6ebl5uPk4uDg4uDf5OHh5OLi5OHi\r\n        5OHh5uPi5eLj4+Dh4+Hh4d/f39zc4Nzc4N7e4N/f4d/f4d/g4d7f39ra4d3d5OHi4+Hg3NnZvbu6vbu6\r\n        ////////////////////////////////////////////////////4d/g4d/g29ja2NXW1tTU2NbV2NXW\r\n        19XV19XV2NbWiIe2CAeBAAB+AAB+AAB/KyuQxsTO19XV19PU1tLR1dHR1NLT0s/Q0tDQ1NTT1dTU0c/O\r\n        z8rJ0c7N0tDQ0M3N0c/Oz83Mz8zM0M3Nz8vLzcvLzczMy8rLzcrLz8vK0c7Lz8zLy8jIyMbGycfHycbG\r\n        ycbGysfHyMXGxsLDxcDBxsLBxsPCxsTDx8XFxsPEw8DBxcHBxcLCw8DAwr+/wr+/wsC/uLW8n5yzbWqh\r\n        KCeKFRWDAAB8AAB8WVaZvLe5v7u6vru8vry9v7q6v7m4vrm4vbm4vbm4u7m5ure4u7e4uba2trOzuLW1\r\n        t7S1uLSztrKxtLCws7Cws7GwtbGxtbGxPj2JAAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABx\r\n        AABwAABwAABvAABvAABvAABuAABuMzKAjYufrKqpq6ioqaWmq6enq6enqqWlq6emqqamqKSlqaWmq6en\r\n        q6emqKWmpaKipaKio6Ghop+eo56do6CgpaKipKCgop+fpKCgpaGhpKGhqKampaOjnpubqaamqKWlsq+x\r\n        pqKip6Skqaamraqqqaent7S0q6inop+eoZ2eqKSlq6emoZ+ds7Gwp6WmnZqcl5WWlZGR////mpaV////\r\n        ////////////////////////oZ6fmZaXlJGRk5GQk5CPk4+Pk4+PkY2NkY6Oko+QkI6NkI2NkY6PkY+P\r\n        kI6OkY+PkI6OjoyNi4mKjIiJjIiIiYaGhoSFioiIjYyLi4iJiYeIiIeIiYeIiIWGiIaHiYaHiIWGiIaF\r\n        iYeIiIWGhYKDhYOEg4KCgX9/g4KAg4CAgn5/hIGChIGCgoCBgYCAgn+Ag4KBhoWElpSUqqemvbq5wL28\r\n        v7y7vru6v7q6v7u7vbu7vbu7vbq5ure3tbOztLKxuri4vrq6wLu6////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////5+Pj5+Pj5+Tk5+Tl6OXl6OXl5uPj5uHj4+Dh4d/f4+Hh5ePj5+Pj5+Pi5+Xk5+Tl5eLj\r\n        4+Li4uDg4N3e4t/g4+Hi4d/g4N7f4N3e3tzc29nX39zc4t/g4Nzc08/Ovbu6////////////////////\r\n        ////////////////////////////////////////4d/g3tvc2NXW19XW2dfX2tfY2tjY2dbW2NbVlJS6\r\n        AAB+AAB+AAB+AAB+EBCFwb3J1tTU19TV2NXV19XU19PT1tLT1tPU19bW19bW1NDP0czK08/N09HR09HR\r\n        09HQ0c7O0M7N0MzMz8vLz8zLzsvKy8jIzMrJzcrIzcnIzsrLzcrKzcrKzcrLy8fIy8jIycjHycbGxsPE\r\n        xcPDx8TDyMTExcPDxsLDxsPExcHBx8LCx8TDxMHBw8DAsKy5fnunQD6TIyKKAAB9AAB9AAB9AAB9Bwd+\r\n        OjiQure8v7u9v729wb+/wby6wbq3wbu7v7u7u7i4ure3vLi3u7e3uba3t7Ozt7SzuLa1uLWzubW0uba0\r\n        trSztLCvtbGxtrSzhYKhBwd2AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABw\r\n        AABvAABvAABvAABuIiJ6fXuYramprampraqprKqpqqenq6enq6ioqqenqqemq6inrampqaenpqOjpaGh\r\n        paChpaKhpaKhp6SkpqOjpKGhpqOiqKWkr6urs7GwqKampaOjnpub////////sq+x////////////////\r\n        ////t7S0q6inop+e////////////////s7Gwp6Wmr6ytl5WWlZGRmpWS////////////////////////\r\n        ////oZ6foZ6fl5OUlpKTlpSUk5GRko+Pko2Nko6Oko6Oko+PkpCQkY6PkY2OkY+Qk5KTk5OSk5KRj46O\r\n        jouNjoqLj4yMjYyLioiIi4iJjYyMj4yMjYuLi4qKi4mJjImKioiJioeHiIWGiIeHioiIjImKioiJh4WF\r\n        hoSFhoOEiISFhIGBg4CAhIGChIGCg4CAhIGChIGBhIKCg4GBf319gH5+iIaGmZWWraqqu7i4u7a2vbi4\r\n        vbu6vbu6vbm5uba2trSztrO0uri4vrq6wLu6wLy8wL29v7y8////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////4d/f\r\n        5+Tk6ebm6efm6efn6Obm5+Pj5+Pj6Obm5OLj5eLj5uPk5+Pj5+Tj6OTk5+Tk5uPi5eLh5ePj5uXl5uXl\r\n        5ePj4+Hh4N3e3tzc3dva29nY3tva4N3d29fXycXEycXE////////////////////////////////////\r\n        ////////////////////////4uDg3tzc29jZ29jZ29ra29rb3Nra29nY2NbVjo23AgJ+AAB9AAB+AAB+\r\n        HBuIv7rG19PT2NbW2dfX2NXV1tPT19XU1tTU1tLS1tLS1NLR1NLR1dLS1NHR1NLS1NHR09LQ09HR0s7P\r\n        0c7O0s/P0c3Mz8vLzsvKzsvKzcrLz8zN0c7O0c7Nz83My8nJy8nJysjIysfHysfHyMbFycbFyMTFx8PE\r\n        xsPDxcPCxcHBxsPDvLrAmpmzUE+aMzKQAAB+AwN/AAB+AAB+AAB9AAB9IyOJW1qcmZexwsDAwL2+v7y8\r\n        wb+/xMHAw8G9wr+/wb6/vry8vbm5vbm4u7i3ubW1uba1ubW1uLW0uba1u7i3vLm5uLW1t7KztrOztrOz\r\n        qqeuHBt+AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABvAABvAABv\r\n        AABuAABuYV+PrquqsKysraqpqqenqKWlrKiorqupraqnrKinqqanqqemqKWkpqKiqKOkqaenqqmnrKmp\r\n        rqqrpaKio5+fqKWkr6urs7Gw////////////////////////////////////////////////////////\r\n        ////////////////////////r6yt////////////////////////////////////////sq+vsq+vp6Wl\r\n        nZubmJWWlJKSkZCPkpCQkY6Pk5CPlJKSlZOTk5GRko6Oj4yMkI2OkpCQkpCPkY+OkIyMkIyNkY6PkpCQ\r\n        kI6OjoyMjYqKjYuLjYuLjIqKjYqLjoyLjImKioeHiYeHiIeHiYiIiYiIioiJiIaGhoOEh4SEiISFhoOE\r\n        hIKDhYODhIGChYKDh4SFhYODhIKDhYKEgH1+fnx8gX5+fnt8fnt8iIWGm5iXraqqv7u6wL29wb69v7u7\r\n        vrq7u7i4ure3ura3vbq6wLy8wL29v7y8w7/AxMC/wL29////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////4d/f4d/f6Obm6ufn6efm6ebm\r\n        6ebm6ebm6efm6efm6OXm5+Tk5uXl5eLi5uTk6OXk5+Lg5ODf5eLi5+Tl5+fm5OLi4+Df4d/f4d/g4N3d\r\n        3NjY3tra4+Hh3tvb2NXUzcrKzcrK////////////////////////////////////////////////////\r\n        ////4uDg4uDg3dvc3Nna3dra3tvc3dvb29nZ29ra2tjZo6DADw+DAAB9AAB9AAB+CQmCpKG92NXU2tjY\r\n        2tfY19TV1NLS1NPS1tTT19LT1dLS1NLS1dPU1tTV1dHS1dDR1NDQ1NLR1NLS1NDR09DQ09HQ0tHQ09DQ\r\n        0c7O0c3O0M3O0M7P0c/Q0M7OzszMysnIysfGy8jIzMnKzMjJy8fGysfGycfHyMXFx8XExcLBpaG3cG6m\r\n        QUGWAAB/BQWBAAB/AAB/AAB/AAB+BweADAyCX16fqKW2vbm9w7/Aw8DAwb69v7u7wb6+xMLDw8LBwb++\r\n        wb6+wsDAwL6+vru7vLm4u7i4u7i4vLi5vLm4vLq5vLq5ure3uLS1uba2ube2t7S0t7OzYF6VAAB1AAB1\r\n        AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABvCgpyTUyI\r\n        oJykr6uqraqoqKWkq6ensK2ssK2rrquqq6eorKioqqenrKmpr6ysr6usramprKmprqqrtbGxo5+f////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////sq+vsrCvoJ6dmJaVlpSUlJOT\r\n        lpSUlZKTlJGRlpKSlJGRk5CQk5CPkY2NkI2Nko+QlJCRk5CQko+Pko+QlJKSko+QkY2OjouLjoqKjYqL\r\n        j4yMjYqLjImJjIqKjImKi4mJjIqKjYuLiomJiYiIioiIioeHiIWFiIWGioiIiYeHh4WFhoWFhoWFhoSE\r\n        iIWGhoODhIODhIKDhIKCg4CAgoCAgH5+fHp6f3t7gX9+fXx8hYOCm5iXsa2twb++wL6+vry8uri5t7W2\r\n        u7m6v72+vbq8v7u9w7/AxMC/wL29wLy8vrq4vru5////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////6efo6efo6efn6ebm6ebm6uXk6ubl6efo6ujo5+Tk\r\n        5uPj6OXl5+Xl5uPj5uTk5+bl5uHf5d/e5eLi5eLj5OLi5ODh49/f4d7e4+Li4+Hh3tva4d3e5+Xk19TV\r\n        x8PDzcrK////////////////////////////////////////////////////////////39zd39zd3drb\r\n        3drb3Nra3dvc3dvb29nZ29rb3Nrbq6nFAgJ9AAB9AAB9AAB9AwN+lZO52dfX29nZ2dbW19XV1tXV1dTU\r\n        2NXV2NbW1tTT09HS1NHT1dPT1tLS1tPT09HR09DQ1NHS09HQ0s/O0s7O0tDQ0tDQ0s/Q09HR0s/P0c7O\r\n        0M7OzszNzsvMzcnKzMjIzcrJzMrKy8jJy8jIy8jJy8nIu7nBh4WuXlygFRWHDQyEAACAAACAAACAAAB/\r\n        AAB/AAB/JyeMXFqcpKG0x8TDyMbDx8TDxcHCxMDAxMHAwr6/wr6+wb6+wL29wL28wL29wL6+v7y9vrq6\r\n        vbu6vby8vLq7vbm6v7y7v7y6vbq5uLW0uLW1ube3ure2ure2uLW1ramxHRyAAAB1AAB1AAB1AAB0AAB0\r\n        AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABvAABvAABvAABuJCN6joygsa6traqo\r\n        rqursK2usq6tsa2pr6yqr6usqKampqOkr6ysr6usramp////////tbGxo5+f////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////srCvnJmZmZaWmZaWmZaWmZeWmZaXlpKUlZKR\r\n        lZGRlJCRlpOSlZSTlpSUlpOTk5CRkY+Qk5GRlJKSkZCQkY6PkI2NkI2NkI2NkY2OkI2Oj42NjYyLjYqL\r\n        jouMjIqLjYuLjouMjYqLjImKjYyMjY2Mjo2Mi4uLioiJiYaGiYaGiYiHiYeHh4WFiIaGiIWGg3+Afn18\r\n        gH5+hIGChYKDhIKCgH5+gX9+gX9+cnBxcXBvfXt6gX+AiYeInJmZsK2svbq4vbq6vbu6vLm3vLm5vbu6\r\n        ure3ure2vru7wLy8vrq4vru5xMDBw7+/xcPE////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////5ePi6+jo6ujn6Obm5+Xk6ubk6+fm6+nq6efo5+Xm5+Xk6Ofm5uTl5OLj\r\n        5ePk5uPk5uPj5uPj5eLi4+Dh5ODi5OLj4uHh4+Dg5ePj5eTk4+Li5OLh4uDfyMXGx8PD////////////\r\n        ////////////////////////////////////////////////////4N7f39zd4N3e3t3e3Nzb3Nva3Nvb\r\n        3dva3tra3drbqajFERGDAAB8AAB9AAB9BAR/eniv29nY29rZ2NbW2NXV2tjX2dfW19XV19TV1tPU1dPT\r\n        1tTT1dPS1tTS1tXU1NHS1dPT2NbW1tTT0tDP0c7O1tPT09DQ0c7O09DQ1NHR1NDR09HR0c/O0M3Nz8zM\r\n        z8zM0MzMzsvLzMrKysnKnJq4bmyoGBiJFRSIAACBAACBAACBAACAAACAAACAAACADw+EVlWco6G4xcLB\r\n        xMHBx8TFycbFycXCxsPBxsPDxsPExMLCwb6+wb29wb6+wr++wLy8v7y7wLu7v7u7v7y7vLq6u7m5vrq5\r\n        v7q4v7u5vbq5ure2ube3uba2uLS0ure2ube2uLW1ZmSZAQF2AAB1AAB1AAB1AAB0AAB0AAB0AABzAABz\r\n        AABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAQFvHx95c3GYraqrsq6utK+vs66ssKyp\r\n        r6yqrauqmJWUpqOk////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////oqCfoqCfm5mYmpeXmpeYmZaWmJaWmJeWl5WVlpWVlpOTl5OTl5SUl5aW\r\n        mJaWlpSUkY6OkIyNlJOTkY+Pi4eIkY6Ok5CQkpCQk5KRkpGRkI6Oj42NkI6OjouMkI2Nj4yMjYqKjouM\r\n        jYyNjoyMjYuMjYyMjYyMjYyMi4mJioeIioeHioiIiYiIiIeIioeHioaHg3+Afnx8fXt8fnx+g4GChYKD\r\n        hIGBg4KBg4GBfHp6e3l4gX9/goCAgH9/gH5/gH5/jYuLoqChtrS0w8LAwcHAxMPDxcPCxcTDx8XFyMbE\r\n        xsTCxcPDxMDBw7+/xcPExsPExMHCxcLC////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////5ePi5ePi7Orq7Ono6ufn6efn6Obm6ufn6+np6ebn5+Tl5+Xl5uXk5+Xm5ePk5uPk5OLi5OLi5uTk\r\n        5uPj5uPj5uPk5OLj4t/g5OLi5uTk5uPi5OLi5uPj393euri4uri4////////////////////////////\r\n        ////////////////////////////////4N7f4N7f4N7f4N3e4N3d393d3tvc29na3dra3dvY3NnZwL7P\r\n        GBiGAAB8AAB8AAB8AAB9YWGn3dvb3dzb2tjY2NTV2NbX2NbW2NXV19TV19TU2NbV2dfW19TV2NbW2NfW\r\n        19bV2tnZ2NbW3tvb2dXW2NXV2dfX2NXV19TU19TU1NHR1NHR1NLR09HR0dDQ0tDQ0tDQz83OrarBiomz\r\n        REOaICCNAACCAACCAACCAACBAACBAACBAACBAgKBDAyETkybnJqzu7i/x8PEyMTEycbFysbGy8bEysXC\r\n        x8PAxcPCx8XFxMLCw8DAw8DAw8DAw8DAw8HAwr++wLy9wL28wLy6vrm4vbm4vru5vbm4vrm6v7u7vrq6\r\n        v7y7vLm5ura3ube3ube2uLW1o6CtDQ16AAB2AAB2AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAABy\r\n        AAByAAByAABxAABxAABwAABwAABwAABvAABvAABvAABuS0qJpKGps7CvtbOytLKysK2usKysmJWUpqOk\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////s6+voJ2dmpeWmZaWmpeYmpiYmpeXmZaXmJaWlpSVmJOUl5STlpSSlpKRlpKSlpSTlpSTl5SU\r\n        l5eXkZCQjomKlZKTl5aVlZOTk5KTkpGRkI+OkZCQkI2OjoqLkI2NkY6PkIyNkI2Oj46Ojo2NjYqLi4iJ\r\n        jYqLjYuMjoyMjYyMjoyMjIuLi4mLioiJioiIiomJhoSEhIGChoSFgoKDfn6AhIOEhoSEhYODhIKChoSE\r\n        hYODg3+AgX5/gX9/gn+Agn9/gYB/gH5/gX5/j42NoqGhtrW2xMLDw8HCw8DBxMC/xMDBw8LDw8DBxMHB\r\n        xcLExsPExMHCxcLCwr6+w8DBxMLC////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////6+jp6+jp6+np\r\n        6+jo6+np6+rq6Obm6ebm6ufn6efn6Obm5+Tk5uPk5uXl5uPl6Obm5+bm5OPk5uTk5+Tk5uTk5eXk5eLj\r\n        5+Lk5+Xl5+bl5ePj5eLj5uTl2tjZuri4////////////////////////////////////////////////\r\n        ////////////////4Nzc4Nzc4uDg4N/f397e4N3e4N3e3tvc3drb3Nra29ravLrNAQF7AAB8AAB8AAB8\r\n        AAB8RkWb0s7V3dra29jY2dXX2NbX2NbW2dfX2dfX2NbX2djX2dfX2tfY2tfY19XW0M7O2tnZ////3tvb\r\n        2dXW2NXV2dfX2NXV4uDg397d2tjX1dLS09HR09HR0dDQvLvHk5G5U1KhLS2TAACDAgKEAACCAACCAACC\r\n        AACCAACCAACBAACBHh6LUU+dlpO1y8jHysfIysbGycXGx8XFyMXFycbFy8jHysjIxsPDxcHBx8TDxMHB\r\n        w8HBxMLCw7+/w7+/xsPDxcLCxMDAxMHBw8C/wb69wb28v7q6v7u7v7y9wL6+wb69wb69vbu6uba2u7i4\r\n        uri5ura3ubS1Pz6MAAB2AAB2AAB2AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABx\r\n        AABxAABxAABwAABwAABwAABvAABvBQVxMC9/iYagtLOztra2sa6wsKys////pqOk////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////s6+vs6+vqqam\r\n        op6enpqanJiYmpaWm5eXnJmampeXmJSUmJWVl5WUlZOSl5OTmJSUmJSVmJWVmJaWmJaWmJaXlpSUlZOT\r\n        lpSUlZOUk5GSko+Qk5CQlJKTk4+Qj4uKj4yNkI2OkI2Oko+PkI6OjoyNj4yNj42Nj4yOj4yOj42Nj46O\r\n        j4+PjIuLioeIjYqLjYyMjYyLiIeIgoCCiIWHi4uLh4aHgoKChYOEh4SFhoSEhoSEhYKCg3+AgoGBhYSE\r\n        hoODhIKCg4CCg4CCg4CAhIGAgX9/gH5+j42Mo6Cht7O0wr6+wsDAwr7Awb7AxMPDw8LDwr/AwL++wb6+\r\n        wr6+w8DBxMLCxMLCxcLExsTF////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////5OPj6enp6+rq6+np6+nq6ujp6efn\r\n        6ujo6+jo6ufo6ujp6efo6efo5+fm6Ofn6ujo6+jp6Obm5+Tk6Obl6Obm5uTk5ePj6ebm6ujo6Obm5uTk\r\n        5uTl5ePkzMvLzMvL////////////////////////////////////////////////////////////////\r\n        4d7d4d7d2tbW3dra4N7e4d/e4N/f3dzc3Nna3tzc3t3dwsDQICCJAAB7AAB7AAB8AAB8LSyP3dvb3NrZ\r\n        3Nra3Nna29jZ2tjY29jZ2tfX2dbX2djY2tjY3NnZ2tfY19XW0M7O////////////////////////////\r\n        4uDg5eTk3tzc2NXVx8TMvLrIZmWpQD+aAACDAQGDAACDAACDAACDAACDAACCAACCAACCBQWEBweFXFqi\r\n        op65v7zDzMjHzMjHzMjHysfHycbGycfGyMXFyMbGysnJycnJxMLDw7/AxsTDyMXExMLBwb+/wr+/w8DA\r\n        xcLCxcHBxcHBxcLBxMLBw8LBxMHBwr6/wb6+wb29wL29v729v729vbu6ure2u7e2vLm5vLm5vbm4mJWr\r\n        BQV5AAB3AAB2AAB2AAB2AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABw\r\n        AABwAABwAABvAABvAABvBARwZWSPkI6Psa6w////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////s6+vqqamop6es66uq6empKCf\r\n        oJ2dnZubmZaWmZWVm5iXmpeYmZWWmJWVmZaXlpOUlpKTlZKSl5SVmZaXmJWVlZKSlpKUlZKTk5CQkpCR\r\n        k5GRlJGRlJGRkpCQkY+Pko+PkpCQkpGQkpGRk5GSk5GSkpGRkI2Oj4yNjoyMjoyNkI2OjYqLjImJjouM\r\n        j42NjouMjYuMhYSFg4GDioiIioiHhIKChoOEh4WFh4SEiIWFhoWEhYODhIKDhIODhIKChYGChoSFh4aG\r\n        hYSEhYOEhYOEg4CBgX+AgX5/goCAkpCRpaOkura3w7/AwsHBwcDAwLy9wb6+w8HBwr7Awr6+xMHBxMLC\r\n        xcLExsTFx8XFxsXF////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////5OPj5OPj6ejo6ujo6efn6+jo6ejn6efo6ufo6ebm6ujo6ujp\r\n        6ujo6ujp6uno6efn5+Xn5+Tm6OXl6Obm6ejo6ejo5+Xm5+Tl5+bm6Obm5+Tk5uTk6Ofn4+Hivby8vby8\r\n        ////////////////////////////////////////////////////////////////////4d7d2dXV2tXW\r\n        4N3d4uDg397e3Nrb3dvb393d393d3NrcICCIAAB7AAB7AAB7AAB8IyOLxcPR3Nva3NnZ29jZ2tjY29jZ\r\n        3Nna3Nrb3Nra3Nna3Nra3NnZ////////////////////////////////////////////5eTkxMLScnGw\r\n        VFOjCgqGAwODAACDAACDAACDAACDAACDAACDAACDAACDAACDISGOWFahqae/zsvMzsrLzMrKzcrKzcnJ\r\n        zMjHzMnIy8jIy8fHysfGy8jHzsvLzMrMysfIyMXEx8XEysjHyMbFw8DAwb+/w8DAxMHBxcHBxMG/wr++\r\n        w7+/xMHBw8HBxMDBxMHBxMDAw7+/wL6+v728vbm5u7i4vLi3vbm4vbq6vry6u7m5QUCNAAB3AAB3AAB2\r\n        AAB2AAB2AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABw\r\n        AABvAABvCwtykI6P////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////s66uq6empKCfs7CuqqemoZ+enpyc\r\n        nJqampeYmpaXmpeXl5SVlpOUlZKSlZGQlJGRl5SVmJaWmJWVlpOTlpOUl5SUmJWVlZOUk5GRlJGRlJKU\r\n        lZOUlZOSlZOSk5KTk5GSkY+PkY6OkY6PkI2OkY+PkI6OkIyNkI6PkY+Qj4yMjoqLjIqLjouMkI2NjIuL\r\n        hISGhYSFiYeGiIaFh4SFhYODhoSEhoOEh4WFh4WFiIWGh4WFh4WEg4GBg4CBhYOEhIODhYSFh4WGhYKD\r\n        g4GBg4GBgX9/gH5/f3x9fnx9kI+PpaKjuLW0wL27wLy8wsDBwsHCw7+/xcDAxcLDxcLDx8PFx8XFxsXF\r\n        x8bGyMPCycK/////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////6ujo6ujo6ufo6Obm6eXn6ebm5+Tk5+Xl6OXm6Obm6uno6efo5+Tl6eXm6ubn6ebn\r\n        5+Xl5uPk5uTk6Ofm6ujo6ebo6OXn6Obn5+bm5+bm5uTl5+Tk6Obl3Nnavby8////////////////////\r\n        ////////////////////////////////////////////////5OPj5OPj4d7f39zd4d7e4uDg4N7e4dze\r\n        4t/g4N7e3tzcy8nVISCJAAB6AAB7AAB7AAB7AgJ8ubfL3Nrb3drb3dra3dvb3Nvb3tzc3t3d3Nra3Nna\r\n        3Nra////////////////////////////////////////////////////xMLSAACCAACCAACCAACCAACC\r\n        AACDAACDAACDAACDAACDAACDDw+IYmGmoJ680M3Nz8zMzsvLzsvMzsrLzsvLzsvLzcrJzcrJzcvLy8nK\r\n        zMnK0MvJ0czK0M3L0M3Jz8vJzcnKy8jKy8nJy8nJycbGyMTDysfGyMXExMHAwr6+w8DAxMHBw8C/xMDB\r\n        xsLCxcHBxcLBw8LBwr++wL69v728vru7ure4u7i4vbq6vru7fn2lAAB3AAB3AAB3AAB3AAB2AAB2AAB2\r\n        AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABwAABwAABwAABvAABvAABv\r\n        AABv////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////s7CuqqemoZ+esq6wqaamoZ6enJmZmpaX\r\n        l5SVlpSUmJaVmJWVmZSTmJKTmZWWmZeWlpSTl5SUmZaWmZaXmZiYl5aWlZKTlZKTlpWVlZOUlZKTlpSV\r\n        kI6Oi4mIjouKko+Rko+QkpCQkpCQko+PkY+PkI6OjoyLjouLjIqLjouLkI2Nj46OjYyNhoaIhoWGioiI\r\n        iYeHh4aFh4aGh4OEh4OFiIaGiYaGiYaHiIWGhoSDhIGChIODhIKChYKDhYODhYOChYOEg4KCg4CAgX9/\r\n        gH5/gH5/gX9/gH5/gX5/k5GRp6Sjuba3w8HCxMLCxMDAxcHCxsLExsLDx8PFxsXHx8bGyMPCycK/xMHC\r\n        xMHBxMHB////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        4t/f5+Xl6OXl5+Xl6eXm6OXn5+Tl6eXm6Obn6Ofn6ebm6Obn6ebn6+fo6ujo6ebn6Obm6Obm6Obm6ujn\r\n        6+jp6ebo6Obm6Ofn6ufn6ujo6ejo6unp5+TkzszMzszM////////////////////////////////////\r\n        ////////////////////////////////6OXm5eLj5uPj5OLi4uDg4d/f4d7f4+Dg4+Hh4uDg4d/e3tzd\r\n        QUGYAAB6AAB6AAB6AAB7Dg6BqKbF3tvb4Nzc4Nzd4d/f4N/f3tzc3t3d////////////////////////\r\n        ////////////////////////////AACAAACAAACBAACBAACBAACBAACCAACCAACCAACCAACCAACDAACD\r\n        BweFS0qeuLfGzcvN0s7O0c3N0MzMz8zLz83N0MzNz8vLz8zLzszMz8rLz8zMzszNz8vN0s3M0s/K0tDJ\r\n        0dDH0cvI0cvMzcrKzcrKzMrLzMnKzMnHy8jGyMbEyMTEyMTEx8TExcLCxcHAx8TDx8TExsHCxMHBxcLC\r\n        xMLBwsHAwb+/wLy9vLq7vLm5vrq6vru7ZGKbAQF4AAB4AAB3AAB3AAB3AAB2AAB2AAB2AAB1DQ16FxZ9\r\n        AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABv////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////sq6wu7a2rquqoqCgnJiYmZWWm5mYnJmZnJqa\r\n        nJiXmpWVmJSVmpiYmJWVmJWWlpSUl5aWmpeYmpiYmJWWmJaWl5aVlZKTlpSUlZOUkY+Pj42Mko+Qk5GS\r\n        lJKTk5GRlJKSk5CQko6PjoqKjIqJkI6OkI2OkI2NjoyMjo2NkI2NjIqKiIaHi4iIi4iJioiIioiIi4eJ\r\n        i4eIiYeHiIaGhoOEiIWGioeIiYaGhYODhoSFhoSFhYODhYODhoSEhIGChIKChIKCgoCBgoCBgoCAgoCB\r\n        goCBgYCAgX9/gn+AlZGTq6envbq7w8HBxcLDxMDBw7+/w8HBxsLDxMLCxMLCxMHCxMHBxMHBxcPDxcPD\r\n        xcLC////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////4t/f4t/f5+Tl5+Xl6OXl\r\n        6Obm6Obn6efn6ebn6ebn6efo6ubo6ubo6ufo6+jp6+rq6ujo6ufo6+jp6unp6+np6+jp6ujp6ujo6efn\r\n        6ubn6+jn6unp7Ovr5+Xlv72+v72+////////////////////////////////////////////////////\r\n        ////////////6OXm6OXm5uTk5eHi4t/f4uDg4t/g4d7e4N7e4eDg4+Li49/g4d/fQkKXAAB5AAB6AAB6\r\n        AAB6AwN8ioi44t7e4t7d4N3e4d/f4N/f////////////////////////////////////////////////\r\n        AAB/AAB/AACAAACAAACAAACBAACBAACBAACBAACBAACCAACCAACCAACCGRiLQkGbjIq309DP0s/O0c/O\r\n        0c3N0c3N0c7O0M3N0c7O0M7Oz8zMz8zN0M3O0s7N08/L087L0s7L09DL0c/Lz83K0tHJ0c3Jz8rH0c/J\r\n        z83IyMTFx8PEy8nIycXFx8TDyMfGyMbFyMbFx8TExsPCxsXEx8XEx8TDxcHBxcPCxMLCv729v7y7wL29\r\n        wL6+wb6+wLy8uLW4WlmYAAB4AAB4AAB4AAB3AAB3AAB3AAB3AAB2AAB2AwN3cW+dLy6GAAB1AAB0AAB0\r\n        AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABwAABwAABwAABvAABvAABvAABu////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////u7a2ure3qqmopqOjoJ2dnZuanpubnZqanJqampiYmZeXmZeY\r\n        m5eZmJWWlpWUl5WWmZaXmJaWmZiYmZiXmJSUl5OUmJeXlpWVlZOTl5WWlZSVlJGSlZKTlZKSlJGRlJKS\r\n        k5KSkpCQkI2OkY6Pko+QkY6OkIyMjouMjouMjouLjouLjImKi4mKioiIi4iIi4qKjIuLiomJh4aGh4aG\r\n        iIaHioeIiIaGhoOEh4SGh4aGhIODhoWFh4WGhICChYODg4GCg4GBg4KCg4GCgn+AhIGBhIKCgX+AgH1+\r\n        gH19gH19fnt9k5CRrKurwL2+wr+/wb29wLu8wb6/xcPExMLCwr6+w8HBxcPDxcPDxcLCyMTFx8TEx8TE\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////6ebn6ebn6ebn5+Tl5eHi5uTl6Obm6+np6ejo\r\n        6Obm6ebn6ebn6ebn6ujp6ujp6ujo6ufn6eXm6+jo7erq7erq6+jp6efo6unp6+jq6ufo6efn6ebn6ebn\r\n        39zdv72+////////////////////////////////////////////////////////////////////////\r\n        6OXm6Obn5OPj4+Dg5OHh5OLi4d7f4N7e4t/f4+Dh4+Dh19XbSUmaAAB5AAB5AAB6AAB6AAB6cXCt4+Dg\r\n        4t7d4N3e////////////////////////////////////////////AAB+AAB+AAB+AAB/AAB/AACAAACA\r\n        AACAAACAAACAAACBAACBAACBAACBAwOCBgaET06fmpi7wr3J1NHR09HR0s/Q0c7O0c3N0s7P0s/Q0c3O\r\n        0czM0s7O0c7O0MzO0s7L1dLK1dPK1dHL1NLJ09LIz8zJzMnK0M7K0c/Lz8zI0c/I0M7IysbFyMTFycfG\r\n        ycbHycbGycbGxsLCxsPCyMTExcLBxcPCx8TEx8TDxMLBxMLCxMLCwb2+wb29wL6+wLy8wb6+wb++s7G5\r\n        OjmOAAB5AQF5AAB4AAB4AAB4AAB3AAB3AAB3AAB2AAB2YWCZvLm5b2ycIyKBAQF1AAB0AAB0AABzAABz\r\n        AABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABuAABv////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////ure3qqmotrS0qKamnpubnJmZnZqam5iYm5iYnJmanJmampeYl5SUmZaWmpiZ\r\n        mJaXmZaXmZiYmJaWlZGSlpOTmJaWmZeXl5WVlpSVl5WUlpOUlpOUlZKTlZKSlJSTlJOSlJKTlZOUkpCR\r\n        kY6PkI2NkY6NkY6PkI+PjoyNjImKjYqLjIqKi4mJi4iJioiIiomJioiJioeIioiIiIeHiIWGh4WFh4WG\r\n        iIaGhoSEhoSEhoWFh4WFhoOEh4SFhYSEhIKChYODhIODg4CBg4CBhYKDhIKChIGCgoGBgH9/fHl6fXp6\r\n        f359g4CBmJWVraqqvru6wLy8wb6+wL6+wr29xcLCx8PDxsPCx8TEyMTFx8TEx8TEycTGysbHy8fJ////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////4N7e6OXl6efm5+Xl5eLi5OHi5ePj5+Xl6ebn6Ofn6Ofn5+Tk5+Tk\r\n        6efn5uTk5+Tk6efm6+jo6+jn6ufm6ufn6+rq6+np6ujp6ujo6ufn6OXm6efn5uTkz83Nz83N////////\r\n        ////////////////////////////////////////////////////////////////6Obn6Obn5uTl5eLj\r\n        5ePj5ePi4+Hh5OHh5eHi4+Li4+Pj3tzeXFuiAAB4AAB5AAB5AAB5AAB6UE+c4+Dg////////////////\r\n        ////////////////////////AAB9AAB9AAB9AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACA\r\n        AACBAACBGhqLTEygmpq91dLS1NHR1NHQ08/P0tDQ09DQ1dLR0tDO0s/PvrzIq6nAko+2vrrH0c3P0c7O\r\n        1dLM1tXK1tbQ1tXS1dTM1NLJ0czKzsrKz8nIz8nJzsrKzsrKzcrIzMnHy8nIycfGycbFy8fHy8jHycXF\r\n        yMPDyMTDxsTDxsTDx8TExsLCxcLBxMLBw8HAwsC/wsDAwr+/wb29wb++w8C/tLC6KiqJAAB5AAB5AQF5\r\n        AAB4AAB4AAB4AAB3AAB3AAB3AAB3BQV4paKwu7i3lpOrQD+MAAB1AAB0AAB0AAB0AABzAABzAABzAABy\r\n        AAByAAByAABxAABxAABwAABwAABwAABvAABvAABv////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////trS0uLa2q6iopaKin5ycmJSVnJiYoZ+en52dnJqam5iYnpubnZuampiYmZeXm5qamZeY\r\n        lZGSlpOTmZeYmJeWmJeWmJaWmZaVmZaWlpWVl5WVlZOTlZKSlZKSlJGRko+Qko+QkY6Nko6NkZCQkZCQ\r\n        j46Oi4iIi4iJjYqLjYqLjImJjIqKjIiJjImJi4eIioeHiYeIiIaHiYeHiYiIiYeHh4WGhoSEhoOEh4WF\r\n        hoWFh4WFiIWGh4WGh4WFhoSFhoSEhYOEhIKCgoCAg4GCg4KCg4OCgH9/fnt7fnt7goB/g39+gH18e3t8\r\n        g4GCmZWVq6iowL29w7+/xsTEx8PEx8PEx8TDyMTFyMbGycbGycTGysbHy8fJy8fIysfHyMXG////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////4N7e4N7e5ePj6Obm6efn5+bm5uPk5OHi5eLi5uPk5ePk5uTk5+Tk5ePj5uTk5uPj5uLj6ebm\r\n        6+jp7Ojo6ufn6efo6efp6ebn6ufn6+jp6+np6ujo7evr5uPkv72+v72+////////////////////////\r\n        ////////////////////////////////////////////////6unp6unp5+Xl5eHh5ODg5uLh5eLi5eLi\r\n        4uDg397d4+Hg5OHiXl6kAAB4AAB4AAB5AAB5AAB5UE+c////////////////////////////////AAB8\r\n        AAB8AAB8AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACB////GhqL1tPZ\r\n        2dbV1dPT1NHR1NHQ1NHQ1NHR1NHR1NLR09HQ1NDPdXOtDQ2IFBOKZ2Wo1NHR1tPT19XT19bO19XO19PP\r\n        1tTO1dXN1dTQ1NLR0c7N0MzLzsvLzcjIysbFy8jGzcrJzMnIzcfGzsjHzcnIysjHysfGycbFycbGycbG\r\n        ycbFxsPDxsTDx8TDxMDAwb6+wb++w8HBw7+/v7u7wL29l5WxBgZ8AAB6BQV7CAh8AgF6AAB5AAB4AAB4\r\n        AAB4AAB3AAB3AAB3VlSUwLu6v7q4vbq5enihLSyFBQV2AAB0AAB0AABzAABzAABzAAByAAByAAByAABx\r\n        AABxAABxAABwAABwAABwAABvAABvAABv////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        uLa2raqqsK2uoZ+gnJubnZubnZqbnZqbnJmanJuanZuanpubnJmam5qam5qam5iYmZaWm5iYm5mam5qa\r\n        mJeXlpWVmZeYm5mampiZmZiYlpSVlZKTmJWWlJKSkY6Pko+Pko+PkY6Oko6QkI2Oj42Nj4yMkY6Oj46O\r\n        jYyMjouLjoyMj4uLjYmJjImJi4iIioiJiIaHhYSEhoSFh4WGh4WFhoSFh4WFiYeHiYiIiIaGiYaGh4WF\r\n        hIKCg4GBhYKDhoSFhYSFg4GBg4CAhIGBg4CAgX9/f319f35+gX9/gn9/gX59fnt7fnt8fHp7e3h4gn9/\r\n        mZaWsa2uxcPDxcLDxsLDycXGycfIyMbIycbIy8bIy8fIy8fIysfHyMXGzMjKzcrMy8jK////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////5OHi5OHi\r\n        5OHi5ePj5+bm5+bm5+Xl5OLj5eLi5+Tl5uTl5uTk5uPj5ePj5+Tl6ebn6ebn6ufo6ufo6ufn6ujp6ejp\r\n        6ebn6ubn6ufo6+jp7Onp7Orp7uzs39zev72+////////////////////////////////////////////\r\n        ////////////////////////////////////6unp6efn5uPj5ODh5eLj5uTk5uTj4+Hh4N3d4uDg5ePj\r\n        eHeuAwN5AAB4AAB4AAB4AAB5AAB5////////////////////AAB6AAB7AAB7AAB8AAB8AAB8AAB8AAB9\r\n        AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AACAAACA////////////////1tPZ29jY19XU1tPT1tLT\r\n        1dLR1dHR1dHR1NLR1dLS1NHRaWipAQGDAACDHx+Ozs3S19PW2NTS2NfR2NfQ2NbS19TQ19XP19fT1tXT\r\n        09DQ0M3N0c3N0c3MzsvKzsvKz8zLz8vKzcnJz8rJ0c7N0M/PzszMy8jIysfGzMnIysfHycXFyMXFx8XE\r\n        yMXFxsPDxcPDxsPDxsLCxMHAxMHAeXemAAB6AAB6Hx6FXFubAAB5AAB5AAB5AAB4AAB4AAB4AAB3AAB3\r\n        CQl6ram0vrq5vrq6vLq6p6WwVFKTAAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABw\r\n        AABwAABwAABvAABvAABv////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////raqqsa6uqKem\r\n        pKOioJ6dnpubm5qZnJmanZubnZqbnZqbnZqbnJmanZubnZubnZucnZqbnpuanJqamZiYl5WWmpaYm5iZ\r\n        mpiYmpiYmJWWlpOUmJaWlpOTkI2OkY6PlZGPlpKQko+Pko+Pk4+Qk5CQk5CQk5CQkI6OjYyMjIqKjImK\r\n        jYmKjouLjouLjIqKjYuLi4iJioeIiIaGiYaGiYeIi4mJjYqKjImJi4iJiIeHh4WFfXp7eHZ2eXh3hIKB\r\n        iYaGh4OEhYKChYGChICAgX5+f319fXx7f35+gX+Ag35+gn19gX5+f319fHt7fXp7fHp6fXt7h4aGnZub\r\n        tLGxyMXFycXHyMXGyMXHycbGycTFyMXFxsTEyMXEzMjKzcrMy8jKysbGyMTEysbG////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////4+Dg5eTk5eLj5ePj5OPj5ePk\r\n        5uPk5ePj5OLi5+Xl6Ofn5+bn5+Xm5+Xm5uTk5uTk5+Xl5+Xm6Obn6Obm6efn6uno6ebm6ebm5+Xl6efn\r\n        6ujo7erq6ujozcvLzcvL////////////////////////////////////////////////////////////\r\n        ////////////////////////6efn6efn5+Tl6OXm5+Xm6Ofm5+Xl5uPj4uDg5ePjeHeuAAB3AAB3AAB4\r\n        AAB4AAB4AAB4////////AAB5AAB5AAB6AAB6AAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB9\r\n        AAB+AAB+AAB+AAB/AAB/////////////////////////4d7e4d7e2tfW19PT2NXV19TT19TT2NTU19PT\r\n        19TT19TTnpy9DAyIAACDBASFpaK/19LR2dXP2djQ2dnV2NjV2NXO2NXM1tPN0s3M0MzM0c3M0s7O1NLR\r\n        09HQ0MzMzcrJzcrKzsvLzsvK0c7N0M7OzsvLzcnJzcrJzcrKy8jIycXFycXFyMbFycfHyMXGxsPEyMXF\r\n        x8XEycbFyMTER0aVAAB7AAB7MDCLpKC2HBuEAAB5AAB5AAB5AAB5AAB4AAB4AAB4AAB3XFqYw7+9wL29\r\n        wL29wb28wbu8iISkLy5+AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABw\r\n        AABvAABvAABv////////////////////////////////////////////////////lpSUko+Pnpubl5SU\r\n        ////////////h4OD////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////uba3uba3srCxqqion5ycn5ycnp2d\r\n        npycnpycnZqbnJqam5manJmbnZubn56dn52en52dnpybnJqamZiZmZeXmZeXmZeXmZiXmpeXmJWWlJKS\r\n        lpOSlpOTko+Rk5CRmpaRmpaPkY+OkY+QlJGSkY6PkY+PkpCPkY6OjYuMjYqLjIqKjImKjouMjouLjYqK\r\n        jYuLjoyMjouLjYqKjYqKjYuMjIqLi4mJi4iIioiJiYiIYF5ePDs7T05NVlVTXlxacm5tgX5+hoODhoOD\r\n        hoKDg4GBf35+f319gH9+gX9/gH19gn5+gn+AgX9+f359gH+AgH9/gH5+gH5+fXt8e3h5hoSEn5ydt7S1\r\n        ycbGycfGyMXFyMPDxsPDyMTFzMjKzMvLysfIysbGyMTEysbGzMrJy8fIyMTF////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////4+Dg4+Dg5ePi5eLj5OLj5OLi5eLj5uTk5uPj5eLi5eTk\r\n        5ePj5ePj5+Xl5+Xl5OPj4uHh4+Hh5OHh5eLi5+Xk5+bm6efn6Obm5+Xl5uXk5uTk5uTk6ufn5eLiv768\r\n        v768////////////////////////////////////////////////////////////////////////////\r\n        ////////6efn6efn5+Tl7Orq6ujp6ujp6ujo5uPj////////////AAB3AAB3AAB3AAB4AAB4AAB4AAB4\r\n        AAB4AAB5AAB5AAB6AAB6AAB6AAB7AAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB+AAB+////\r\n        ////////////////////////////////4d7e39zb2tfX2NXV19TU2NXV2dfX2NTV2NXV2tfXubfJAgKD\r\n        AACDAACDg4Kz2tbQ2tbS2tfT2tnV2dnR2dnO2dbO1M/MzsnK0M3M0c7N0s7O1NLR29fX2NPT1dLQ08/N\r\n        0M3MzsvLzMjIzMnJzMnJzcvKzcvKy8jIy8jHysjHysfGycXFyMTEyMXFyMXGycbGysjHysjIwb3EMjGO\r\n        AAB7AAB7MzKNuba9f32oAAB6AAB6AAB5AAB5AAB5AAB4AAB4AAB4DQx7u7a5wb++wb6/w76/wr6+rKqp\r\n        Ly5+////AAB0AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABwAABwAABwAABvAABvAABv\r\n        ////////////////////////////////////////oJ+fqKenlpSUko+Pnpubl5SUr62tp6WkoJych4OD\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////uba3vbu7raqqpqOjo6ChoZ+foZ6fn56en52dn5yc\r\n        n56enZydnZqbnpucnpycnpydnpydnJqbmpiZmZaXmZaWmZiXmpiYmZiXmJaXl5SUmJWVlZKSkY6PlJKT\r\n        mZaTm5WQlpCOk5CQk5GRk5GSko+QkY+OkI2Nj42Nj46OjouLjouLjoyMjouLjImKjIqKjIuLj4yMjouL\r\n        joyMjIqLiIeHhoWEiIaGiYeHioeIKyopHx8eMDAvKSgnIyMiOjk4XFtafnx8hIODhIKChIODhIKChIGB\r\n        hIGBgoCAgn9/goB/gX+AgH1+gX5+gn+AgX9/f3x9f319fXt8enh4e3h4e3h4e3l5iYaHoZ6eubW2ycXE\r\n        yMPDx8PEysbHysfHysfGy8jIysbGy8fHzMrJy8fIyMTFyMTFx8PEyMbE////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////5OHh5OHh49/f4d3e4uDh5eHh5uLi5uPk5OLi5OHh4+Dh5N/e5N/f5OHi4+Hi\r\n        4+Hh4+Hh5OLj5uHg59/e5+Lg5uTk5uPk5uPk5uPk5+Xm5+Xm5uPj5+Pj29fXv768////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////7Orq6ujp6ujp6ujo////////////////AAB2AAB3AAB3AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5\r\n        AAB6AAB6AAB6AAB6AAB7AAB7AAB7AAB8AAB8AAB8AAB7AAB9AAB9////////////////////////////\r\n        ////////////////4uDg4uDg3dvb29jX2dXU19TU2dbW2dbW2dbW29bVzMnPLy6TAACCAACCTEuf3NjQ\r\n        29jT29rW29nT2tjO2NfQ1tPT1tLSzMrJyMbF0c7N////////29fX2NPT1dLQ3dnX1dPS08/QzcnKyMXF\r\n        y8rJ0M7OzcrKysbGzMnJy8nIycfHysfGycbGysjIysjIyMbFysjHysjIo6K5IB+IAAB8AAB7R0aVw8DB\r\n        uLe9Cwt+AAB6AAB6AAB5AAB5AAB5AAB5AAB4AAB4W1eXw7+9wr+/xcPCxcLCtbGxhoOCnpyc////////\r\n        AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABv////////\r\n        ////////////vri2q6alqqemoJ+fqKenrKqpr6yss7CwsrCwr62tp6WkoJych4ODcW9u////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////vbu7raqqu7q5sK6upqSkop+fop+foqCgoqChoqCgoKCfn52dnpuc\r\n        nJmZnZubnZqbnJqanJmZm5iZm5manpubnZqanJmYmZeXmpeXmZeWlZKTlJGRl5WVlpOVmJKSnJaSmJSS\r\n        lpOTlpSUlpOTk5CQkpCQkpCQkI6Oj42Mj46NkI2Nj4yNj42NjoyNj42Nj42Mj4yMjouMjYuLiYeHiIWF\r\n        iYeHi4iJbWtrISAfGxoZHRwbIyIhPTw8HBsaQD8+YWBehIODh4WFhYODbGpqXl1bZ2VkbmxrfHh5g4GB\r\n        goCAgoCBgoCBgn9/f3x8fnt7gH1+gX9/fnx8fHl5fHh5e3h4fXl5fXl5fHl6iYeHoZ2dubW0ysbFysbH\r\n        ysjIy8jIzMfHysXFyMTDycfFycfIyMTFx8PEyMbEysbGysTGyMPE////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////3NnZ4d/f4N3d4d7e4uDh4+Hh5N/f4uDh4N7f4N/f4t/f5N/f5ODg4uHh4t/g4t/f4+Hh4+Li5+Pi\r\n        6uDd6t/c5uHg5OLj5eLj5uLj5uTl6Obm6efm5uTkycfHycfH////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////AAB0AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3AAB4AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6\r\n        AAB6AAB7AAB7AAB7AAB8AAB8AAB7////////////////////////////////////////////////////\r\n        ////4uDg4d7e3dva29jX2tfX2dbW2NbV2tfV2tXU1tLTQ0OcAACCAACCCQmFxsLK2tjS29rU29jU2dXR\r\n        1tHR0c3O0s7OysbFyMbF////////////////////////3dnX1dPS3NnY0tDQycbGzMrJ0c/PzcrKysbH\r\n        zsvLzcnJy8jIzMrJzMrKzMrJy8rJysfHycbGyMXFkY+yFxeFAAB8AAB8ZWOgx8PExMHDS0mWAAB6AAB6\r\n        AAB6AAB6AAB5AAB5AAB5AAB4CQl7ubS6yMO/y8jFyMTCx8HAt7Kxnpycnpyc////////////AAB0AAB0\r\n        AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABwAABwAABwAABvAABvAABv////////////////vri2\r\n        q6alqqemr66usa+vs6+wtrO0trS0trS0t7S1tbKyr6urmJSUcW9uiIaG////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////u7q5urm5qqmopKKipKGho6CgoZ+foJ+eoaCfoZ+gn52enZubnpubnpycnZyc\r\n        nZubnJuanpycn5ycnpubnZmZm5mZmpmYmJeWlpOTlpOTmZiXmZaXmJWWmZaVmJaVlpOUlpOUlpSUlpSU\r\n        k5KRkpCQko6Ok5CQkI+Pj4yNkI2NkI+OkY+Pko+QkI6NkY6OkI6Pjo2Nj42MjYqLjYqKjYuLdXNzPz4+\r\n        GRkYHR0cRUREaWdnGhkYKCgnSEdFcnBxiYaHXVpaIiEhLy4tPj07PTs7VVJTYmBggX9/hIGChIGCgoCA\r\n        gX9/f319gX5+gX59gH5+gH19gH19f319fnt8fXt8fHl6fHl4fHp6e3l5jImJpKChvLm6yMbGy8fHy8bG\r\n        ycTEycXGysjHycbGx8HCxsLCysbGysTGyMPEzMK+x7u3xcDA////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////3NnZ3NnZ393d393d\r\n        4N7e4uDg4d/f4d7e393d39zc4d7e4d/f4d/g4+Hi5OHi4t/g4N3d4d/f4uDg4t7f5+Dd6ODc5eDg5OHi\r\n        5uLi5eLi5uPj6Obl7Orq4+Liu7m5u7m5////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////AAByAABzAABzAABzAAB0AAB1\r\n        AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6AAB7AAB7\r\n        ////////////////////////////////////////////////////////////////////5ePi5ePi3dvb\r\n        29ra3Nrb2NbW1tTV2NbX2NfX1dPVcG+uAACCAACCAwODlJG619TV2NXV2NXW1tPT2NTTzcrJtbKzysbF\r\n        ////////////////////////////////////3NnY2dbW0M3N0MzM0c7OzcvLy8jJzszMzszLzsvLz8zL\r\n        zcvKzMrJzcrKzMnJysfHx8TFeXepBAR+AAB8AwN9eXipyMbGy8jGpKC4BgZ9AAB7AAB6AAB6AAB6AAB5\r\n        AAB5AAB5AAB5bWuhycPAx8LBxcLBxsLBxsPDrqurmZaV////////////////AAB0AAB0AAB0AABzAABz\r\n        AABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABvBARwLCx7vri2t7KxtLKxt7W1trOz\r\n        trKztLKytbOztbOzsq+wr62tsq+wrKmpnJqZiIaGqaennpyckI6OmZiYpKKin5yck5CPdHFx////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////urm5rayso6Kiop+gop6foZ+fo6Ggo5+foJ6eoJ6edXNzXFpZcG9tiIeGl5aWnZycnZuanJmZ\r\n        mZeYnJmZnJqZm5qamZiXl5SUl5WVmpiYnZmXmpeVlZSVlpSVlpSUlJKSlJKRlJGRk5CRkY6Pko+Pk5CR\r\n        k5GRkZCPkpCQko+QkI6OkI6Oj42NkI6OkY6PkI6Ojo2NkY6OkY6Oj4yMdXN0V1ZWIyMiKyopYF9eZGJj\r\n        GRgXHRwcOTg3aGVliYaGNzY2ISEgHBsaHRwbHRwbKyopQD8/Z2dngH1+hICBhIKCgn+AgH5+gX59gH18\r\n        gH19gX5+gH5+gH5+gH5/gH5+f3x8fXt6fXt7fHp6fXt7fHp6end3jImJpqSivbu7ycfHycbHycfFycbE\r\n        xsLCxL/Bx8TEyMTFy8bGzMK+x7u3xcDAz87NzsrKzsnJ////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////3tvb3tvb3tzc393d3tzd393d4t7e393d\r\n        3Nrb39vc4d/f4N/f4N7e4+Dg4uDg4N3d4N7e4uDg4uDg4d7f4t7f49/g4+Hh5OLh5OLg5OHh5eLi6OXl\r\n        6efn2dfXu7m5////////////////////////////////////////////////////////////////////\r\n        ////////////////////////AABwAABxAABxAAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1\r\n        AAB2AAB2AAB2AAB3AAB3AAB3AAB4AAB4AAB4AAB4AAB5AAB5AAB6AAB6////////////////////////\r\n        ////////////////////////////////////////////////////////5ePi4N7e3dra29jZ2NbW2tjX\r\n        2djY2NbX2tjZi4q6AgKCAACCAQGCXl2m19PT2NXV2NXV19XU1dLSx8TEtbKz////////////////////\r\n        ////////////////////29jY29jY1dLR0s/Oz8zMzsrLzsvLz83MzszNzsvLzMjIzMrJzszLzcrJzMnJ\r\n        zMnJycbHWFedAAB9AAB9ExOEi4qwycfGycbFw8DDRUOUAAB7AAB7AAB6AAB6AAB6AAB6AAB5AAB5EBB/\r\n        qqe3xsLCxcPDw8PCw8HBvLm4mZaVura3////////////////////AAB0AABzAAB0AABzAABzAABzAABy\r\n        AAByAAByAABxAABxAABwAABwAABwAABvAABvBARwLCx7hIKftLO1uLW1t7O0t7S1uLa2t7S1tbKytbOz\r\n        tLKysq+vsa6ttrOyt7OzrqusqaennpyckI6OmZiYpKKin5yck5CPdHFxh4OD////////////////////\r\n        ////////////////////////////////////////////////////////////////////////rKusrKus\r\n        pKOjoqChoqCgoqChop+gpaGgpaGgX11dLCsqPz49KyopT05OdXRzgH1+mpeYmpmYm5mYnJmZnZmZnJiY\r\n        m5iXmZaWmZeXmpiYmpeYm5eXmJWUmJWVlpSUlJKSlJGRlJCRk5CRk5GRk5GRlZSTlZOSlJKSlJKTlZOU\r\n        k5GSk5GQkY6Oj4yMkI2NkI6Oj42OkI6OkY+Pj42OWllYSEdGKysrOzo5YWBebm1sISEgHBwbNTQzZWNi\r\n        iYeHOTg3JCMiJCQjIyMigX9/KCcnLSwqUlBPbWxthIKCgoCBgH5+gX5+g4CAgn5/gH19gX19gn5+gH5+\r\n        f35+f319fnx7fnx8fXt7fnt7fXt7fHl6end3e3l4fHl5fHp6kI6Pqaanu7e2xsHAysfHy8jIycbGyMbF\r\n        yMPDw7e1v7OxxsPBz87NzsrKzsnJzsnIzMjJ////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////2NfX3Nra3Nra3dra39vc4N3d4d/f4d7e3tvc3tzb4N7e4N7f\r\n        4t3c5N7d4N3d3tzc4d7e4t/f4t/g4uDg4t/g49/g5OHh5OPh4+Dg4t/g5OHh6OTl5ePjx8XFx8XF////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AABwAABwAABxAABxAAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2\r\n        AAB3AAB3AAB3AAB3AAB4AAB4AAB5AAB5////////////////////////////////////////////////\r\n        ////////////////////////////////////////5eLj5eLj3tvc2NbW3NjX39zb2tfX2NbX29nZwL7O\r\n        Dg6HAACBAACBGhqMzcvR19XV2dfX19XV2dbWysfHysfH////////////////////////////////////\r\n        ////2tjY2tjY1NHR0c7OzsvLzsvK0M3N0c/P0M7OzcvLzMrJzMrKzcrKz8vKz8vKzcrKzMnJLi6PAAB+\r\n        AAB9HByHm5m1ycbGxsTDx8XEn5y2BgZ9AAB7AAB7AAB7AAB6AAB6AAB6AAB5AAB5PDyPxMHDxsPDxsPC\r\n        xsLCxsTDxcHBura3ysfHyMbGure1////////////////AAB0AABzAABzAABzAABzAAByAAByAAByAABx\r\n        AABxAABxAABwAABwAABwAABvAABvAwNvTUyMn5yqt7S0uba2ura3ube3uLW1tbOztbS0tbGxtLCwtLGx\r\n        tLGxtLGwtbKytLGxsq+vsa6usa+urq2rqaemn5ubh4ODn5ube3h3////////////////////////////\r\n        ////////////////////////////////////////////////////////s7Kys7KyqqmopaOjpKKioqCh\r\n        oqChpaKiqaWjKyopODc2TU1MHx8eISAfICAfPDs6a2lnoJybnpuanpuanpmZnZmZmpiYl5WVl5WUmZiX\r\n        m5mZnJiYm5eWmpaXmZeXlpWVl5WVlpSUl5WVl5aVl5WWlZOUlJKSk5CRlZKTlZOUlJOTk5KSkpCQko+P\r\n        kpCQko+QkI2Oj4yNj4yNkI6OPDs6Hh4cLCsrOTg3c3JxZmRkKiopHR0cIyIhaWdnioeIIyIhHRwbMC8u\r\n        QD8+hoOENjU0Hh0cRENCWVhWhYSDg4GAgn9/hIGBg4CAgX9/gH59gn9/g4CAg4GBgX+AgH5+fnx7fXt7\r\n        fnt7gH18gH19fXp6e3h4fHl4fHl5e3l4fHp6fHp6f3x9k5GRrKmqxsTEzsvMy8nKx8PDxL++xcG/x8TD\r\n        yMfHzMjIzMfGzsnIzMjJy8fGy8fHzMnJ////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////2NfX2NfX29nZ29jZ29jY3tra4Nzc4d/f4eDg4N7e3dra3tzb397f4t7e49/e39zc3tvc\r\n        4d/e4d/g4t/g4+Dh4+Hi5OHj5uLj5eHi5OHh5OHh5ePj6Ofo4N/ftrS0trS0////////////////////\r\n        ////////////////////////////////////////////////////////////////////AABwAABwAABw\r\n        AABxAABxAABxAAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2AAB3AAB3\r\n        AAB4////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////5eLj4d/g3NrZ39za4d7d3Nja2tjZ29nZy8nSKCeRAACBAACBAACB\r\n        oZ/B2NXV2dfX09HRzcvLysfHysfH////////////////////////////////////////3dzb3dzb1tTU\r\n        0c/O0c7O0c7O0c7O0M/P0dDP0M7OzszLzcvLzcrLz8zL08/M0c3LvLnEBweBAAB+AAB+GxuHsq++y8fG\r\n        ysbFysbFycXESkmXAAB8AAB7AAB7AAB7AAB6AAB6AAB6AAB6AAB5paO3xsPCyMTEx8XFx8XEyMXExsLD\r\n        ysfHyMbGure1y8jHyMXFtbOy////////////AABzAAB0AABzAABzAABzAAByAAByAAByAABxAABxAABw\r\n        AABwAABwAABvAABvBQVxKSh+cG6ZuLa2uba2uLW1tbOzs7CwtbKytrS0trOztbKysq+vsa6usq6usrCw\r\n        tbKytLGxr6ysrquqsK6tsq6vrKion5ube3h3gHx9////////////////////////////////////////\r\n        ////////////////////////////////////////wL69wL69tbOzrKqqpaOjpqOjpaKjpaOjiomINDMy\r\n        Pz49Ojo6IiIhmpeYPz4+MjEwPz48gn9+oJycn5ycnpubnpqbnZqampeXmpeXmpiXmpiXmZaWm5iYm5mZ\r\n        mpiXmZeXmZiYmpiZmZeXmZeXlpSVlJGSlJGRlZOTlZOTlJOTk5GSlZOTlpSTlJKSkZCPkpCPk5CPkI6O\r\n        joyMj4yMOjo5HBwcKSkoODc2c3JySkhIHh0cNTU0LS0scW9uend4GhkYGxsaHx4dTUxLhoSEICAfHBsa\r\n        MzIyQD8+hIKBhIKChYKChIGBgX5+gX19gH5+f319goCAhIGCgoB/gH5+gX5/gX5+gX9+gH59fnt7fHl6\r\n        fHl5fHl4e3h3fHp6fXt7e3l5fHl6f31+fn19fXt8lZOTr62txsPDy8rJysjIxcLCxcHCysbGy8fHzcnH\r\n        zMjHy8fGy8fHzMnJzsvKz8vLz8vL////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////29rZ\r\n        29rZ3NnZ2tjZ2tfY3dra393c393d4N7e3tzc3drb3NnZ39zd4uDh4eDh39zd39vb4+Df4uDg4t/f4+Dg\r\n        4+Hh5ePj5uPk5OHi5OHh5eLi5ePk5OPj1NPTtrS0////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////AABwAABwAABwAABwAABxAABx\r\n        AAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AABzAAB2AAB3////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////5OLi5OLi4N7d3tvb3Nna3drb3Nra29ra09DWSUidAACBAACBAwOCZGKo2NTV19TUwsHA\r\n        zcvL////////////////////////////////////////////////////3dzb1NHR0c/O0s/P0s/P0c/O\r\n        0M7N0c/O0tDP0M7N0M3M0M3Nz83N0c7N0M3MiIexAAB+AAB+AAB+JyeMycbIzsrIzsnIzcnIzMfHoZ63\r\n        BAR9AAB8AAB7AAB7AAB7AAB7AAB6AAB6AAB6UlGYycTCy8XFx8XFx8XDycTDx8PDxcLDxcLCxcLBy8jH\r\n        yMXFtbOyycXFxsLCsK2s////AAB0AABuAABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABw\r\n        AABvAABvAABuLy+AgICfrKqwtbO0tbKytbKzt7W1trS0tLKytLKys7Cxsq+wsq6vsq+vsK2tsK6ur6ys\r\n        r6uss7CxtbGxsayro56dgHx9gHx9////////////////////////////////////////////////////\r\n        ////////////////////////////wL69wL6+rqysp6SlpqKjpqSlpKKjbm1sHx4dJCMiPTs7VFJRoqGg\r\n        XVtbMzMyUVBQZWNkoJ2dkY+PUVFRbmxrjYuLnpybnZqanpqbnJmanJmZnJqZmpiYmpeXm5iYnJiZmpiY\r\n        mJWVmJWWl5WVlJKSlZKSlJGRlJGRlZKSlpOTlpOTl5aWlZSTk5CQko6Ok5GQk5GRkpCQkY6OKikpGxsa\r\n        HR0cJycmjoyNOjg4Hh0cJyYlQT8/hYKCbGlpGxoZIyMhICAeSklJiYeHGRgYHBsaLCwrOTg3hICAhYKB\r\n        hoODhYKChIGAhIGBhIKCbm5tVVNTeXd3gYB/gH19gX5/gn5/gX5+gH19f3x8fnt7fXp5e3h4e3l4f318\r\n        gX+Afnx9f3x9f35+f35+fnx8fXp6fXt7gX9/lZKTraurw8HAy8fHzMjIy8nIzMjHzcjIzsjJzsnKzcnJ\r\n        zsvKz8vLz8vL0MzM0czN0czN////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////1NLS2tfX29fY2dfX2tjY\r\n        29jZ29na3dvb3tvb3Nra3Nrb3drb3tzc4eDh4ODh393d4Nzc4dzd39zc393e4d/f4t/e4+Dh4uDh4N7e\r\n        4t/f4+Dg5eLi4N3dwsDAwsDA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////AABwAABwAABwAABxAABxAABxAAByAABy\r\n        AAByAABzAABzAABzAAB0AAB0AAB0AAB1AABz////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        5OLi4d/f3dra2tfY3dvb3Nra3Nrb3NvbcXCuAACAAACBAACBMzKVz8zU1dHRsq+vsq+v////////////\r\n        ////////////////////////////////////2tbX2tbX1NHR0s/O0c7O0c7O09DP0tDO0c7O0M3Nz8zM\r\n        0M3N0c7PzszNzcvKzszLZWSkAgKAAAB/AAB+T06bzsvKzcvKzcrKzsrKzcrKxMPGPj2TAAB8AAB8AAB8\r\n        AAB7AAB7AAB7AAB6AAB6CAh9r6u7ysXFycbFx8TDx8TDx8TDxMHAw8C/xMHAxcLCxMLBxMDAycXFxsLC\r\n        sK2sxsLBgn19S0loFBNjAwNtAAByAABzAABzAAByAAByAAByAABxAABxAABwAABwAABwAABvAABvAABv\r\n        FBN1U1KNr6yyube4ubi4ubi4uLa3trW0uLa2uLW2tLCys7CxsrCwsq+usq+vsq6usq6us7CxtbGxubSz\r\n        s62sn5iXioaF////////////////////////////////////////////////////////////////////\r\n        ////////////////wL6+tLKyqKWlpqOkpaOjpaKib21sKCcmKyopIyIhVlRUo6CgQ0FALCwramhoWlhX\r\n        oZ+fXVxbJycmSUhHWlhXZ2VkdHJyj4yMm5iZnpqbnZqanJqZnJqbm5mampeYmZaWmJWVmZaXmpeXmJaW\r\n        lZOTlZKSlpKSl5OTlZGRlJCRlZOTl5aVlJGQkY6OkpCQlJKSlJKSlZKTOzo5JCQjJiUlODc2j42NMjEx\r\n        JCIiHh4dPz09gH1+YF5eJSQjKCcmR0dGVVRShYODGhoZHRwcMC8vTkxMiIaGiIaGhYKChoGChoODiIaG\r\n        h4aGiIWGHBwbOjk3TkxMcG1ugn9/gn1+gn5+gX9+gX5+gXx9gX19gHt8f3x8gH5+gH5+gX5/gn+Agn+A\r\n        gX+AgYCBf319fnx9fHl6eXd3fHl6goCAmJaWsa2tyMXEzMnJzcjIz8vKz8vLz8vJz8vLz8zMz8vL0MzM\r\n        0czN0czN0M3O1NDR1tPU////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////1NLS1NLS1tPT19PU2dbX2tjY19TU19TU29jY3NnZ\r\n        3Nna3tzc39zc3t3d3t3d3tzd3dvb4Nzd3trb39zc4uDi4eDh4Nzc4N3d397e3dvb39zc4d7d5+Li39vb\r\n        wsDA////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AABwAABwAABwAABwAABxAABxAAByAAByAAByAABzAABz\r\n        AABzAAB0AAB0AAB1////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////5eLh5eLh3tzc3Nra\r\n        3dvb3tzc3dzc3dvboJ7BAgKBAACAAACABASDtrTM19TUsq+v////////////////////////////////\r\n        ////////////////////29jY29jY19TU09DP0c7O0s/Q09DQ09DQ0s/Oz8zMzsvL0M3N0M3NzsvLzsrJ\r\n        yMXJQ0KYAQF/AAB/BASAb22nysfJy8nJzcrKzcrKzcvKzcvLhIKvAgJ9AAB8AAB8AAB8AAB7AAB7AAB7\r\n        AAB7AAB6TEuXysfGysfGyMTDyMTEycbFxsTDxcLBxcHBw8DAw8DAxcHBx8TDw8DAwL28xsLBxcDAsa6u\r\n        iIaSUU95GhlsAABzAABzAABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABuIiF7cG+b\r\n        qKaxu7e4uba2ube3uri3uba2trKztbKytbOztLGxtLCwtLCwtbKxs7Cwsq+wtLGxt7KwrKWjioaFioaF\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        vry8vry8sK6up6WmpaOjpqKiaWZmPj07PTs6NDQybmxspKGiW1paLy8uKSgnUU9NoZ+fQUBAIB8gJSQj\r\n        NTQzOjk5KiooS0lIT01NlpKTnpycjIuKlJGRnJmanJmZmpiYmZeXmpeWm5eWmZiXmJWVl5WUmJaVlpOU\r\n        lpOTlZKSlJGQlZKSlJKRkpCQkpCRko+PlJCQlJKSHx8eJycmIB8eNjQzkI6OHh0cLi0sLi0sQUA/kI2O\r\n        WFZXHBsaJCQjPj09ZWRjb21tGxoZHRwbNDMzUlFSjIqKioiHiIWFiIWGiYeHiIaGiIWFh4SEGhoZJSQj\r\n        Ojo5YmBgeXV1Pz09amdmeHZ1gX9+gn5/fHh4f3x8gn9/g4CAgoCAg4GBhIKCgoCBgoCBgoCBgX9+f319\r\n        fHl6fXp6gH5+fnx+fHl6fHp6gX9/mJOUsq+vyMbGy8nJz8vL0MvMz8vMz8vL0c3O087P0M3O0M3O1NDR\r\n        1tPU087P0s7P0MzM////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////1dHR1dHR1NHS1dLT2dbW2dfY09LR1dLS29nZ29na29nZ29na29nZ3NrZ\r\n        3dvb3dra3dra3tvb3dvb4eDf5eTl5eTl4N/e39zc397e3dvb3tva4t7e5N/f1NDQ1NDQ////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////AABwAABwAABwAABwAABxAABwAAByAAByAAByAAByAABzAABzAABzAAB0\r\n        AAB0////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////5eLh4N/f3dra3Nna4N7e393e3drb\r\n        t7TKBgaCAACAAACAAACAc3KvzcvLzcvL////////////////////////////////////////////////\r\n        ////////29jY2NTV1NLR1dPS1NLS09HQ09DQ09DQ0M7O0s/O0c/PzszM0MzM0s3NrarAMzKTAACAAAB/\r\n        DAyDg4GvysfJy8fHzsrJzcvKzcrJz8vLwr7HJCOKAAB9AAB8AAB8AAB8AAB8AAB7AAB7AAB7BgZ8r6y8\r\n        ycbGycXEysbFy8fGycbGycXFycXFx8XExsLDxcHBw8HAxMHAxMHAxMHAwr+/xMDAyMXExMDApaGocnGg\r\n        LCyFAABzAABzAABzAAByAAByAAByAABxAABxAABwAABwAABwAABvAABvAABvAABuNDKCh4Oiu7e3ura3\r\n        ubW2t7S0uLa1t7S0trOztbGxtLGxtbOztrOztrOztLKytbKyubOxsq2rnZqah4SF////////////////\r\n        ////////////////////////////////////////////////////////////////////vry8s7Cxq6mp\r\n        qaenqKanYmBgQD89NjU0SEdGdXNzpaOjpKKipaOjbm1tZ2ZloZ+fQUBAISAfNTQzYV9fZGJiISAfQkA/\r\n        Q0FAoJ2eaWdnRERCZGJidXJyhoSDmpeXi4iIjoyKmpeWmJaVl5OTl5STl5WUmJWVmJWVmJWUlJGQlJGQ\r\n        lJKRlJKSkJCQkZCPk5GQe3p5JiYkKCcmQD89VVNSk5GRNTUzHx8eMTAvPj08kY+QUU9PIiEgHBwbISAf\r\n        Z2VkaGZmJCMjHh4dMTEwU1JRi4eHioeHi4qJjIuKioeHiIWFiYaGiYeGHBsaKCcmMC8vZGJgbmxsLy4t\r\n        QkJAT01MZWNiYF5dPTw7Tk1LVVRSaGdlf31+hIODhIOCgYCAf31+f3x8fnt7fnt7fnt7gH19gH5+fnx9\r\n        fXt7fHt6e3h4fHh5e3h3gH59mJWVtLCxzsrM0M3N0c3O0MvM0c3O0c3Nz8zM0c7P1NHR087P0s7P0MzM\r\n        0c3P1dPU1NHS////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////0c/O1NHR1dPT1tTU1tTU19XW1dPT1dPT2tjZ29na2tfY2dfX2NbW2NbX29jZ3dra3dra3tra\r\n        393d4ODg5OPj5OTk4N/g3drb3dvb3tzc39zc5eHh4d3dwb++wb++////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////AABwAABvAABwAABwAABw////////AAByAAByAAByAABzAABzAABzAABz////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////4+Hh4+Hh39zb3NnZ4d/f4d/g3tvc3tvbKSiQAACAAACA\r\n        AACAIiKLzcvL////////////////////////////////////////////////////////2tjY2tjY1tPU\r\n        19TU1tTT1NLS09HQ1dLS1dLS09DQ09DQ0tDQ0c/O0s/P1NDRqqbAFhaIAACAAACAAgKAiYeyzszMzcvK\r\n        zsvLzszLzcrJzsrKz8zLcG6nAQF9AAB9AAB8AAB8AAB8AAB8AAB7AAB7AAB7RkWWz8vMzcrJy8jIysXF\r\n        y8bGysbGysfGy8jIyMbGxMHBxcLBx8TEycbFxcLCw8HAxMHAxMHBxMDAxMC/wr++ure6bmydLy6FCgp3\r\n        AABzAAByAAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABuFxd3V1aRpaKuuLS0uLa2ubi4u7i3\r\n        t7OztbKytrS0t7S0trKzt7S0t7S0trKytrKytrSzrKuqh4SFh4SF////////////////////////////\r\n        ////////////////////////////////////////////////////ure3ure3srCwq6mpqaenTk5MLS0r\r\n        YmFgOjk4f318o6GhpaKip6WkqKalpaOjo6GhHh4dIiIgQ0JBb25sZWNjIyIhNzc1RkVEoZ+eQT8+ISAf\r\n        NzY1PTw7VlVTg4CBNzY0Xlxbbm1se3l5l5STmZWUmZeWmJaWl5OTlpKSl5WUmJWVl5STlJKRlJKSk5GS\r\n        k5KScnJxTUxMIB8eMC8ua2pqfXt7JSUjHR0bHx8eS0pJk5GSXFpZMzMyJSUkKikodnN0W1lZHBwbHx4d\r\n        MzIxZWNijImJi4iIi4qKioiHioaFioaGioiIi4mJHR0bMTAwODc2QD49MjExKikoLSwrMjEwdnRzKSgn\r\n        IB8eJiUkHBsaJCQjT05Nd3V1fnt7fnx8fXt7fHp5fXp6fXt7f319f3x8fHp6fXp6f3x7fHp4enZ3fHl5\r\n        fHt7enl4eHV1d3R0gX5+nJmauLW20M3M0c7O0s7O0MzMz8zMz83N0MvM0MzM0MzM0c3P1dPU1NHS087Q\r\n        0c7Oz8zL////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////0c/O0c/O09HR\r\n        1dLT1tPU1NLS19XV19XU1dLS19TU2dfX2tfX29jY2dbW19bW2tjY3Nra3dva39zb4N3e4d/g4uDh4N7g\r\n        3drc3Nna3Nra3dvc4d7f5uPj3drawb++////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AABvAABvAABwAABwAABwAABwAABxAABxAAByAAByAAByAABzAABz////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////4+Hh4uHh3t3d39zd4d7f393d29nbWVikAAB/AAB/AACAIiKL////////\r\n        ////////////////////////////////////////////////////2tjX2tjX1tTU19PT1dHS1dLS1dLS\r\n        1dPT1dLS09DP0tDP09HR0tHQ0tDP0c7Pk5G5BgaCAACAAACAAgKBqKa90M7Mz83Mz83NzszLzszLzsrK\r\n        z8zMvLnDFBSEAAB9AAB9AAB9AAB8AAB8AAB8AAB8AAB7AwN8np2+19XV1NHQzsvLz8zLzMnIy8jHzcrK\r\n        y8rJyMfGysbHzMnJysjIx8bFxcPDxMDAwb6+w8HAw8DAw7+/xMDBvbq9o5+waGaaGhl9AABzAABzAABy\r\n        AAByAAByAABxAABxAABwAABwAABwAABvAABvAABvAABuDg1zVlWPm5eqt7S3vbm4vbi2ure2ube3t7S0\r\n        tbOztrOztbKytbKytrO0t7W1tLGwoZ2doZ2d////////////////////////////////////////////\r\n        ////////////////////////////////////////ure3vLm6rqurqaalYWBeVVRUXFtaUFBOjYyLjYqL\r\n        ioeInpubo6CgpKKipKKiHR0cIiIhPj08bmxsZmVkIiEgNDMyYmFgoZ6eSEZGHh0cHx8fQ0JBhIGBYV9f\r\n        ICAfMTAvOTk4Pj49mpiYn5qZnZiYmpeXmJaUl5WUnJmaoJ6em5mYl5WUmJWVlpSUkI+RcHBxOTk4Ozo5\r\n        Hx4dY2Jid3R1Hh0cR0ZFISAfUlFQlJKRXVxaKCYmLy8tLCsqdXR1WllZHBwbIyMiNjU0bGlpjIqKioiI\r\n        jImIjIiHi4iIjImKi4mKi4mKHRwbJiUkHRwcHRwcGhkYHBsaJyYlNzY1d3R0FxYVFxcXGRkYd3V0GBgY\r\n        MTAuVlRTfHh5fHl6dXJyend3f318f359fnx8fXt6e3l4fXp5fHp5e3h4e3h4fHp5fXt7fXt7enh5eHV1\r\n        d3N0eHR0eXd3hoODnpububa2z8zM0MzM0c7O0dDP0c/O087P1dHS1tLU1NDR087Q0c7Oz8zLz8zM08/R\r\n        1dLT////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////09HR09HR09HR1dTU1tTU1NHR1NPS\r\n        1dPS1NLS1tPU2NbV2NbW2NXV19XV1tTU19XW2dfX29nZ3tzc3tzd4N3e393e3Nna29jZ393c393d3tvc\r\n        39zc3tvay8jIpKGi////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AABvAABvAABv\r\n        AABwAABwAABwAABxAABxAAByAAByAAByAABy////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////5eLj5eLj4d/f3tzc39zd3drb3tzcd3eyAAB/AAB/AAB/AAB/////////////////////////\r\n        ////////////////////////////////////2tfY2tfY19XV1tPT1dPT1dTU1dPT1NHS1NLR09HQ09DQ\r\n        09HR0tDQ0s/P0c/PXFujAACBAACBAACAIyKNzMjL0M3M0MzM0c7N0M3Nz8zMzszMzsvLzsvKZmSkAAB9\r\n        AAB9AAB9AAB9AAB8AAB8AAB8AAB8AAB7GRlz19XV1NHQ2tnX1tTT0s/O0c3MzszLysjIysjIy8jIzcrK\r\n        zMrLysfIycbGxsTEw8HBwsDAxMHBxMHAxsPDxMHBv7u7v7u6pqOzaWebHx9/AABzAAByAAByAAByAABx\r\n        AABxAABxAABwAABwAABwAABvAABvAABuAABuJyZ9eXacubS2v7m4vri4uba2trS0trS0uLW1tbKytbOz\r\n        t7S0ubW1t7OznpmZhYKB////////////////////////////////////////////////////////////\r\n        ////////////////////////wsC/wsC/s6+vq6ioYV9fMTAvQ0JBYWBfjYuLa2lpQ0JBcnFvjIqJmpeX\r\n        pKKiHx8dJCQiQD8+hoKDQ0NBIiIgPDw6ZGJhop+fMDAvOzo5Ly4tbm1rn5ydYWBfHR0cHx8eJycleXh4\r\n        ZWNjYl9dioaEkY+Om5mYmpiXn52doqCgnZqZl5STmJaVmZiWlpWVlZOTl5STbGppS0pJZ2RleXd3JiYl\r\n        HBwbHx4dXFtalZSUWllZHh0cLCsrPz49kY6PPDs7HR0cKSgnODc1d3V1jIqLi4mIjYmIjouLjIuLjYuL\r\n        jYuLiYeHHBsaIyMhHBwbZGNiJiYlGhoYKSgnTkxMhYOCb2xsSklIREJBfHp5GhkYLi0rVFNRgH18W1lY\r\n        Ozo5TExKVFJSZ2Rke3h3f3x8fnt7fXt6fnt7fXt7fXt7e3h4fHh4fnp7fXt7fHp6fHt6fHl5end4enh3\r\n        d3V1eHV1hoODop+fvru70c/Q1NHS09DR1dHS09DR0M3O0s7O0c7OzszKz8zM08/R1dLT1dHQ1dXT09HT\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////0M3O0s/Q0tDR09HS1NPT09HR09HQ09HQ09HQ1tPT2NXV\r\n        1tTU1NLS1tPT1tXV19XV2NTV2dfX2tnZ29jZ3dra3dzb2dfX29nY4t/g4d/g3drb3NnZ2tjYzMrKpKGi\r\n        pKGi////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////AABvAABvAABvAABwAABwAABw\r\n        AABxAABxAABxAAByAABy////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////5eLj\r\n        4+Hh393c3tzc3Nna3dvboZ/DBweCAAB/AAB/AAB/AAB/////////////////////////////////////\r\n        ////////////////////3dva3dva2dfW19TU1tPT1dLS1dLS1dPT1dLS09HQ1NHR1NHR1NDQ1tHQ1NHQ\r\n        NjaVAACBAACBAACBRkWa0s7P0c7O0M3O0c7Oz8zMz83Mz8zLzcnJzcnJu7nEFxeHAAB+AAB9AAB9AAB9\r\n        AAB9AAB8AAB8AAB8GRlz////////2tnX1tTT0s/O2dbV1dHQz8rJz8zLzsvLycbFyMTFycbHy8nJy8nJ\r\n        yMXFw8HAwr+/w8C/w7+/w8DAwr++wr++w7+/wr6+t7W6bWueLi6FCwt3AAByAAByAABxAABxAABxAABw\r\n        AABwAABwAABvAABvAABvAABuCAhxNTSDg4Ghu7a3vbe3ura1uLW0t7OztbKztbKzt7S0ura2uLS0pqKi\r\n        hYKBioeH////////////////////////////////////////////////////////////////////////\r\n        ////////////wsC/sa6vrKqqhoSEc3JxIyIhPDs6kY+OVlVUNDQzTUxLU1JRiYeGg4GBHx8fJiUkRENC\r\n        hYODQ0FBIiEgOTg3a2lno6CgISAgKyopRkVEe3l5np2cUVBOISEfRkVET01MnpybSUdHJyYlRENDbGpo\r\n        hoWCi4iHn52dn52cmpeXl5SUlpSUmZeXmZeVl5STlZKRlpOTmJaWnJubi4qKXV1cfn19TkxLcG5tmJaX\r\n        j46PKyopHh4dPT08XVtbNzY1Hx4dKCcmMTAugoGAj42NjYuLjIqKjImKjIqKjIqKj4yMjYuLHBwaMzIx\r\n        JiUkiISEGRkYHRwbLy0samdnhYKBf3x7ZmRkXVpaRUNCJSQjMzIxQD49gX5+KCYmIB8eJiUkHBsaJCQj\r\n        Tk1MeXV2gX5+gH19gn5/hICBgX9/gH5/gHx9gHx9fXl6enl4fXt6fnx7fHl4e3l5fHl5end3eXd3dnRz\r\n        dnR0iIeGpqSkwLy90czO0MzN0MzM0M3N09DQ1NDQ1dPR0c/R0MvM1dHQ1dXT09HT0c7P0s7O1NLS////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////0M3O0M3O0s/Q1NHR09HR09HR1NHR1NHS0s/Q0c/P09DQ1NDQ08/Q1dHS1tTU19XW\r\n        2NXW2NbW2NbW2NbW2tfX2dfX2dfW29nZ3tzc393e3dvc29nZ2tjX4N3d2NbXpKGi////////////////\r\n        ////////////////////////////////////////////////////////x8TEwr6+x8bF0c/Quri4////\r\n        ////////////////////////////////////////////AABvAABvAABvAABvAABwAABwAABwAABxAABx\r\n        AABx////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////5OHi5OHi39vc3tvc39zc\r\n        3tzcx8bSHR2LAAB+AAB/AAB/AAB/////////////////////////////////////////////////////\r\n        ////39zc39zc29jY2dfX2NXW2NXV2dbW2NbW19TU1NHR1dLS1dHR1NDP1dHQwb7KBgaEAACBAACBAgKC\r\n        WViiysjM0c7O0M3Nz8zMz8zM0M3Nz8zMzsrJzsvKz8zMZGOjAAB+AAB+AAB9AAB9AAB9AAB9AAB8AAB8\r\n        AAB8AAB8////////////////2dbV1dHQz8rJ2NXV1NLSzcrKyMXFyMTEy8fHy8jIyMXFx8TDxcLCxcHB\r\n        xMHBw8DAxMHAxcHBxcLCw8DAw7++wLu8p6OyaWicHBt+AAByAAByAAByAABxAABxAABxAABwAABwAABw\r\n        AABvAABvAABuAABuAABuSUeKiIOhsKuwt7W0uLa1uba2uLa2uLW2ure3uLW2tbKzrqysioeHioeH////\r\n        ////////////////////////////////////////////////////////////////////////uLa2uLa2\r\n        r66urauqraqqX11cTEtKLS0sMzIxKyopJCQiJiUkNTQzp6Wle3h4IB8eJCMiQkFAoJ2dMjEwJCMiQUE/\r\n        d3V1k4+PHx4dJCMiRENCioeGnZuaQD89JiUkQ0JBa2looZ+fQUA/KSknOTg3Xl1cb2xrREJBYV9ehoOC\r\n        mpmYmpiXmpeXmZaWmZWVmJSUl5SUmpeXm5mYm5iXnJmZnZubnJqakI+OiYiHmZaWl5aWfHt7ISAfHR0c\r\n        KSkoHh4dHh0cHx4dLy4tkI2NkI2MkI2NjoyMj4yMj4yNiomJjIqJkI2MHR0bNTQzMjEwd3RzGhoZHh0c\r\n        LCsqgX18d3V0Ly4uNzY1PTw7JyYlGxsZHBwaKyopcm9vFhYVFxcXGhkYeXV1GBgYMTAvXlxbgX9+gH5/\r\n        g4GBhoSDhoSEhIGCgX9/gH58fnx7fXp6fnx7e3p5enh3fHp6fnx8fXp6enh3d3R0dXNzeXZ2eHZ0d3V0\r\n        ioeGpKGhwb2909DQ1dHS2dXW29jY1tPU0c7P0c7O1dLR1NHS0c7P0s7O1NLS1NHR1dLT2NLU////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        0c/Q0c/Q0c/P0c7P0dDQ0M7O09HQ0tDQz8zN0c3O0s/P0c/O09DQ1dLT1dLT1tTV19XW1tTU1tPT19TU\r\n        2dbW1tTU1dLT2tfY3Nra2tjY2tfY29na2tjZ2tbXz83Nz83N////////////////////////////////\r\n        ////////////////////////////////4+Hh1tTTx8TEwr6+x8bF0c/Quri429naysjImpeW////////\r\n        ////////////////////////////////AABvAABvAABvAABvAABwAABwAABwAABxAABw////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////5OHi4t/g4d7f4d3e4N3d3NvcLy+SAAB+\r\n        AAB+AAB/AAB+////////////////////////////////////////////////////////39zd29nZ2tfX\r\n        2djX2tjY29fX2dbX2NXV1dPS1tLS1dLR1dPR1tLS1NDRkpC5AACCAACCAACBBwaDbWupzsvN0c/O0s/O\r\n        0c7O0s7O0s/P0c7O0MzM0MzLz8vLu7jDGBiHAAB+AAB+AAB+AAB9AAB9AAB9AAB9AAB8AAB8////////\r\n        ////////////////////2NXV1NLSzcrK1tTTzMnIyMTEyMTFycbGysjIycbGxcLCxsPCxcLBx8PDycfH\r\n        x8TExcHBw8C/w7+/wL29wb6+oJ6zbGmeFxZ8AAByAAByAABxAABxAABxAABwAABwAABwAABvAABvAABv\r\n        AABuBARwFRR2UE6NoqGuu7i4u7e3uri4u7m5urm5ure3u7i4trS0op+gop+g////////////////////\r\n        ////////////////////////////////////////////////////////wb6+wb6+t7S0srCwr6ysraur\r\n        c3JyTk1OHh0cHx8eHh4cICAeY2JhqqeoaWdnJyclIiIhNTQzqqenIB8eIyIhQD49cm9xgX+AKCcmJSQj\r\n        Q0JAiIWFn5ybLy8tISEgKikodHNyop+fMjEwIiEgPz48VVNScG1tQkFBMTAvZGFigYB+TEpKf317kY2N\r\n        mZaVmpiXc3JxcnBwgH58jouLmpaXnZmanJqanJuanZubmZaWmJWVmpeXk4+PS0lJISAfGRgXGRkYIyMi\r\n        e3h4kY2OkI2NkY6NkY6Oko6Nko+PjoyMj42MkpCPHRwbOTg3MC8uZWRjGxsaISAfRkRDiYWETUtKIiIg\r\n        GhoZGxoZGRgXFxcWJyUkZ2VkgX9/bGtqSklIRkRDg4CAGxoZMC8uWFZVb21sRUNCbmtqenh4goCAgH19\r\n        e3h3d3Z0fXt6fnt7fXp6e3p5e3h4e3l5fXt7fXt6fHl5enh3eXd3enZ2end1eXZ1enh4dnV1dXNzjIqK\r\n        qaamxMLC1dHS1dPT1NPT0M3P0czO1tLS09DP0c7O1NDR1NHR1dLT2NLU2NXV19fX1dLR////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////zMrL1NLSz83OycfI\r\n        zszM0M7O0c7Oz8zM0tDO19TS1NDQ0M/P09LR09LR09DR1NLS1NLS0s/Q09DR1dPS1tPT1dPT1dLT19PU\r\n        19TU2dfX3Nra3NnZ2tfZ1dPUuLa2uLa2////////////////////////////////////////////////\r\n        ////////////////4+Hh1tTT2tjY4N3d4+Hj5eTl4uHh29naysjImpeWmpeW////////////////////\r\n        ////////////////////AABvAABuAABvAABvAABvAABwAABwAABwAABw////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////5OHi4t/g5uPj5eDg4t7f4uDhZGOqAAB+AAB+AAB+AAB+AAB5\r\n        ////////////////////////////////////////////////39zd39zd29jZ2tjY2tnZ29nZ2dXV19PT\r\n        19TU19TU1tTT1dPS19XU2NTU1dLSZ2aoAwKDAACCAACCAgKDiIa01NDQ0s/O09DQ1NLR1dLS1tPT09DQ\r\n        0M3M0c3N0s7P0c7OZGOlAAB+AAB+AAB+AAB+AAB9AAB9AAB9AAB9AAB8AAB8////////////////////\r\n        ////////////////1tTTzMnIyMTEzcvLzMrJy8rJysfGx8LCyMTFycfHysjIy8jJyMXFxcLBxsPDx8TE\r\n        xsPCxsLBxMDBw8HCw76/d3KhNTOHCAh1AAByAABxAABxAABxAABwAABwAABwAABvAABvAABuAABuAABu\r\n        GBh3VFKPoJ2tu7i4u7m5u7m4vbm4v7q5uLa1op+g////////////////////////////////////////\r\n        ////////////////////////////////////////////wb6+w7+/ure4sa+vr62tr6ytrqurcm9vaWhm\r\n        aWhmdHJyraqqrKmpfHp5Ly8tJycmNDQym5qaHx8dIyIhPDs6ioiJf35/IiIgLCsqPDs6nJmZop+fHh4e\r\n        KyopOTg3dHJxop6fHRwcISAfOjk4cG9tWVdXMzIxODc2aWdmfXp6IiIhTUtKYF5clJKSg4GBISAfIiIh\r\n        LSwrRENBXFtaiIaFnJqan52dnpybnZubnpycnpybm5iXlZOSk5CQdHJxdXNylJOSlJKSlJGRk5GRk5CQ\r\n        kY6OkI6Oj42Mj42Njo2Njo2NKiopJSQjMTAvXFpaHh4cMDAuYV9diISDODc2LCsqIyMiNzc2a2hoeHR0\r\n        hIB/g4GAhIKCfnt7Z2ZlYF9fR0ZFJiUkMC8tNTQzUlBQHRwbOjk4UlBPfHp6bWtrOTg3SkdHVFJSZWJh\r\n        dXJzfXt7f3t7fnt7fn18fXt6fHl5fXp6fHp5fXp6fXp6end3eHV1end3fHp6e3l5dnNzdXJyjIqKqaem\r\n        xcLC08/P1NHS1tLU1dLS1M/Q1tLS19TU1tTU19LT2NXV19fX1dLR0c3M19TS2NbV////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////zMrLzMrL0tDQzczLyMbGy8jJ0M3Oz83N0M3M\r\n        2NbT2djU0s7O0M7P0tDR0s/Q0s/Q09HS0s/P0c7O09HR1NLT1dLT1tPT1NLS1NLR19XV29nZ3Nvb2tfY\r\n        29jZ0M/PuLa2////////////////////////////////////////////////////////////////4+Hh\r\n        4+Hh393c3Nva4N/f4+Dh4+Dh4+Hg5OHh19TUuLa1mZeX////////////////////////////////////\r\n        ////////AABuAABuAABvAABvAABvAABwAABwAABw////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////5uPj5eDg5ePj5OHiZGOqAwN7AAB+AAB+AAB+AAB5AAB+////////////\r\n        ////////////////////////////////397e397e3dra3Nrb3Nra29nY2NXV2NXV2tbW2dXV1tPT1tPT\r\n        2NXU2NXUzcrPSEieAgKDAACCAACCAwKDrqzD1NLR09DP1NHQ1NHQ1dLS19TU1dLS0c7N0tDP1NLS1dPS\r\n        s7HCDAuCAAB/AAB+AAB+AAB+AAB+AAB9AAB9AAB9AAB9////////////////////////////////////\r\n        ////////////zcvLzMrJ0c/PzsvJy8bEzMnJzs3Ny8nJx8PEx8LDx8TEx8TEycbGy8fGzMfGyMHBxcDA\r\n        xcLCxMLCvLm+c3GgNTSHCQl2AgFyAABxAABxAABwAABwAABwAABvAABvAABvAABuAABuAABuGhp3WFeR\r\n        m5mrtrO2vbm5wLy8trSzkpCPkpCP////////////////////////////////////////////////////\r\n        ////////////////////////////////w7+/v7y9sq+vsK2tsK2ur62trqysrKqqrKmprKmprqurrquq\r\n        raqqrKmpmZeXeHZ3f35+GxsZHh4cJCQibWxrICAfIB8fJiUkYF5dqqinpaKiJCMiLy4tQ0JBf3x8o6Cg\r\n        Hh0dIiIgNTUzZ2VkMzIxKSknPz48bWtqbWtqHx8dLi0sQkA/npublpSUc3FxUU9OJycmSklJICAgVVRT\r\n        j42LoqCgoJ6eoZ6eop+gnpycmJWVl5SUmZaVmJeWmJaVlJKSlJKSlpSTlpWUk5GRkY6PkpGRkZGQjYuL\r\n        jYuMjoyNPDs6Ly4tLy4uPz49Ly4tNjU0aWdnhoSETk1MHh4cPTw7c3FwSkdHVFFQbGhogX9+enh4MC8v\r\n        NzY1PTw7JyYlGxoZGhoZKSgmUlBPISEgKikoQ0E/gH19Q0FAHBwbJiUkHh0cIiEgSEdGcnBvgX99gX59\r\n        f319f3x8f3x8fnx8fHp5fHl5e3l6eHV2eXZ2f3x6f3x7e3h4d3R0dXJzeHZ2e3h4enh3kY6Oraqry8bI\r\n        19LU2NTV29bY2tjZ19XW1tLT1dHS0s7Q0MzM0c3M19TS2NbV0MzMzcjK////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////zcvLzcvLzszMzMrKzMrKzMjJzsrLz83N0c7N1NHP1M/Pz8zN0c/Q\r\n        0tDR0c/P0c/P0tDR0dDQ0dDP09LS1dPU2NXW19XV09DR0s/P2NfX29ra2tfY2dbX1tPUxMHAxMHA////\r\n        ////////////////////////////////////////////////////////////29nY4N3d3tvc3trb3NrZ\r\n        3dvb4N3e4N7e4d/e39zczcrLmZeXmZeX////////////////////////////////////////AABuAABu\r\n        AABuAABuAABvAABvAABvAABv////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////5ePj5OHi////AwN7AAB9AAB9AAB+AAB+AAB+AAB+////////////////////////\r\n        ////////////////4N7d3t3d3dvb29nZ29nZ29nY29jY29nZ2tbV19PS1tLS2NTU2NXU2NXUsq/GMzKW\r\n        AACDAACDAACCHR2NyMbO1NPS0tDP1NHP1NHQ1dHR1NHR09HR1NHR1NHR0tDP1dPS0M7NSkiQAAB/AAB/\r\n        AAB+AAB+AAB+AAB+AAB9AAB9AAB9AAB9////////////////////////////////////////////////\r\n        ////0c/P0M3OzcvLzszL0MzMy8jJxcLCx8PDyMbGx8TEyMTEycbGzMfGzMXDx8LBxMLCxcLBysXDxL/A\r\n        qaW0bm2dMC+FAAByAABxAABxAABxAABwAABwAABwAABvAABvAABuAABuAABuBgZvKip+bWyZrqy0vLq6\r\n        tbOynpubnpub////////////////////////////////////////////////////////////////////\r\n        ////////////////vry7vry7tLGxsa+vsa+vsq+vsa6vrqysrqurr6ysr62sr62traqqqaioqaanp6Sk\r\n        p6SkjIqJXVtbTkxMjIuLOTg3KCgnJiUkSUhHfHt7Ly8tICAeJCQiSUhInpqagoCAKikoJiYkU1FRd3V0\r\n        Hh4dIiIgOTg3Z2VlZGJiHx8eKyopUlFQoqChnJqaWVhWXVxbeHd2n5ydLi0tIiEgQkFAmJeXoqCgoJ2d\r\n        o6Cfn52cmJeWm5iYnpybm5iYl5SUlZKTlZOUlpWVlZKSko+Pko+PmJaWmJeWlJGRk5CQlpOTPz08Ly4t\r\n        KCgnKSkoLy4tLi0sj4yNjIqLa2ppGRgXJCMiVFJRRURCPDo4QD8+cnBvUE9OIyMhGxoZGxoZGRgXGBcW\r\n        KCcmamhnRENCGxoZKikoNTQygHx8JSUkFxcWGhkYZ2ZlLiwsIiEgTEtKfXx7f3x8cW5ueXh3goB/fnt8\r\n        fHl5fXt6fXt6e3l5fnx7gH59fXp5fHl5fXt7e3l5e3d4fHl5fHl5end3c3Bxb21ujYqKrqyszMnK19PU\r\n        19TV1dPS1NDR0s7P0c7N1NLR2NXV1NPT0MzMzcjK19TU19TU1dLT////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////zMrKzcvLzMnJzcrLz83Nz8zNzsvLzszMzszMzMnJzMnKz83O0c/Q0tDQ0c/P0c7P0M7O\r\n        0M7O0M/P1NLS1tTU1dTU1tPU1NHR0s/Q1tTU2NfX19TV2NTV1NDRsq6vsq6v////////////////////\r\n        ////////////////////////////////////3dvb3dvb29nY393d39zd4Nzd39zc3tzc393c4d7f4uDg\r\n        4uDh2NXWu7m5nZua////////////////////////////////////////////AABuAABtAABuAABuAABv\r\n        AABvAABvAABv////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB+AAB+////////////////////////4N7d\r\n        4N7d3dva29jY29nY3Nva3dvb3drb29jZ2NXV2NTU2dbV2dfV19XU19TUtLHHFRWLAACDAACDAACDPj6a\r\n        zcvR1NLS0s7O1NHQ1tPS1dPT1NLS09HQ1dPR1NHQ0c3N09DPzcvLoqCtDAx/AAB/AAB/AAB/AAB+AAB+\r\n        AAB+AAB+AAB9AAB9////////////////////////////////////////////////1NHS1NHS0M3OzMvL\r\n        zsvLzsvLzcrKysfHycfHy8jIysfGx8TFyMbFzcjGzcjGx8TExMLCyMTDzsnGzcfEyMLBxcLBtLK7hYKn\r\n        NzaIAABxAABxAABxAABwAABwAABwAABvAABvAABvAABuAABuAABuAABtJSR8a2qYp6WwmZeXmZeX////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        vbq6vbq6uLS1tbKytbGwtbGwsq+vsK6usq+usrCwr66urq2traurqaenpaOkpqOkqqenrKipqqioqKWm\r\n        qqWmV1VUISEfLSwsMjEwSEdHR0VFMjEwJCQjSUhIY2JghYKCISEfNzY1S0lIgX9+OTg3IyIhVlVUi4mJ\r\n        XVtbISEgNzY1YWBepqSlaWhnKCcmTExKXl1bZWJjOzk5TExKY2JhkY+OoJ2dn5ycoZ6enZybmZiYmpeX\r\n        mZaVl5SUl5OUl5aVmJaWl5OUlJCQk5CQlpSTmZaWmpiYnJqZmpiXlJKROzk4GxoZGxsaHBwbIB8eUlFQ\r\n        mpaWlZOSioiIWFdXICAfHR0bJCQjHBwaHx4djYqKOTk4LCsqJCMiOTk4bmxrfHt6i4iIioeHNjY1GhoZ\r\n        KSgnSkhHh4SEeHZ1UlBQMTEwhoODODY2KikoU1JRbWxrVlVUODc1VFNTYV9fbGlofnt7gX9+goB/goB/\r\n        gH1+gH19fnx8fXt6fnx8gH5+f319fXt6fXt7fHl5dHJxcW9vdnRzeXd3eHZ2kpCQsbCvzsvM1dDR1NDP\r\n        1dPS2NTV19XU1NHS09DQ1tLS19TU19TU1dLT////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////zMrKzMrK\r\n        y8nIysjIzszN0NDQ0M/OzsvLzcrKzsvLzsvLzcvLz83N0M3Oz83N0M7O0c/Q0M3N0M3N0M7P0s/Q1NLS\r\n        09HS1NHR09DQ09HR1dLT1dLS1NHR1dPT1NHRwr/Awr/A////////////////////////////////////\r\n        ////////////////////3dvb3dvb2NXV29jZ3tvc4N3e393d397d393d4d7f4+Dg4uDg393d0M3NnZua\r\n        nZua////////////////////////////////////////AABtAABtAABtAABuAABuAABuAABvAABvAABv\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////AAB8\r\n        AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB+AAB/AAB/////////////g4Gv4t/f39zc3dnZ3drZ\r\n        3dra3Nra3tzc3dvb3NnZ29nZ3dza2tnZ19PT09DRlJK7BweGAACDAACDAgKETk2gysjP1dHQ1tHR19PT\r\n        1NHR1NHR1NHR1NHQ1dLR1NHR08/P1NHR0M3Nure2Li2CAAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+AAB9\r\n        AAB9////////////////////////////////////////////1dHR1dHRz8zMzcrKzszMzszMzcvKzMnK\r\n        ysjJy8jIzMnJycfHycfGy8fGysfGyMfHyMXFycTEzsjFzcbDyMTDxcLCxMHCw8DAxMLClZKuTEuQHh59\r\n        AABxAABxAABwAABwAABwAABvAABvAABuAABuAABuAABtAABtHh55X16MX16M////////////////////\r\n        ////////////////////////////////////////////////////////////////wb+/wb+/uLW2tbGx\r\n        trKwt7KwtLCwsq+ws7GxsbCwrqysrampr6yssa6urqysrKmqq6iorqmqrKmpqqamrKalaWdlJyYlICAg\r\n        SEdGpaSkdHJzIB8eIiEgNjU0KikoaGZmISAfKikoSEhGjIqIOjk4MzIwYV9flpSUQ0JCIiIgODc2ZGNh\r\n        op+fZWNjICAeJiUkMTEvMjIwISEgOTg4UU9Pi4qJoZ+fop+foJ2dmJaXlJSUmJeWm5mYmpiYmpiYmpiX\r\n        mJaWl5STlpKSlZSTmJaVnJqanZmZnZmZmJaWlJKSg4CBXFpZMTAvGBcWHRwbYF5el5SUmZeWlJGSjImK\r\n        hIKCV1ZVPTw8Pz08b21tjImJTk1MHh0cPTw7dnN0TExMV1dWbm5thIKCODc2HBsaLCwrTEtKjIqJiYeG\r\n        bWtrZmRjUE5OKikoODY1PDs6amhoNjU0HBwbLy8uMjEwSEZGgoB/hIKBhIGAg39/gn5/f3x9gHx9fnt7\r\n        fnt7gH59fnt7end3enh3fnt7end2d3R0eXZ2e3l5d3R0cnBwcW9vd3R0kY+PrqyrzsrL1M/Q1NHS1dDR\r\n        19LT2NbU1tTU1dPT1dLT1dLT////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////wL6/ycfHyMbGyMbGysjIy8rK\r\n        zcrKzsnIzMjHy8nJzszNzszMzMvLzszLzszMz83N0c/Q0M7Oz8zMz8zMzszM0M3N0c/P09HR09HQ09HR\r\n        1tLU19TV1tXV19bW19XWyMbGyMbG////////////////////////////////////////////////////\r\n        ////4N3e3dvb3NnZ29jZ2tfX2tjY3Nra3drb3dvb39zd4N3e4d7f4+Dh2NbWs7CwlpOU////////////\r\n        ////////////////////////////AABsAABsAABtAABtAABtAABuAABuAABvAABvAABvAABv////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////AAB8AAB8AAB8AAB9\r\n        AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/g4Gv2NXd4Nzd3tvb3tva3Nna3Nna3tzb3Nra\r\n        29jZ29nZ3Nra2dbW19TU19PUZGOpAACDAACDAACDAwOEYV+n0c/R1dHQ2dbV29jY1dLS1NDQ1NDP1NHR\r\n        1tXV19XU1tPT19XV09HQtrW0YmCEAACAAACAAAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+////////////\r\n        ////////////////////////////////2NXU2NXU1dHQ0M3NzcvLzcvK0M3Nz83Ny8nJysfHy8jJycbH\r\n        ycbGysfHysjIysnIycfHyMTFy8XEysXEx8TEx8TEx8TEx8XEx8LCx8LCwL3An52xUVCQJyeACAh0AABw\r\n        AABwAABwAABvAABvAABvAABuAABuAABuAABtCQlxAABt////////////////////////////////////\r\n        ////////////////////////////////////////////////u7m5u7m5trS0tbKytLGxtK+wtbCws7Gy\r\n        sLCxrq6vrqysrqursa2stLCvtLGwsa6ur6urr6uqr6uqrqior6mpramprKenfHp6ioiHsK+ufXx8Li0s\r\n        Hh4cISAfnZubZ2VkHx8dJCQiQUA+iISFICAgODc2V1ZVpaOjQ0NCJCQiQD49d3V0oJubSUhHIB8eLy4s\r\n        YWBebWxsJycmISAfIiEglpSUoJ6eop+foZ2dmpeXkpGTY2NkbWxrh4WEnJmZnJmYmZeXmZaVlpOSlJGR\r\n        mJaWnZuam5eXl5KSlpKSlZKSlpOTlZKSlJCRg4B/XVxaiYeHmZeXmpiYm5iYkY+Oi4mJjoyMkI2Nj42L\r\n        j4yMjouLbGpqGRkYJCMiUk9PRURDPT07QUA/cm9uISAfHBwbNDIybGlpiIWFOzk5Ojk4QUA/KiopGxsa\r\n        GxsbHRwbdXNzPTs6GRkYGhoaNzY1b2xsd3V1U1JRZGFhdnRzgn9/gX5+gX1+gH19f3x8gH19fnt7eHV1\r\n        eHV1fHl5fXt7e3h4eHV1d3R0d3R0dHJyc3FydXN0dHN0cG5vd3V1lZKSsa6uzsnK1NDQ09DQ09DQ1dDQ\r\n        0s7OzsrK////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////wL6/wL6/x8bFxsTDxsPDyMPEyMTFysfHzMjIysfHyMbG\r\n        y8nJzcrKy8nJzcvLzsvM0M3O0M7NzcvLzcnKzszMzs3NzszL0M3N0dDP0c/O0c/P1NLT1dLT1NHS1tTU\r\n        1dPUure3ure3////////////////////////////////////////////////////4N3e4N3e29fZ2tjZ\r\n        3Nra2dbW2tfW3NrZ29jZ3Nra393d39zd4N3e4eDg3dzcycbIlpOUlpOU////////////////////////\r\n        ////////////AABsAABsAABsAABsAABtAABtAABuAABuAABuAABvAABvAABv////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////AAB8AAB8AAB8AAB8AAB9AAB2AAB+AAB9\r\n        AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/Dg6GUE+ioJ7D2dba3tvb3dzb3tzc3dra2dfX2dfX2tfW19TT\r\n        2NXV2tjYNjWXAACDAACDAACDAACDgH6029jX2NXU2dbV2tbX19TU1tTT1tLS1tPS19XV19TU1tLS2NXV\r\n        2NXVzsvLt7a2Hh6CAACAAACAAAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+////////////////////////\r\n        ////////////////3Nna3Nna1dPS1NDQ0MvLzcnJ0M3Nz83NycfIycfIzMrKysjIysfHysjIy8jIzMjI\r\n        y8fHycbFysbFzMjGy8bFx8PEx8XEyMXFx8TEx8PDyMTEw7+/srC3nJquYWCXHh59BQVzAABwAABwAABw\r\n        AABvAABvAABuAABuAABuAABtAABtAABtAABt////////////////////////////////////////////\r\n        ////////////////////////////////wb6+tLKxsrGwtbOztLGxtLGysq+ws7CwsK6vrq2tr62ssa6u\r\n        sq+vsq+vs66usK2sr62tsa+us6+usaurr6urrqurq6inrampr6ysr6ysramqq6iojYuLcnBwqaWmb21t\r\n        HRwbHh0cIyMhdXNyISEfMTEvWllZpqSlISEfJSQjQT8+dnRzo6CfSkhHISAfNzY0bGppbWxsHx8eXFta\r\n        W1lZn5ycnpuaop+fo56enZiZl5aXTU1NS0tLPj08XVpadnRzj42Nl5WVl5OUl5SUmJaVmZaVl5SUmJWV\r\n        l5STl5STl5STl5WUlZKRko+OlJGQl5SUl5OUmJaWmZWUko+Pi4mJjYuLkI2NkY+OkI2Nj4uLjYqKXVxb\r\n        ICAfHBwbJCQjHBwaISAfjImIGhkYHh0cPTw7aGZmY2FhIyIhHBwaGxoZGBgXFhYWHh4cU1FShoSEKign\r\n        MjEwJiUkWVhXhIKCTEtKLy4tPTw7TUxLaGVlaWdmfHl5gHx9amhodnR0fnx8enh3e3d4fHp6gH5+fnt8\r\n        dnNzdHNzeXd3e3d4eXZ2eXd4e3l5d3V1cnBwcW5ucnBwfXt7mpaWsaytzsrK1NDQ0s7NzsrKzsrK////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////xcLCxcLCxcLCxcPCyMXFxsPDxcLCx8XFycfHyMbGx8XFycfHysfGycbGysjJ\r\n        zMrKz83Nz8zNzcrKzsvL0M7Oz8zNzcrKzsrKzszMz83M0M3Oz83NzszLzsvM1dLS0tDQure3////////\r\n        ////////////////////////////////////////////////2tfY2tfY1tPT1dTU19bV19XU1tTT2dbW\r\n        3NnZ3dvb3tzc3tvb3tvb3tzc4N7e1NLTtbS0tbS0////////////////////////////////////AABr\r\n        AABrAABsAABsAABsAABtAABtAABtAABuAABuAABvAABvAABv////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////AAB7AAB7AAB8AAB8AAB8AAB2////AAB9AAB+AAB+AAB+AAB+\r\n        AAB+AAB/AAB/AAB/AAB/AAB/AACAQ0KbfXyzr67J29nc393d3NnZ2tfX2tfX2tfW2tfXw8DOBASEAACC\r\n        AACDAACDAwOEravG29jY2dfX2NXV2tXV2NTV2NXV2NXU19XU19TU1tPT1tLS2dbV29jY29fXw8HBbWuO\r\n        AACAAACAAACAAACAAAB/AAB/AAB/AAB/AAB+AAB+AAB+////////////////////////////////////\r\n        ////3Nna1NPS0c7O0c7OzsvLz8zMz8vLy8nIy8nIzMjJycbGyMbHy8jIzcnJzsrKzsnJy8jHzMjHzsnH\r\n        zMfFycXEysfGy8jHyMXExsHBxsHBxcHBwr+/wsDAwb6/o6GxenigNzaGAABwAABwAABwAABvAABvAABv\r\n        AABuAABuAABuAABtAABtAABtAABt////////////////////////////////////////////////////\r\n        ////////////wb6+wb6+uLW0tLGxtbOztbOytLOztLOzt7S1uLS0tbKxtLGxtLGxtLKxs7Cwta2rt62q\r\n        tK6ss6+vs66us6yrs62rsq2rr6uqsKuqsa2tr6urraqqq6ioqqenq6iorKioc3FvfHp5cnFwYl9fbGpr\r\n        Hh4cISEfLy8thoODIiEgKCcmOzs5ioqIqKWlMTEwIiIgLSsqZ2Vlf319R0VER0RDXFtboZ2cnpuaoZ+e\r\n        n5ybnJmZnpuaSEdHNjY2ICAfXFtbSkpKX2Bge3t8lZOVmJWWnJiYm5iXmJaWm5qampiYlZKSlJGRl5SU\r\n        l5STkpCPkI2LkI2MlZGRlZKSlJGQkI2NjYuMjoyLko+Oko+PkI2NjouLkI2NkI6Nh4SEVlRUPTw7Pj08\r\n        bmtrd3RzGhoZHx4dNzY1YGBfWFZWIiIhKysqKikoZGJicW5thIGAhoSEiYeHHBwcJCMiOjk4Z2Zlg4GB\r\n        NTQzHBsaIyIhLy4uJCMiQEA/TEtKU1FRUlFQNzY0VVNScG1tfXt6f318gX9+f3x8e3l5e3l5fnx8fHl5\r\n        enh3e3l4e3l5d3V1dXJydXJxd3V0eXh3eHZ1cm9veHZ2l5SUuLW1w7/Aw7/A////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////vLm5w8C/wsDAw8HBx8XFyMbGx8TFx8XFx8XFxsPDxsTEycfIysjJysfHycbGyMbGzMrK0c/P0M7O\r\n        zcvKzsrKzsrKzszMz83NzszMzsvMzMnJy8jIzsvLz83NzszMwL29m5eY////////////////////////\r\n        ////////////////////////////////1dLS19XV1dPT09HR1NLR1NHR09DR19XV29jZ29jY29jY29nZ\r\n        29fY29jY3dvb2tnZy8rKs7Gy////////////////////////////////////AABrAABrAABrAABrAABs\r\n        AABsAABtAABtAABtAABuAABuAABuAABvAABv////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////AAB7AAB7AAB7AAB8AAB8AAB8////////////AAB+AAB+AAB+AAB+AAB+AAB+AAB/\r\n        AAB/AAB/AAB/AgKBBAOBFBSJSUiegX+1srDJ29jZ3NnZ3dra3NnZnJm/AACCAACCAACCAACCHR2OzMrT\r\n        2tjX2NXV2dXU3NjY2tfY2dbW2dbW19TU19XU2NTU2dXW2NXV19TU2NXUy8nIoqChFxd7AACAAACAAACA\r\n        AACAAAB/AAB/AAB/AAB/AAB+AAB/////////////////////////////////////////2tfX0c/PzczM\r\n        zszMz83Nz83N0czLz8vKzMrJy8jIycfHysjJy8nKzcnKzcrKzcrKzcrKzMnJy8fGy8bFysbFy8fHzMrI\r\n        y8jHx8TExMLCw8HBw8DAxMLBxcPDw8HAwb++wr6+lJKtWVeVGBd6AABwAABwAABvAABvAABuAABuAABu\r\n        AABtAABtAABtAABtAABsCQlv////////////////////////////////////////////////////wr++\r\n        wr++vbq6t7SztrSzuLa1t7W1uLa1ube2ube2uLa0tbKytLCwtLGwtLKxuLCvvrGtvLCstq6ss62stKyq\r\n        uK2qta2rs62ss66ts6+usK6tr62sr6ysrauqrqurrKmpRkVDJyYlTUxKcW9vnJqaamloVVRSYF5eQ0JA\r\n        Hx4dIyMhPTw7h4eGq6mqISAfNjY0UU9PlZOSaWdmJyclRUVDZGNhpKGhoqCgpKGhnpybm5mYnJmYbGpo\r\n        OTk4MTIxODg3ICAfUFBPfX19hoWGZWVkgX59lpOSmJWUmZeXm5mZlpOTk4+PlJCQlJCQlJGQk5GPk5CP\r\n        lZKSlJCQkY6NkpGRk5GRlJGRk5GQko+PkI2MkI6OkI6Nj4yMj4yMj42MjouKjYuKjIqJbWxsGhkYHRwb\r\n        LCsqcXBvYF9dJCMiLSwrZmRkX11cRkRDZ2ZkfXt6end3GRkYHBwbNzY1cnBviIaFNDQ0GRgXHRwbXFpa\r\n        RUNDOzk5OTg3VlRTVFNSJiYlOTg2Y2FfW1lYSUhHa2ppd3V0gX9+f3x9e3l5enl4enh4eXd3dHNydHFx\r\n        d3V1enh3eXd2eHd2dXR0dHJyb2tsbGpqe3p5w7/A////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////vLm5vLm5xMHBw8HB\r\n        w8DAw8DBxcPDxsTEx8XGx8TEx8PCyMXEycfHy8jJysjIycbGx8TFycfH0dDPz87OycfHycXFzMnK0M7P\r\n        0tHR0M3OzMnKycfHy8nJ0M3N0M7Oy8nJvbq6m5eYm5eY////////////////////////////////////\r\n        ////////2dXW2dXW1dLS19XV1dLS09HQ1dPS19XU2NXV2dbX2dbX2NXW2dfY2tjZ29jZ29nZ3Nra3dvc\r\n        1tPUs7GylZKU////////////////////////////////AABqAABqAABqAABrAABrAABsAABsAABsAABq\r\n        AABtAABtAABuAABuAABvAABu////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAB7AAB7AAB7AAB7AAB8AAB8////////////////AAB+AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/\r\n        AAB/AACAAwOBBAOBGBeKTEufg4G1tbPK3NnZbGutAwODAACCAACCAACCNzeYzMnT2tbW2dbV3NnY3tzb\r\n        3Nzb2tjX19TU1dLS19TT29fX2tfY2NXV19TU3tvb09LRqaenNDNWAACBAACAAACAAACAAACAAACAAAB/\r\n        AAB/AAB/AAB/AAB/////////////////////////////////2tfX2tfX1dPS0c/Pz8zNz83N0M3N0MvL\r\n        z8vLzMrLzMrKzcvLzsvMzszMzczMzMrKzMnKzMrKzMnKy8nJysjHycXFyMXFysfHy8jIycbGxsPDxsLC\r\n        wsDAv729w8DAxMLCwr/Aw8HCxMLDxMLCsrC5YmGZOTiIERF3AABvAABvAABvAABuAABuAABuAABtAABt\r\n        AABsCQlvAABsAABsFBRy////////////////////////////////////////vbq6v7y8ube2uLW1uba1\r\n        ube2u7i3uLW1trOys7GwtLKytrKytLCvs7CvtLGxtrOzurOxv7KvvbCutK6ts62sta6stq6ttK6us7Cv\r\n        sq+vsK2tsK2tsK2tsa6usK6trquqjoyLX15dMzIyZGNjr6ysrampq6enq6ioe3p6Li4sHx8fPz09qaan\r\n        q6qqIyMiR0ZEUVBPko+QUE5NJCMiPDw6ZWNipqSkp6SlpaKioZ+enpybnZmZMTAvSEdFT05MZGNinJmZ\r\n        ko6Nko6OOTg3OTg3VlVVYWBegX59hIGAmZaVmZaVl5OTiYaGZGFhcG5tg4B/joyLl5WUlZGRk5CPk5KR\r\n        lZOUlZOTlZOTlJGRkpCQkY+OkI2NkI2NkY+PkI6NjouLjYuKjIuKdnRzISAfGhkYHh0cb21shIOCICAf\r\n        Hh0cR0VET01NODg3SUhHZGFhbGlpICAfHR0cNjU0cG5ti4iIPj08ICAfJSUjb21sODg3KyopOjg4UE5O\r\n        Pj49KyopOTc2ZmRjU1FQJCMiQD8+VFFRgn9/f318bmtqcG5tfXt6eHV2dnN0d3RzeXZ2eHZ2eXZ1d3R0\r\n        dnR0eHZ1cm9vcGxue3p5////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////xMDBxMDBw8HCwsDAw7+/wr/AwL2+wL+/\r\n        w8HCxMHCyMTDy8fGycbGxsPEx8TEyMTFx8XFyMXFy8nJy8nJycbGycbHy8nKzcvM0M3Nz8zMzMnIzcrK\r\n        zcvKzMrKzMrK0M7Nx8TEm5eY////////////////////////////////////////////////2dXW2dXW\r\n        0c7P1NHS09DQ1dLS19TU2NbW2NbW2NXV2NXV2dbW2tnZ29na3Nra3tzc3Nvb29na2dbYycfIlZKUlZKU\r\n        ////////////////////////////AABpAABpAABqAABqAABrAABrAABrAABsAABqAABtAABtAABtAABu\r\n        AABuAABuAABuAABv////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAB6AAB6AAB7\r\n        AAB7AAB7AAB7////////////////////////AAB+AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACA\r\n        AACAAwOBAwOBGxuMTEufKCiRAQGBAACCAACCAQGCTk6izcnT2tXW3NnZ397d3tzc3tzc29nY1tPS1tPT\r\n        2tbW29jY2tjY2dfX29fY3NnZ0c/PramoeXV0AQFoAACBAACBAACAAACAAACAAACAAAB/AAB/AAB/AAB/\r\n        ////////////////////////////////////2tfX3Nra1tLT0dDQz87Oz83Mz8zMz8zNzszNzszM0MzM\r\n        zsvMzczLzs3Mz8zMzsnJzMnKzcvMz8zNzMrKycfHyMbGycbGysbGycXFzcXDz8bEyMPDwL2+vry8wL2+\r\n        w8DAxsPExcPEw8LCw8LBwL3At7W7mZauTkyQHBx8BwdyAABvAABuAABuAABuAABtAABtAABtAABsAABs\r\n        FBRyAABsAABrR0WD////////////////v7y9v729w8LBvbq6vbq6uLa2uLW1ubW2uba2ure3uLW1tbKy\r\n        s7CwtbGxuba2uLS0t7OyuLSztrO0trOzvLSyvbSztrGxsrCvs6+vs6+vtLCws7Cws6+wsa6usa6usq6u\r\n        sa6usa+ur6urrqurraqrsK6usK2trKmoq6ioramqrqyssa+unZuba2hompiXrKmorKmpMzIyLCwrPz49\r\n        f3x8Li4sJyYlQkFAend3paKipqOjpaKhpKKho6CgoJ2dMzIxOzo5MTAvg4B+nJeWm5eWmpaVJSUjISAf\r\n        MjEwLy4tJCMhSEVEZWNhgH58m5eXSEZFHx4dISEfNTQySEZFbm1slpSTlJGPko+PkZGSkZGSlJOTmZaV\r\n        lpSUkpCQkY+Pk5CQk5CPko6Oj4yNj42MkI6OcXBvY2Fha2loRENDjouMjoyMdnNzKCcmGxoZJCMiHR0c\r\n        JCMic3FwbmtqHRwbJSQjMTEwgn9/iIaFcXBvICAfHR0cXlxaOjk4HBwbKyopODc2GxsaJiUkMzIxamZm\r\n        REJCGhkZLCsqSkdHg4CAbWxrLCsqS0lIW1hYZmNjfXp7fXp6e3h3end3eXV1eHR1eHV1eHV1d3V1eXZ3\r\n        eXZ3////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////uLa3wb+/wL+/wL6+wb+/wsDBwL/Av729v7y9wb6+xsLDycbH\r\n        x8TFxMHCxMLCxcPDxcPCxsTDxcPDyMXFy8jIzMnKysnJycfFysjIzMnKy8jIzsvLzMnKyMbGy8nIz83M\r\n        vru7jYqL////////////////////////////////////////////////0s7O19TV0c/Q09HR1NLS2NXV\r\n        1tPU1NHS09DR1NLS1tPU2NbW2tjX2tjY2dfX2dbX2NXV2dbX3Nrb0M/Qr66ur66u////////////////\r\n        ////////////AABpAABpAABpAABqAABqAABqAABrAABs////////AABtAABtAABtAABtAABuAABuAABv\r\n        AABu////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAB6AAB6AAB6AAB7AAB7AAB7////\r\n        ////////////////////////////AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACA\r\n        AgKCAACBAACBAACBAACBAwODXl2o39zc3dnZ3dvb3tzc3dva3dra3NnY2tbW3NrZ39zc3dra29jY2tfX\r\n        2tfX3NjY1tTUwb6+ko+QPz5rAACBAACBAACBAACAAACAAACAAACAAACAAAB/AAB/AAB/////////////\r\n        ////////////////////////3Nra2tjY09HR0M/Ozs3Mz83N0s/Q0M3OzcrKzsvLzcvLzMrKzcvL0MzM\r\n        0MzLz83M0M7Nz8zMzcrKy8rKy8nJzcnJy8jIzMjH0MjG0MjFy8bFyMbGxsTFxsPDxsPDx8PDx8TExsTE\r\n        xsPDxMPBwsHBwr/AtbK7kpGtZGOaNjaGGhp6BgZyAABuAABuAABuAABtAABtAABsAABsAABsAABrR0WD\r\n        CQlvOTiDfnuXxMHCv7y9v729w8LBvry8u7i4vLq6vLm5uba3ura3uLW1uLW0ure2ura2ubW1ura4vLi4\r\n        vbe2vba1uLKyt7OyubW0uLW1uLS0tbGwtbCwtLGxtbKytbGytLCxtLGws7Cvs7CwsrCvsq+vsK2tsa2t\r\n        sa6vsK6usK6trqysr62tsK2usK2tsa2trqurrqqqrqyrraqprKipkpCRMTAwIiIgIiIgICAeJCMiNTQz\r\n        fHp6p6WlpaKipaOjqaenp6WlkI+PIyMhNjY0Ojg4hYKBn5ubpKGhmZeWHR0cICAeLSwqend1Pj08ISAe\r\n        Q0E/Xl1cmpeWfnx8XltaNDQyNDMyLS0sLi4sZ2Zkko+OlJGQlZOTkZCQkZGSl5SUmZWVlpOSlJGRlJGR\r\n        k5CQkpCPko+PkY+Pk5GQW1pZIB8eNjU0XFpZj4uMkIyNj4yMjYuKXl1cRkRENzY1YWBfeHV1GxsbHBsa\r\n        ISAfUE5Ni4iIgH5+amlogHx9MTAvHh0cJCMiHx4dNzU1VFJSGBgXHRwbLy4ubmprNDMyGhoZLCsqWVdW\r\n        gn9/Uk9QGxoZKCgnMC8uMC8ugH5+fnx8fnp6fXp6end2d3R0d3V1d3R1e3l5e3p6e3p6////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////uLa3uLa3wL6+v729wL69wL6+wb+/w8HBxMLCwsDAwb6+wsDAxcLCxMHCxcPDxsXExcTD\r\n        xcPDxMLCxcLCx8TEysjIysjIysjHysfHysfHysjIycfHysjIycbHx8XFzMnKzcvLvLm5jYqLjYqL////\r\n        ////////////////////////////////ycbFzMnJ0s7O09HR09HS09HS1NLT19XV1tTU1dLT1dLT1NHS\r\n        1dLS19XU19TU1tTU1tPU19TV19XV2dbW3NnZ1tXVxcTEr6yt////////////////////////////////\r\n        AABpAABpAABpAABpAABqAABqAABrAABr////////AABtAABtAABtAABtAABuAABuAABuAABu////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAB6AAB6AAB6AAB6AAB6AAB7AAB7////////////////\r\n        ////////////////////AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACB\r\n        AACBAACBEBCJb22usrDK39zc3tvb2tfY3dra3tva3tvb3dva3Nra3NnZ3NjZ3NjZ2tjY2tjZ3dvb1dPT\r\n        wr+/lJKVDg14AACBAACBAACBAACBAACAAACAAACAAACAAAB/AACA////////////////////////////\r\n        ////////3dvb3dvb1dPT0c/Pz8zMz83N0s/P0s7OzsrKzMjJzczLzszMzszMzszN0M3N0c7O0M3Nz8zM\r\n        zszLzsvLzcrKzsrKzcnJy8jIzMjIy8fGy8jGysjIy8jIzMnIycbGxsTEx8TEx8XDx8PDyMXFzszMysjH\r\n        x8XFx8XGw8LFr6y6lJKvZGKaMTCEAQFuAgJvAABuAABtAABtAABtAABsAABsAwNsCQlvOTiDfnuXxMHC\r\n        wsDAwsDAxMLCwb6/v728wL69vru7vLi5ure4uri3ure2ura2ura2ure3u7e4u7i4vbm4vbe2vLWyuLOy\r\n        trSzuLWzvbe0urSyta+vtrOxtrKyt7OztrKztLGxtLGxtLGws7Gws7Gws7Cwsq+vsq+vrqyrrqyssrCw\r\n        srCwsq+usKyssK2traurraqrr6yrr6yrr6ysr6ytpaOihoWDmJWVPz8/HRwbJCMihYSEraurrKqqrKur\r\n        rKqrq6ingoB/R0ZFPz8+SUlIT05MhIKClpOSgn9+QUFAIiEgOzo4fXl5Pz48ISAfNzY0aWdmmpiYamhn\r\n        UlBPX11dioeHYF1eKCcmKSgmZGJhl5WUl5OSlJCPk5CQkpGRk5KRl5OTlpOTlpOTlpOSlZKSk5CQk5CR\r\n        k5GRg4GAWVdXMTAvNDMykI2Nj42MjYqKj42MkI6OkY6OkI6OkI6Ofn18MTAvIyMhICAfPTw7ZGJicW5u\r\n        WlhYSkhHUU9PT0xMGRkYJCMiOzo6V1RUIB8fHRwbTUtKhoOCLi0sHBwbNTQzYV9fgn9+UE5OGBgXGhoZ\r\n        ISEgZmRkgoB/gH18fXp6fHp6fHp5end3eHV2enl6fXx7e3p6////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////vbu7\r\n        vbu7vry8v7y8wLy9wb29v7y8v729wcDAwsDAv7y8wLy9wb2+wr6/xMLCxcTDw8HBxsTDxsTExcLCxcLD\r\n        x8XFycfGyMbGycbHycXFyMXFyMbGycfHyMbFx8XFx8XFy8jJxcPDrKmpiIWF////////////////////\r\n        ////////////////ycbFzMnJzMrL0tDR1NLS1NLS1dTU1dTU09HS1NLS1tTT1NHR09DQ1NHR1dHS1NLT\r\n        1tPU1tTU1tTU19TV19TU2NXVzcvLr6ytr6yt////////////////////////////AABoAABoAABpAABp\r\n        AABpAABqAABqAABq////////////AABtAABtAABtAABtAABtAABuAABuAABu////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////AAB6AAB5AAB6AAB6AAB6AAB6////////////////////////////////\r\n        ////////////AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACBAACBAACB\r\n        AACCLSyUZ2WshIO3ubnN3trc1NDY3tzb2NXV3NjY4+Dg4N7e2dbW1dLT2NXV3NnZy8nInpycLi5TAACA\r\n        AACBAACBAACBAACBAACAAACAAACAAACAAACAAACA////////////////////////////////////3dvb\r\n        29nZ1NLR0M7P0M7P09DQ09DQ0c7Oz83Nz8zNzcvMzszMzcvLzMrKzsvLz8zMzszMz83Mz8zMz8rKzsvL\r\n        zsvKy8jIy8fIy8fIy8jHysjIycbGycbGysfHyMXFx8PDx8TEyMXEwr+/wb+/zMnJzMnJy8jJy8nJysjH\r\n        ycbGwr/Dqqi4Y2GZMjKECwtzAgJvAQFuAABtAABtAABsAABsAABsAABrXlyVvru9wb29wb6+wr2+wr6+\r\n        wsC/wb6+wL29v7y7vbm6vLm5vLm4ure3u7i4vLq5vLm5uri4vbm4wbq4vri2uba1trOzvLi2wry5vba0\r\n        trGyt7S0t7Szt7OzuLW1t7OztbKxs7GwsrCvtLGxtLKxtLGxsq+vr62srqussKytsa+usa+ur62srqys\r\n        sK6usa+vs7Cwsq+vr6ysrKqqrKmprKmqrqussa6wlJGSZGJinZqaraqqrquqraurrqusrqurfHt6JSUj\r\n        RkVEPTw6KikoMjEwb21scG1tMjIxKyspQ0JAn52cHh0cISAfOzo4b2xrmpaWKSknOjg3V1VTUE1NXlxb\r\n        RkVDamhnaGZmmZaWmJSUjoqKjouKlJKSlZOTlpOUmJaWmJeWmJWVl5KTlpOTlJKSlJKSlZKRlJGQkI6O\r\n        kI2Nko+PkpCPkIyMj4uLkI2NkI6Oko+PkY6OkI2NSkhIHBwbJiYkKiopPz09bWtrHBwbLCsqWVhXfXp6\r\n        GRgXHRwbOTg3amhpKyopKikpWFdWhoODGRkYHRwbNTMyYl9ehYOCRENCHBsaOzo5QT8+goCAgoGAg4F/\r\n        gX59f319fnx8fXt7fXt7f319gH19gH19////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////tbOzu7i5vLm6v7y8v7y8\r\n        vry8vru7vru8wL6+v7y9vbu7vry7v7y8wL2+wr/AxMHBxcLCyMbFyMXFxcTExcTExsTDxsTExsTExcLD\r\n        xsPDxcPCxsTDx8XFxsTExsTExsTEyMXFx8TEuba2iIWFjIqK////////////////////////////1NHQ\r\n        ycbFzMvKzMvL09HR09HR09DQ09DQ0s/Pz83Nz87N09HQ1NHR0tDQ0tDQ09DQ09HR1dLS1NLS09LR1NLS\r\n        1NLS19TU09HRwb6+paKi////////////////////////////AABoAABoAABoAABoAABpAABpAABpAABp\r\n        ////////////////////AABtAABtAABtAABtAABuAABuAABu////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////AAB5AAB5AAB5AAB6AAB6AAB6////////////////////////////////////////////////\r\n        ////AAB+AAB/AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACBAACCAACCAACC\r\n        ISGPVVSkZWOqxsPQ2NbV29jX4t/e4d7f29jY2dfX3NnZ2dfWzMnJo6GhdXNyAQFrAACCAACBAACBAACB\r\n        AACBAACBAACAAACAAACAAACA////////////////////////////////////////29nZ2NXV0s/P09HQ\r\n        1NPT1NLS09HR0tDR0M3NzszMz87Oz83NzcvLz8zN0M7Oz83M0M3N0M3Mz8vMz8vMzsvLzMnIysfHy8jI\r\n        zMnJzMnJysbGycTEycXFycbFyMbFyMbGyMXEv7u7mpeXzMnJw8DAz83Oy8nKycfHycfHysfHyMbFx8XF\r\n        vLnBkpCuYmGYLSyBCQlyAgJuAABtAABtAABsBgZvfXuiwL69wb29wb69wL29wr6+wr6+wLy9wL69wcC+\r\n        wb6+vbq6vLm5vLm5vLm5vrq6vbq6vbq6vbq5v7q4vbq4u7m5ure3vrm3xL25v7i2ubW1uLW1t7OzuLW0\r\n        ube2uLW1tbKytLGxtLKytbOztrSztbOytLGxsq+vsa+usa6tsq6tsa6tsK2usa6vsq+vtLGwtLCwsq6u\r\n        r6ysraurraqqraqrsrGytbS1s7KysK6urqurraioraqprKmpraqrr6ysbGtqLi0rODc2NjU0cW9vQ0FA\r\n        gX59aGVkISAgMzMxSEZGoZ6eHx4dIyIgPjw7goB+n52cHh0dISEfLy4sOTg3Hx4dMC8uPjw7dHJxm5iY\r\n        YWBgTk1MX15cY2JgeHd2k5GRl5aWmJaWlpOTmJWVmZaWl5SUlZKSlJGRlJGQkpCPkY+OkY+Ok5GQk5CQ\r\n        ko+Pk5CQkpCQlJGRk5GRkY+PWVhWISEgGxsbPTs6hoWEhYKCISAfJSQjX11db21tHRwbHx4dMjEwW1pZ\r\n        HR0cNDMyWVhXiIWEGhkYHh0cNDIycG1tiYeGODc2IB8eNzY1V1ZUgoB/gX9/goB/goB/fXt7fXt6f3x7\r\n        fXt6fXt7fXp6fXp6////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////tbOztbOzvbq7vry8vbu7vLm5u7m4u7m5vLm6v7y8\r\n        v769wL6+wb+/v7y8v729w8LBxcLCxMDBw8LCxcLCxsTEx8bFxsTExMLCxcPCxsPDxsTDxcTDxcPDxcLD\r\n        xMHCxcPDx8XEx8bEyMXFv72+q6mpjIqKraur////////////////////wr/A1NHQw8DAwsDAysnJz83O\r\n        z87P0s/Pz83NzszM0M7N0M3N0M3N0M3O0M7O0dDP0dDP0M7N0c7O0tDP09HR1NPT1dPT1tTU2NbVysfG\r\n        paKipaKi////////////////////////AABnAABnAABnAABoAABoAABpAABpAABp////////////////\r\n        ////////AABtAABsAABtAABtAABtAABuAABu////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////AAB5AAB5\r\n        AAB5AAB5AAB5AAB6AAB6////////////////////////////////////////////////////////AAB+\r\n        AAB/AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACBAACBAACBAACCAACCAACCAACCgoG0\r\n        19bV3tzb4t/g4d7f4N3e4Nzd3Nra3NrZ1dPSwr++iIWFKCZZAACCAACCAACBAACBAACBAACBAACBAACA\r\n        AACAAACAAACA////////////////////////////////////1NLR1NLR0M3M0c7N1NPS09LR09HR1NHR\r\n        0tDQ0M/P09HR1NLS0tDQ0M7O0M7O0M7O0c7P0c3Nz8vLzszM0M3Nz8zNzcrJzsnIz8nIzsrJzMjJysbG\r\n        ysbGysfHycfHzMrKx8XEsK2rmpeX////w8DAz83Oy8nK1NHRzMrKx8TExsPDysnJysnJy8jIysfGt7S+\r\n        jYuqXl2XJyZ/Dw90DQ1zOjqFuLa7w8HAxMC/w7+/wL69wb6+wL29wLy8wL29wsDAxMC/wr29wL28wb6+\r\n        v7y8vru7vbq6vbq6vbq5vbm5vbu7vry7vLm5vbi4wLm3vri3u7i3u7i4ure3u7i4ure3uLW1uLW0t7Sz\r\n        t7SztbOytrS0trOztrKytbGxtLKxtLKys6+wsa6usa6vsrCwtLCwtbGwtbCwsq6tr62tsK6tsa+ur62s\r\n        srGxtrW2s7KyrqysrKmprKmpq6inrKioraursK2tbGtqICAeIiIhKyooq6enqaWlpqOiXV1cHx8eJCMi\r\n        UE5NioeHHx4dJSQjPj07gn9+iIeFHx4dIyIhMTAvj4uLLSwrJSUlISAfZWNijoyMIiEgJSQjIyIhIiEg\r\n        KyopW1pZj42MlpSTlZOTl5WVmpiXmZaWlZKSkpCPkpCQlJKRlZKRk4+Pk5GQlZSTlJOTlpSUlZKSlpOU\r\n        lpWUlJKQk4+PlJGSamhoc3Fxj4yNj42NX11dOjk4TEpKLS0rGxoZGxsaJCQjSEhHHRwbMC8uXFlZbWpp\r\n        GxoZIB8eMzIxb2xsiYaFKSknHBsaIiEgX15dg4B/gX5+gX9/f319end3d3RzenZ1eXd3e3h5fXp6////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////ure3ure3u7i4vLq6u7m5uri3u7m5vLq6vbu7v7y8wL++wsHBxMLCwr+/\r\n        wsDAxMLCwb+/wLy9wL6+wsDAxcLCxsPDw8LBwr+/w8DAxcPDxcPCxcLCxcLDw8HBxMLCxMHBxcLCycfH\r\n        y8rJzMvKxcTDvbq6raurxMLCvbq6r62srayrvbm5wr/AzsvLyMXFxcTEycfHzMnJz83N0M3OzMjJzMnK\r\n        0M7O0c/O0M7Oz83N0M3M0c7O0dDP0M7O0M3N0tDP1NLS1dLT1dLT09LS1NHS0M3Ovbu6qaio////////\r\n        ////////////////AABmAABmAABnAABnAABoAABoAABoAABo////////////////////////////AABs\r\n        AABsAABtAABtAABtAABuAABtAABu////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////AAB4AAB4AAB4AAB5AAB5AAB5\r\n        AAB5////////////////////////////////////////////////////////////////AAB/AAB/AAB/\r\n        AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACBAACCAACCAACCXFyo3t3c4t/g4+Dh4t/g\r\n        49/f4d7f3dvc29nZ3dra09DQq6eodHF2Cgl4AACCAACCAACCAACBAACBAACBAACBAACBAACAAACAAACA\r\n        ////////////////////////////////19TU19TU1NLR09DQ09HR1dPT1dTU1NLS0s/Q0tDQ0tDQ1NDR\r\n        1dPT0tDQ0M7N0c/P0tDQ0c7Oz83M0M7O0c/P0M7N0M3M0MvL0MvK0s/O0tDQz83NzcrJy8jIzcvKzsvK\r\n        w8DAsK2r////////////////////1NHRzMrKx8TE0M3Nzs3N0c/PzcnJzcnIycXFx8XEyMXFs7G8j42s\r\n        c3KfnZqxxsPDxsTExcLCxMDAwr+/v729wb++xcC/xL6+xcC/xsG/x8C+xcC/wb6+vry8vry8wL28vru7\r\n        vbq6vru7v7y7v7y7vrm5vbi4v7q5wLu5vbm4vLi4vLq5vLm4vLi3vLi4vrq6vLi3uba0t7Szt7S0t7W1\r\n        trSztrS0trSztrOztrO0tbKztbKxs7GwtLGxtbCwtbCvs6+vr62tr62tsrCwsq6usq+vs7Kzsa+vraqp\r\n        rqmqraqqrKqqrqurr6yrrqurY2FhKyopLy4tUlFRqqenqaWlqaSjRUJCKikoLSwqW1pZhoSDHx8dJycl\r\n        R0ZEmZeXh4WEHh4cJyYlQT8+oZ+fMjEwOzo4YmBfbGlpbmxsIB8eKSgoICAfi4mIMC4uPTw7bWtrlZOT\r\n        l5WVlpSUl5WVmZaVmJWUmJWVl5SUlpSTlpOTlZKSlpOTl5WUl5WVl5WVl5WUlZOTlZKSkpCPko+Pk5GR\r\n        lZKSko+PkI2NjouMkI2NaGZmOTg3QT8/KiopQkJBUU9PNzY2GRkXHBsaOjk4WVdXHBwaKSgnOjg2gX18\r\n        hoOCGRkZIyMiLi0sX11dhICAhICAgoCAgX9+fnx8fXp6fHl5fXt7fnx7fnx7////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////tbO0uLa2uLW1uba2u7q5vLu6vLm6vbq7vby7vry8vry8wb++wcC/wb+/wsDBwb6/v7y8vry8\r\n        wb6+wsC/wsDAwb6+wb++wb6+wL29wL6+wr6+w8DAw8DAw8DAxMLCxMHBw7/AxsPEyMbGycfHysfHysfH\r\n        xsTExMLCvbq6r62srayrvbm5ycbGysfHzMnJzsvLzMnIy8jIz8zMzsvMzcrKzszM0M7O0M7O0c/Q0c/Q\r\n        0c7O0c7P0s/P0c7P0tDQ09HR09DR09DR09DR09HQ0s/P0tDQycjIqaioqaio////////////////////\r\n        AABmAABmAABmAABnAABnAABnAABoAABoAABo////////////////////////////AABsAABsAABsAABt\r\n        AABtAABtAABuAABu////////////////////////////yMXF0tDP0tDPvLu7pKKi////////////////\r\n        ////////////////////////////////////////AAB4AAB4AAB4AAB4AAB5AAB5AAB5////////////\r\n        ////////////////////////////////////////////////////////////AAB/AAB/AAB/AAB/AAB/\r\n        AAB/AACAAACAAACAAACAAACBAACBAACBAACBAACBAACCJiWS3dri5+Tk5OLi4+Hh4uDg4uDg4t/f4N3d\r\n        39zc29nYzcrLr62tVVSBAACCAACCAACCAACCAACBAACBAACBAACBAACBAACAAACB////////////////\r\n        ////////////////////19TU393c2tnZ1dTU1tPT19XV1tPT1NDQ1NHR0c7P0s/Q1dPT1NLS0s/Q1NHR\r\n        09LR0c/P0s/Q08/R0M3NzsrK0M3N0M7O0M3M09DQ1NPS0c7Oz8vL0MzMz83MzsvLxsLCxsLC////////\r\n        ////////////////////////0M3Nzs3N0c/P1NDQxsPIzMnJycXFycXFyMTEx8XFx8XEyMTEycXFx8TF\r\n        xsPExcLCxMHBxMLCxcLBx8LAx8HAx8G/xMC+xL+/xsC/wr29v7y7wL28wLy8vbq6vru7wb29wr69wr29\r\n        wby8v7u6wLy6wry5wLq4vLm4vbq5vru6vbm5v7u6wbu7v7q6u7i3ure3uba2uLe2uLe2uLW1trOztbGy\r\n        t7W1ube2uLa2trS0tLGxtbGxtLGxtLKxsrCvsq+vtLKytLGxs7CvsrCwsa6vsa2tsq2tsa2tr62usK+w\r\n        r62sraqpRkVFLSwqJiUkSUhGX1xaf3l2sKejTktLIB8eJSQjaGZlfnx7IiIhNzY1SEdHpaKgbWtrHh0c\r\n        IiEgMjEwp6WkT05MU1FQRURCdnRzZmNjIyIhSUdGPj08oZ+fHh0cJiYkSklHkpCQmZeXlZOTlpOUmJaW\r\n        mZeXmpiYmpmYmJaVmZaWmpiXmZeWmJWVmJWVl5SUl5WUlJGRko+Pk5CRlJKRlZSTlJGRko+PkI6OkY+P\r\n        ko+PkpCPj4yMfnt7WFZWcXBwkY+Pd3V1VFNTTk1MQUA/MDAwGhoZHR0cNTIyhoKBh4WDHR0bJyUkNjU0\r\n        aGVkgX5+gn5+gH19f319gH9+gX9/gX9/gX5+f318f318////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////tbO0tbO0urm4\r\n        uLW1uLW2uri4vLm5u7i4u7m5vbu8vry8vLm6vbq6wL29wL6/v72+wL29wb++wb+/wL6+wr+/v76+v729\r\n        wr6+wr+/v728vru6v7y9wb6+wb+/wsDAxMHBxMLCxMLCxMLCxcLCxMLCxcLDxMLDx8XFy8nJzMjIxsLD\r\n        x8XFy8nJzMvLy8nJysfIzcrKzMnJysjIzMrKzszM0dDP0tDP0M7P0M7P0c7Q0c7P0M7O0M7P0M3O0M7O\r\n        09HR09HR0dDQ0dDQ0tDQ0tDQ0s/Q0tDRzs3OvLq8oqCf////////////////////AABlAABlAABmAABm\r\n        AABmAABnAABnAABoAABo////////////////////////////////AABsAABsAABsAABtAABtAABtAABu\r\n        AABt////////////////x8TE1NDQyMXF0tDP0tDPvLu7pKKiwsHAkI2O////////////////////////\r\n        ////////////////////////////AAB4AAB3AAB4AAB4AAB4AAB5AAB5////////////////////////\r\n        ////////////////////////////////////////////////AAB/AAB+AAB/AAB/AAB/AAB/AACAAACA\r\n        AACAAACAAACAAACBAACBAACBAACBAwOA3dri5+Tk6ebm5+Xl5uXl5ePk5OHi5ODh4t/f4uDg3tzcu7m5\r\n        e3h6AQFwAACCAACCAACCAACCAACCAACBAACBAACBAACBAACBAACB////////////////////////////\r\n        ////////393c2tnZ3dvb19XV1tPT1tLS19PT1dHR1dHS09LS1NLS09DR09HS1NLR1NHR1M/P1NDQ0s/Q\r\n        0czN0s7N0s/O0s/O0M3N0MzN0M3Nz8zLz83M0c7OzsvLxcLCxsLCxsLC////////////////////////\r\n        ////////////////////1NDQVVSUhoSt0s/OzcnJzcnJzcnJy8fHycXFysbFycTEycXEyMXEx8XFxsLD\r\n        xsHBx8PCxsPCxMDAw8DAwb/AxcDAx7++w768wL28v7u7vru7v7y9wL29w7++w7+/w7+/wr++wLy8wLu6\r\n        wLq5v7u6wLy8wb69v7y7vbq5v7u6v7u6vLi5ure4u7m5u7i4uri3uba3uLS1t7W1uLW1uLW1uLW2t7W1\r\n        t7W1t7W1t7W1trOztrOztrOztrS0trSztbKxtLGws7CwtLGxs7Cvsa6usa2usa6usK2trquraWhoREFA\r\n        MzAvLCooMC4sRkE+tqukiIOBODc2KyooMS8uNjQ0IyIhNTQzQ0FAp6KgZ2VkICAfPjw7cnBvoJ2cIiEg\r\n        Ly4sQ0JAgX59ZGJiJCMiRENCZ2dloJ2cHBsaHh4dLy8thIOCnZqam5iYmJaWmZeXl5WWmJaWmpiYmpiY\r\n        m5mYnZuam5iYmZaWl5SUlpOUlpOTlJGRk5CQlZOTmZeXmJWVlpOTk5GRk5GRk5GQlJKRkpCQkY+Pj4yM\r\n        jYuLjouLj4yMjoyMkI+OkpCQkY+OVFNSFRUUGBgXS0hIhoOEIyIhGhkYHRwbOzo6fnt6fnt7fXt6fHl5\r\n        eXZ2d3R0end2e3l4eHR1f318////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////t7O0t7O0t7W1uLW1uba2ube3uba3\r\n        ube3uri4vry8v729vLu7vbq6wL2+wb/Av72+v7y9wb+/wcDAv76+v7y8vru8v729wb+/wL69wL29wL29\r\n        v729wb6+wsDAw8HBxMLDxcTExsXExsPDxsLDxcPDxcHDxsTExcTDxsTExsPEycbGzcvLzMvLzczMy8jJ\r\n        x8TFycfIzMrJysnJy8rKzszN0M7Pz83Nzs3Nz87O0M3Oz8vMzcvLz8zNz8zN0s7O0s/Q0c/Q0dDQ0c/P\r\n        0c7O0M3O0M3Oz83N0tDRycbGoqCfoqCf////////////////AABlAABlAABlAABlAABmAABmAABnAABn\r\n        AABn////////////////////////////////////AABsAABsAABsAABsAABtAABtAABtAABtBARvYmCY\r\n        0M3Nx8TE1NDQ2tbW3tzb393d3NnZ1tTTwsHAkI2Ok5GS////////////////////////////////////\r\n        ////////////AAB3AAB3AAB3AAB4AAB4AAB4AAB4////////////////////////////////////////\r\n        ////////////////////////////AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACA\r\n        AACBAACBAACBAwOA////////6ebm5+Xl5uXl6efn6Obm5+Tl5uLj4+Hh29nZw8HBioeHJCNWAACDAACC\r\n        AACCAACCAACCAACCAACBAACBAACBAACBAACB////////////////////////////////////////////\r\n        3dvb3Nra19XV2NXU2NXV19TU2NbX29nZ2NXV1tPT1NLT0tDR1NDQ1tDP09DP0s7P2dPS3NjU1dHQ0c7O\r\n        0s7Pz8vMzMnJ0M7N09HRz83Nx8PExcLC////////////////////////////////////////////////\r\n        ////AAByAABwBgZuWVh+zcnJzcnJ1tLR0c3Nz8vLz8rIzcXCzcTCycTDyMbGysfHyMXFyMbGx8TExMHB\r\n        w8HBxMLCxcDAx8C+w7++wL++wb++wr+/w8DAwr+/wsDAwr+/wb6+wr+/wb6/wL29wLy8v7q6wLy8wL28\r\n        v7y7vbq6v7y7v7y7u7i4ure3u7m4vbm5vLm4u7m5u7m5uri4uba2t7O0uLW2uLa2uLe3uLe3uLW1t7Oz\r\n        t7OzuLS1t7O0trO0tbGys7Cws7Gxs7Cwsa6urqursKyssq2rsKyssK2ur6ysrqmonZWTb2dlR0JALysp\r\n        tqqlr6qojYyMX11dRUNCMjAwISEgNDIxaWZlp6SkaGZlIyIhU1FPcW9uiYaGICAfLi0sR0ZEf319QUBA\r\n        ISEgRURCZmVjhIKBc3BvUVBPMTEvhoSDn5ycn52dnJqZmpiXmpeYmZaXmpiYm5mZnJqanZmZm5eYmJWW\r\n        mJaWmZeXmpeXl5SVlpOTmJWVmpeXmZeXmJaVlpSUlZGSlJCRk5CQlJKSk5GRkpCQkY+PkI6NjouLjouL\r\n        j46NkI2Ni4iIiIWFZmNjWFZWgYB+iIWFNTQ0KCYlHR0cOTg2V1NTfnp6fnx7fXt6end3dnFydXBxdnJy\r\n        dHBwdHBw////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////tLGxtLGxtLKyuLa2ube3uba2uLa2t7a2uLa2u7i4vry7\r\n        vLu6u7i5vLq6vbu7vLq6vLm5vrq6v7y9v7y9vbq6u7i4vLm5vbu6wL28wsDAwcDAvry7wb6+xMHBxMLD\r\n        xcPDxsPDxcLCxMLCxMLDxsTEx8XFxsXExcPDxsPDyMbGycfGycbGyMbHysjIycjHxsXEx8XFycfHy8nI\r\n        y8nJzcrLzcrLzMrKzcvLzszMzsvLzcvLzszMz87Nz83Nz8vMz8zNz8zNzsvMzsvLz8zM0M3O0M3N0MzN\r\n        0c7OzcvKuri4op+g////////////////////AABlAABkAABlAABlAABmAABmAABmAABm////////////\r\n        ////////////////////////////AABsAABrAABsAABsAABtAABtAABtBARvYmCY0M3N1tPT29nY3Nra\r\n        3NrZ2tfY2tjY3dvb1NLSwL6/k5GSk5GS////////////////////////////////////////////AAB3\r\n        AAB3AAB3AAB3AAB3AAB4AAB4////////////////////////////////////////////////////////\r\n        ////////////AAB9AAB9AAB+AAB+AAB+AAB/////AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACB\r\n        ////////////////////6efn6Obm5+Tl6ebn6Obm5OLj3Nvburi4dXJ0AAByAACDAACDAACCAACCAACC\r\n        AACCAACCAACBAACBAACBAACB////////////////////////////////////////////3Nra19XV397d\r\n        2NXV19TU2NbX29nZ2NXV3NnY2tjY1dPT1dLR1NLR0tDQ1NHQ29bT29fT09DO0c7O09DR0M3Ny8jJ0c/P\r\n        2dbW09DQx8PE////////////////////////////////////////////AAB0AABzAABzAAByAAByAABx\r\n        WVh+////////1tLR0c3NzsvLzcfG08nHzcTDy8TEysbGy8fFy8jFysbFysTDyMPCxcPDyMXFyMTExcHA\r\n        wsDAw8DAxcHBxcDBxMHBw8HBxMLBxcHAw76+wr+/xMHBw8DBwb6+vry7vru7v7u7v7u6v7y7v7u7vrq6\r\n        vLm4vbm5vLm5u7m4vbq5vLm5u7m5u7m5u7i5ube3ube3ure4uba3uLW1t7Szt7Ozt7SzuLa0t7OztbKy\r\n        tLGys7GxtLGxs7CwsK2tsKyss66tta6rsKyrsK2usa2usa2ssKuqr6qqr6qor6imsaqorqqpq6mpq6mp\r\n        rqqqRENCISAfJCQiZmRjqqencG5tJyYlKSknYF9eaGdmIyIhNzY0R0ZFoJ2dPz49Hh4dIyMhPTw7QUA+\r\n        WllXcHBvh4SFnpycnpybnJqanJqZnJmZnpybnZqampeXm5mYnJqZnJqanJqZm5qZnJqanZqampiYmZiY\r\n        mpiYmpaXmJWVlpSUl5WVmJWVl5SVlJKSlJKSlZSTlpOTk5CQlJGRkY+PkY6Oj4uMjouLi4mIiYaFh4SE\r\n        iYeHjoyMjoyMiISEWVdWGRkYGxsZKSgnJyYlgn18gHp5f3t7gH18fnl5e3R1fHV1fnd1fnd1////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////sK6vs7Cxt7S0t7a2uLa2uLa2ube2t7W1trS0ube3u7q5vLm5ubW2ure3ubi3\r\n        ure3uba2uri4vru7v7y9vbm5vbe3v7u7wL6+v76+wL6/vbu7uba3u7i4wL6/w8HBw8HAwb2+v7u8wL6+\r\n        xMLCxcTExcPDw8HBxMHBxsPDx8XFyMbGx8TFyMbGycfHycjHycjHysfHy8jIy8nJzcrLzcrKzMrJzMrK\r\n        zMrLzczMzczLzMvLzszNz83NzszMzcvLzMvLzcvMz8zMzsvMz8zMz8zNzszLzs3Mzs3Mzs3MxMLCop+g\r\n        op+g////////////////AABkAABkAABkAABlAABlAABlAABmAABm////////////////////////////\r\n        ////////////////AABrAABrAABsAABsAABsAABtAABtAABtW1qa19TX29nZ2tnY29nZ29nY2tjY2tnZ\r\n        397e19TVwsDAwsDA////////////////////////////////////////////AAB2AAB2AAB2AAB3AAB3\r\n        AAB3AAB4AAB4////////////////////////////////////////////////////////////////AAB9\r\n        AAB9AAB9AAB+AAB+AAB+////////////AAB/AACAAAB+AACAAACAAACAAACAAACBAACB////////////\r\n        ////////////////6ebn6Obm5OLj6+np5+bmpqSkKCdeAACDAACDAACDAACCAACCAACCAACCAACCAACB\r\n        AACBAACB////////////////////////////////////////////////////397d////////////////\r\n        ////3NnY3tzb19TV1NLS1NLS09LR1dLR1tHR1M/P0c7O1NHQ1NHR1NHR0s/Q0c/P2dbW09DQx8PE////\r\n        ////////////////////////////AAB1AAB1AAB0AAB0AABzAABzAABzAAByAAByAABxAABy////////\r\n        ////zsvLy8bGyMLCy8fHy8jIzcjHzcfEzMfEysfFysbFyMTEx8XFyMbGysfHyMXFx8TExcHBxMDAxMHB\r\n        wr+/w8C/xMHAx8HBxsDAxMLBxsPDxcHBwr6/wL6+wL29wb29wb29wLy8wr29wby8wL29vru8vbu6uLa4\r\n        u7i6vbm6u7i4vLq6vby8vry8vbu6vLq5vLq6ure3t7S0trSzuLWzuLW0uLS0trKytbGxtbKytbKys7Gx\r\n        sa6us7Cws7Cwsq6usa6usK6usa+vsa6vsK6usK6usa6urqysrqyssa2urquqraqpraurRUVEPTw8UlFQ\r\n        dXNzq6ioqKWlW1lYHRwbIiEgISEfIB8eIyIhPDs6o6CgQD8/JiYmICAeV1ZVRENBMC8tU1FQWllXoZ+f\r\n        npycnJqam5mZnJmZn5ycnpybnZubn52dn52dnpybnZuanZqanpubnJuam5qZm5qanJqanJiZm5iYmJaW\r\n        l5SVmZWWl5SUlpSUmJaVmZaWlpOTlZOTlZKSk5GQko+OkI2NjImJi4mIi4iIjImIjImIjImIioeHiYWE\r\n        YV5dJCIiGBcWGhkYfXh3g317g318gn19gX9+gHx8gHt7gXt6fnd1////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        sK6vsK6vtLGyt7S0tLGxs7Gxt7W1t7S0trOztrS0ubW2uba2ura3ubW2uba3urm4uri4uLS1trKzuba2\r\n        vLi4u7e3vLi3vrq6v7y9wL2/wL6+vbu7u7i4vbq6v7y9wL6+vru7u7e4vLm6wb/AxcPDxMLBwr+/wb6+\r\n        wr/AxcLDxsTEx8XGysjJysjJycbHycXHysfIysjIysfHycbHycjIy8jJzMjIy8jIy8jJzsvMzcvLy8nJ\r\n        zcrMzsvMzsvNzcvMzszLzs3Mz83NzszMzszMz8zN0M3N0M/Pz87Nzs3MysjHt7S0oJ6e////////////\r\n        ////AABjAABjAABkAABkAABkAABlAABlAABmAABm////////////////////////////////////////\r\n        u7i4BARsAABrAABrAABsAABsAABtAABtAwNuWFeZyMbQ3Nra3Nna2tfY2dfX29ra393c3drZxMLCxMLC\r\n        ////////////////////////////////////////////////AAB2AAB2AAB2AAB3AAB3AAB3AAB3////\r\n        ////////////////////////////////////////////////////////////AAB9AAB9AAB9AAB9AAB9\r\n        AAB9////////////////////AAB+AACAAACAAACAAACAAACAAACA////////////////////////////\r\n        ////////////6+np5+bmpqSkt7W6AwN2AACDAACDAACDAACDAACCAACCAACCAACCAACCAACBAACB////\r\n        ////////////////////////////////////////////////////////////////////////3tzb3Nna\r\n        2dXW1dHR09DP09DP1NDQ0s/Q1dPT1dLR1dLS1NHR0s/Q////////////////////////////////////\r\n        AAB2AAB2AAB2AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABy////////19XU19XUzMrK\r\n        zMnJzMjJzcjHzcfGy8bGysfHycjHyMXFyMXFycbGyMXFx8TEycXFycPDw7+/wr6/xMLBxMHBxMHBxcHB\r\n        x8PDx8TDx8PDxcHBxMHBw8DAwr+/xL+/xL++wb6+wr6+w7++wb6+f32eUE6HWliMlJGnvru7v7u7vbu7\r\n        vbu7vbu6vru7vry7vry7vLq5uba2uba2uLW1t7OzubOwvbOvubKxtbKztbOztLGxtLGwtbKytbOzs7Gy\r\n        tLCxsa6ur6yssa6us7CvtLCxs7GxsrCwsa6usa6usK2trqqrrqysa2ppNDMyU1FQf319rqurq6ioqKWl\r\n        i4mJhIKBhIOCGRkZHh0cPT07pqOjVFNSOjk4Li0scnBvTEpJISAfNDMyV1VVoqCfoZ+fn5ycn5ycnp2c\r\n        n52cnpycnpycnpycnpubn5ubnpycn5ycn5ubnpubnZqZm5iZmZaWm5mZnp2dnJmamJWVmZaWmJWVmJWV\r\n        mJaVmJWVmJWWlpSTk5GQkY6Nj4yLjoyLj4yLjYmJjImKjYqKioaFhoGChYGCh4ODiIOChYB/bmtqXFlY\r\n        iISDhoB/hn9/hH9+gnx8gXx8gn19g359g359////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////sK2tsK2ts7Cxsq+w\r\n        sa6vsa+vsrCvsK2tsq+wuLW2ure4ure4uLW2uri4vLu7vLq7ure4uLW1uba2uri5uba2ube2urm4vLq6\r\n        u7m6vbq7vru7v728wcDAxMLCw8LCwcDAvry8u7i5vbu7wr+/w8HBwsDAwb6+wsHAxMPExsPExcLDxcTE\r\n        yMbGx8TFxsPDx8XFyMXGx8XGx8TExsPDxMLCxcPDyMTFyMbGzMnKz83NzsvMy8jJy8nKy8rKzcvLzMrL\r\n        zcrLzszMz83Nz8zMzcvLzszM0s/Q09LSz87OzcrKzMrKw8HBoJ6eoJ6e////////////AABjAABjAABj\r\n        AABjAABkAABkAABlAABlAABl////////////////////////////////////vr29u7i4UE+NAABqAABr\r\n        AABrAABsAABsAABsAABtAABtMjKGz83U3tvc2tfX1tTU2tjY3tzc2tfXxMHBxMHB////////////////\r\n        ////////////////////////////////AAB1AAB1AAB2AAB2AAB2AAB3AAB3////////////////////\r\n        ////////////////////////////////////////////AAB8AAB8AAB9AAB9AAB9////////////////\r\n        ////////////////AACAAACAAACAAACAAACA////////////////////////////////////////////\r\n        ////////t7W6AwN2AACDAACDAACDAACDAACDAACCAACCAACCAACCAACCAACC////////////////////\r\n        ////////////////////////////////////////////////////////3tzb3Nna3tra3NjY2dbW2NXU\r\n        19TU19XV2tfX09DQ1dLS////////////////////////////////AAB4AAB4AAB3AAB2AAB2AAB2AAB1\r\n        AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAAByAAByAAByAABy////19TU19TU0M7OzsvK0MzJzsrIysfI\r\n        ysfIzMrKzcvLzMnIysfHycfHyMXFx8XFycbFycTExsLCxcLCxsPDxcLCxMLBw8DAxMHAxcLBxMHAxcLB\r\n        xsLCxcDAxMC/xcHAxcHAwb6+wL29wL29uba5QUCBAABjAABibGqVu7i6wL29v7y8vbm5vLi4vLq6vbq6\r\n        vLq5vLq7vLm6vLi4ure3ubW1u7SyvrKuvbSyuLW1trW1trOztbKytbOztbOzt7KxtrCws7CwsK+vsa+v\r\n        tbGyt7KytrO0tLGys66usayssa2usK6usK6vs7CwqKWld3R0npubr62trKmpqqamqqenrKmpq6mpoJ6e\r\n        cW9vaWdnpqOjiIaFJSUjIyIgWFVVODc2IyIhMjEwYmBfoqCfoJ2doZ6eo6CfpKKhoqGgop+foZ+foJ6e\r\n        npubn5ydoZ6foZ+en52cn52cn5ybnZmYnJmYnJubnpubmpeXmZeWmZeWmpeXmZaWl5WVmJaWl5WVlZOS\r\n        ko+PjoyLi4mJjIqKjoyLjouKjYiIjYmJjIiHiYODh4GBioaFjImIioWEhX9+hX9/h4KCiIODhH9/g359\r\n        h39+iIGBh4GCg39/g39/////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////rauqrauqsq+vs7Gys7Kysa+vrqysr62t\r\n        s7CxtrW1t7W1tbSztbOzt7a1urm4u7i5vLm5vLu6vby8vbu9ura4ube2urm5u7q6ubi4ube3vLq6wL6+\r\n        xMHCxMLDwsHAv72+v7y9v728wL29wL6+v729v769wL2+xMHBxcXExcPExcHDxMHCxMLDxMHBw8HAxcPC\r\n        xsTExMHCxMLDx8bGx8bFxsTEx8XGycbHy8jJzczMzMrLy8nJycjHycfHy8rJzMvLy8nKy8nKzszMzszM\r\n        zMrKzsrLz8zN0c7P0M3OzcrLzcrLyMfGtbOzo6Cg////////////AABiAABiAABiAABjAABjAABkAABk\r\n        AABkAABk////////////////////////t7S1v7y8yMbFvr29y8nJw8HGXl2XAgJrAABrAABrAABrAABs\r\n        AABsAABtAQFtOjmJuLbH2dbW19TV2NfX2tjY2tjYzcrKzcrK////////////////////////////////\r\n        ////////////////AAB1AAB1AAB1AAB2AAB2AAB2AAB3AAB3////////////////////////////////\r\n        ////////////////////////AAB8AAB8AAB8AAB8AAB8AAB8////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AACDAACDAACDAACDAACDAACDAACDAACCAACCAACCAACCAACC////////////////////////////////\r\n        ////////////////////////////////////////////////3tra3NjY2dbW2tbX19TU19XV2tfX09DQ\r\n        ////////////////////////////////////AAB4AAB4AAB3AAB3AAB3AAB2AAB2AAB2AAB1AAB1AAB1\r\n        AAB0AAB0AAB0AABzAABzAABzAAByAAByAABy////19TUzsvLzsnI0c3Jz8vKysjJysfIzsrJz8zLzsrK\r\n        zMvKzMnIzMfIzMjJzMnJy8fIysfIycbGxsLCxcPDxsTExcLCxMHBxcLCxsPDxsPCxsPCxsHBxcDAxcHA\r\n        w8DAwb+/wb+/wb6+sa+2OTd+AABjAgJkUlGIvLq7vry8wL69wb68v7y8vbm5u7e3u7i4vLq7vLq6u7i4\r\n        u7i5vLm6vLm4vLW0vLOyurW1trW1t7W1t7S0trS0t7Szt7GwtrGxtrOztrOztrOzuLW1uLW0trOztbKz\r\n        s6+vtK+vtLCws7GysbCwsrCvsrCwsa6usq6tsa6tsK2srKmpqqenq6ioq6ioq6qprKyrrKmpqKSkpaKi\r\n        dXNzLi4tIB8eHh4eHx8eISAfgn9+o6CgoZ6foqCfo6Cfo6Cfo6GgpaKipaGhoJ2doJ2doqCgpKKjoqCg\r\n        n52coJ6doJ+fn52dn5ycoJ2dnJqam5mYnJmZm5mZmZaXlpOTlpSUmZaWl5SUlZKSkpCQkI+Nj42MjIiI\r\n        jIqKj42NkIyLj4uKjouKjIiHjIiHjIiHiISEiIKCi4WEiYSEhoGBhYCAg359hoB/jIaFjoqJioSEg39/\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////q6mpq6mpsK+utrS0tLKysa6vsa+wtLOztrW1tbOzs7Cwsa6u\r\n        sq+vtLGxtLGxt7W1uri4vLq6vLq7vLm6uri4uLW2uri4u7m6uri4uba2ubi3u7q6vbq7v72+vru8vLq6\r\n        vbq6v728vry8vry8vry9v769wL6/v7y9v76+wb+/w8DBxMHBw8HBw8LCwr/Aw8HBxcPDxcPCxMHCxcPD\r\n        yMfHy8nKysjIyMXGx8XFyMbFyMXGx8TFycbGysnIy8nJy8nJysjIysjIzMnJzMrKy8jIrqy6gH6gdHOb\r\n        srG8zMvLzcvLzszLvry8o6Cgvbq6lZOS////AQFdAABhAABiAABiAABjAABjAABjAABkAABk////////\r\n        ////////////v729t7S1v7y8yMbF0M/O09HR1NHQ1M/OWViVAABqAABqAABrAABrAABsAABsAABsAABt\r\n        MTCEvLrI2NbW2dfX2tjY2dbWwb+/wb+/////////////////////////////////////////////////\r\n        AAB0AAB0AAB1AAB1AAB1AAB2AAB2AQF2////////////////////////////////////////////////\r\n        ////////AAB7AAB7AAB7AAB8AAB8AAB8////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AACDAACDAACD\r\n        AACDAACDAACDAACDAACCAACCAACCAACCAACC////////////////////////////////////////////\r\n        ////////////////////////////////////////////2tbX////////////////////////////////\r\n        ////////////////////AAB4AAB4AAB4AAB3AAB3AAB3AAB2AAB2AAB2AAB1AAB1AAB1AAB1AAB0AAB0\r\n        AAB0AABzAABzAAByAAByAAByxsTJzsrKzsrJz8zLzsrLzcrKzMnIz8jH0cnIzcrJzsvLz8rI0MrIz8vL\r\n        zsvLzMrKzMnJy8fHx8XEyMbFysfHycfGyMXFx8XEyMbFyMXEx8TDx8PCxcHBxcLCxcLCxsPDxcLBw8C/\r\n        w8DANDN8AABkAABjVlWLwL6+wL6+wL69wcC+wb++wb28vrq6vbq6vLq6u7m5vLq5vbu7vru7vLq6u7m5\r\n        u7e2ure2uLa2t7W1uri4u7i4ure3uLa2uLe3uba2uLW0ubW1uba2t7W1trOzt7O0trOztrS0t7Oztq+u\r\n        tK+tsa+vs7Cwsq6usq6tsq6usa2trqysrKmprKipq6eoqqenq6mprKqpq6ioqaamqKWlnpycbmxsSEZF\r\n        QD89d3V1pKKhpKKipaOio6GgoJ2dn5ycoJ6eo6GhoqCfoJ2doJ6eoqCfop+foqCgoqCgoZ6enpubn5yc\r\n        oJ6eoJ2dnpycnZqanpycnpubm5iYlpSTlpOTlpOTlZOSmJWVlJGSk5GQkpCPj4uMjouMkY+PkY+OkY6N\r\n        jouKjouKkIyLkIuLioSEi4WEkY2Lj4uKiYWEiYOCjISDjIWEioaGjoqJioSE////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////q6mpr62tsa+vsa2ssa2ss7CwtLOztbW0tLKysa2usKytsa6ts7Cws7Cxs7Gx\r\n        trOztrO0trO0t7Szube2uba3ura4vLm6u7m5ure3uLW1t7W0t7W1u7i4vbq7vLu6vbu7vbq7vbu7vru7\r\n        v7y9wL6/wL+/vbu7vbq7v72+wL+/wsC/wcC/w8HBxMHCw8HCw8LDxcXDxcLCwr7AxMHCx8XFx8TFxsTE\r\n        xcPDxcLCxcLDxcLDyMXGy8rKycbHycbGysjHysjIysnJy8jJvbvAJCNuEBBlAABcMjF3enmeubi/ycfI\r\n        ysjIyMXFvbq6lZOSkI2RAQFdAABhAABhAABiAABiAABiAABjAABjAABj////////trO0wb++yMbFv729\r\n        ycbG0M3N0tDQ09HQ09DP09DP0s7O0c7OUE+RAABqAABqAABrAABrAABrAABsAABsAABtHh17n5262NfW\r\n        29nZ2NbWtbOztbOz////////////////////////////////////////////////////AAB0AAB0AAB1\r\n        AAB1AAB1AAB2AQF2Dw93////////////////////////////////////////////////////AAB6AAB7\r\n        AAB7AAB7AAB8AAB8////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AACDAACDAACDAACDAACDAACDAACD\r\n        AACDAACDAACCAACCAACC////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAB4AAB4AAB4AAB4AAB4AAB3AAB3AAB3AAB2AAB2AAB2AAB1AAB1AAB0AAB0AAB0AAB0AABzAABz\r\n        AABzAAByUlGWz8zMz83N0c7O0c3N0s7K0s3K0MnIz8jHzsvKzcrKzcjHzcnHzsrJz8zLzsvLzcrLy8jJ\r\n        ycbGysjHy8jHzMnJzMnJyMbFx8TDycbGycfGyMXFx8TDx8TDysbFycbEx8PCw7+/u7i8GxpxAABkAABk\r\n        Pz6Cvbq8xL/Awr6/wL6+wsDAxMHAw8C/wL29v7y8vry7v7y8v729vry7vbq6vLq6vLu7u7m5vLm5u7m5\r\n        vLq6vbu7vLq6vLu7u7m5ube2t7W1uba2uba3t7W2t7W1t7W1t7S0t7a2t7OyuK+st66stbKztbKytbGx\r\n        s7Cws7Cvsa6urqysrKqqrKiorqiosKmorqqqrKurrKqprKiprKiprKmoqqemqaamq6qpq6mopaOjpaSj\r\n        p6WjpKKhoZ6en52eoJ+foZ+foqCfoaCfoqCgoJ2doJycoZ+fpKGhoJycopuZo5yaoJ2doJ6eoJ2dnpuc\r\n        nZuanZqanJmZnZubmZeXlJGSk5GRk5KSkY2Oko6Pk5CRk5CQlJGQk5CQkY+PkY+PkY6OkIyNkouLkouL\r\n        k42MkYyLkIqJkImJkYuKkYuIjoeGjIWEioaG////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////rKqqrKqqrqysr6yssa2ssKuqsKyssK2tsK6usK6ur62tsa6us7Gxs7Gxs7CwtLGxs7KysrCws7Cw\r\n        tbOytrS0uLW1u7m5u7q5uri5u7e4ube3ube3ube3u7m5vbu7vby8vbu7vbu7v728vry8v7y9wL2+v729\r\n        wL2+wb/AwcHBwb+/wb+/wr+/xMLCxMLCwcHAxMPCxcPExMLDwsDBwsDAwsC/xMHBxcLCxMLDxsTEyMbG\r\n        yMXGyMbGxsXFyMXGysfHyMfHycjIysfIg4GhAABbAABbAABcAABcDg5kPDt9eHecrqu5zsvLycfHtbKy\r\n        kI2RHh1mAABgAABhAABhAABhAABiAABiAABjAABjAABjf32etrO0wb++yMbFzMrK0c/P09DQ0s/O0M3N\r\n        0M7O0s/O0s7N0M3Nwb/HVlaTBARsAABqAABqAABrAABrAABsAABsAABsHh57oqC72dfY0c/PtbOz////\r\n        ////////////////////////////////////////////////////AAB0AAB0AAB0AAB0AAB1AAB1AAB1\r\n        Dw93aWiT////////////////////////////////////////////AAB6AAB6AAB6AAB7AAB7AAB7AAB7\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////AACDAACDAACDAACDAACDAACDAACDAACDAACDAACC\r\n        AACCAACC////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAB5AAB5AAB5\r\n        AAB4AAB4AAB4AAB3AAB3AAB3AAB2AAB2AAB2AAB1////////AAB0AAB0AAB0AAB0AABzAABzAwNzenio\r\n        0c7O0s/P1dHO2NPL2NPM0s7MzsvL0M3MzsvLzMjIy8fHy8jIzcrJ0MzLz8zLzcnJy8bGysfHycbGy8jI\r\n        zcrKy8fIysbGzMnIysjHyMbFyMXFy8fGzMbEy8XDyMPCx8LBqKazHx5zAABlAABlMjJ8v7u9xMDBxMHC\r\n        w8DBxMHBxcLCxMHAwr+/wb6/wr6/wb2+wL+/wL+/v7y8vry7vru8vru8vru8vru7u7m4u7i4vLm6vLm5\r\n        u7m5ure3uba3uba2ube3uri4uri4uLa2trOztrO0t7S0t7Szt7S0t7S2uLW1trOztLGxs6+wsa+vsK6t\r\n        raurraqqsauqta2rsa2tr66urq2sr6ysrqurrKqpqqenqaenr66vr62tqKalpaOiqKWkpqOjpKGho6Gh\r\n        pKOio6GhpKGhpKGhop+foZ6eoZ6eop+foZ+fo56dqqGdqZ+bopyboZ+gop+goJ2dnJqZmpeWnZuan52d\r\n        mpeXlZGSlZKSkI+Pj4yMk5COk5CQlJGRlpSUlpOTko+PkY6Ok5CPlJCQk42MkoyLkYyLj4qJjoeHk4uK\r\n        lo+Oko2LjoeG////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////rKqqrKqq\r\n        rqytrKqrrqurr6qqr6mor6ypr66trqytsa6usq+vsq+vs7Kys7Kxs7Cws7CwtLOztLOys7KxtLKytrSz\r\n        t7W1uLW2ure4u7m5urm4uri4u7i4vbq7vbu7vbu7vbu7vby7vbu7vbq6v7y8v7y9wb6+wsHBw8LCw8HB\r\n        wr+/wL6+wb++wb+/wL++wsHBxcPExcPDw8HBwb+/wb++w8DAxcLCxcPExsTFyMXGxsTExcTDxsXFxsTE\r\n        xsPDxcPDxsTFycbHOzp6AABaAABaAABbAABbAABcAABcAABdIB9ubGqVq6m4ycbGxMHBPj18AABgAABg\r\n        AABgAABhAABhAABiAABiAABiAABjf32ex8TEzcvKzcrKz8zM0c7O0M3N0c7N0c/O0c7O0s/P0c/Pz83N\r\n        0M7N0c/OTUyOAABqAABqAABqAABrAABrAABrAABsAABsDQ1zlpW1vbq6vbq6////////////////////\r\n        ////////////////////////////////////AABzAABzAAB0AAB0AAB0AAB1AAB1AAB1aWiT0s/Qwb6/\r\n        pqOj////////////////////////////////AAB6AAB6AAB6AAB6AAB6AAB6AAB6////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////AACCAACCAACDAACDAACDAACDAACDAACDAACDAACDAACCAACD////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAB5AAB5AAB5AAB5AAB4AAB4AAB4\r\n        AAB4AAB3AAB3AAB3AAB2AAB2////////////AAB0AAB0AAB0AAB0AABzAABzDAx5m5m30s3O1dHO2NbO\r\n        2djO2NPN0s7Mz8zMzsvLzsrKzcvJzMrJzcnJz8vK0MvKzsnIzcjHzMjHysfHy8nJzMnIzMjJzMnKzcrJ\r\n        zMjHysXEy8XEzsfGzsfFzcfEzcbEzMXDtK+5KSh5AABmAABlLy57vbq/xsPExsTExMLDxMLCxMLCw8HB\r\n        wsDAwb+/wb6+wb6+wb/AwsHBw8C/wb6+v728vru8vru8vLm5u7i4vLm5vbq6u7m5vLm6vry8vLq5ure3\r\n        ure4u7m6u7m5uLa2t7S0t7S1uLa3uLe4uLe4uLW2uLW2trSztLGxs7GxsrCwsrCvsa6tsK2ssK6tsK6u\r\n        sa6vsK6usK2tr6ysr6ysrqqrq6moqqioraqrrqurqaenpqWkp6WkqKWlp6SkqKamqaenpKKipKGhpaKi\r\n        pKGgo6Cfo6Ggo6GgoqCgpaCerKKfqp+copycoJ6eoZ+eoJ6doJ2dnpubnZubmpeXlpOTmJWVmJWVl5WV\r\n        lpWVmJaVlpKSlZKSlpSTl5STlJGQko6OlZCPk4+OlJKRlJGQkYyMkIuMlZCPlI6NkI2Lko2L////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////qKSlqKSlqqeoq6mpraurrqus\r\n        squptrCpsq6rrKurraurr6ussq6usq+vsq+vsa+vtbOzt7a2t7a2trS0t7S1t7W2trS1tbKytLGytrS0\r\n        t7S1uLW2uri5u7i5vLi5vLm6u7q6uri4ube4uri5vbm6vry9v76+wL6/wL2+wL29wL69wL6+wL6+wb/A\r\n        w8DCwr/Bwb6+v728wb6+wb+/wr+/w8HBw8HBxcPDxcPExMLDw8HBw8DBxMLCxMLCxMLCxsPEx8TEvbq/\r\n        ERFiAABZAABaAABaAABbAABbAABcAABcAABcAABdAABdQUCAk5GsYF+RAABfAABfAABgAABgAABhAABh\r\n        AABhAABiAABiWFeOx8XHzMvKzMnJzcvKzcvLy8jJzsvL0c7O0M3N0c7O0c7Oz83M0M3M0s/Pw8LIOjqF\r\n        AABpAABqAABqAABqAABrAABrAABsAABsFhZ3gH6igH6i////////////////////////////////////\r\n        ////////////////////AABzAABzAABzAABzAAB0AAB0AAB0AAB1QD+R0s/Qwb6/pqOj09HQwb+/pqSj\r\n        ////////////////////AAB5AAB5AAB5AAB6AAB6AAB6////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////AACCAACCAACDAACDAACDAACDAACDAACDAACDAACDAACDAACD////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAB6AAB6AAB6AAB5AAB5AAB5AAB4AAB4AAB4AAB3AAB3\r\n        AAB3AAB3////////////////AAB0AAB1AAB0AAB0AAB0AABzExN8wLzH1dDN1tHO2dbO2tTN1M3MzsvM\r\n        zcrKz8zL0M7N0M3Mz8vLzsvLz8vLz8vKzcrJzMnIy8nJzMnJzcnJy8jIysjIy8fIzcfG0MbDzcXDzcfF\r\n        z8jF0MjGz8jGzcjFwr7CERFvAABmAABmFRVvray5xsPExsPExcTEw8HBxMHBxMHCw8HBwsHAwsDAw8DB\r\n        w8DBw8DAwr+/wr+/wb6+v7y8vru7vry8vru7v7u8vrq7vbu7vry8v7y9vLu7uri3uba1uba2vbq5vLm5\r\n        u7m5ube3t7W1uLa2ube3uba3uLS0trOytLGxtLGytLGxs7Cwsq+vsq+vs7GxsrCxsq+vsa6ur62trqys\r\n        r6ysr62tr6urraqqrKmpq6ioqainqKemqaemqqemqqioq6iprKmpqKWlp6Wkp6WkpqOjpaOjpqOjpaKi\r\n        paKipqOipqGgpZ+fop+eop+foZ6doJ6eoZ6eoJydnJmZmZaWmZeXmZeYm5mZnJmampmYmZeWmJaVmJWV\r\n        mJWUl5KSmJKSl5GRl5CQk4+PlZKRlZKSk5GRlpKTl5SUlJORkI2L////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////qKSlqqeoqqiorKurq6mqrqqosaunr6uprKur\r\n        rKqrramqrqurr6yssK6usrCxs7GxtrSzt7W2t7W2trO0trS1t7W2tbKytLKxtbOztrO0trS0ube3uba3\r\n        ure4vLq7u7q6ube4uLW3u7m6vLm6vbu7vr29vry9vru9vLq7vbu7v7y9wL2+wb+/wb/Awr+/v729vry8\r\n        v769wsDAw8DBwsDBwb+/w8LBxcPDwr/Awr+/w8DBxcLCxcPDxMLCxcLCxsPDlpSpDw9gAABZAABZAABa\r\n        AABaAABaAABbAABbAABcAABcAABdAABdDg5kExNoAABeAABfAABfAABgAABgAABgAABhAABhAABiLi55\r\n        y8nJzszNzszLzcrJzMnIy8jJzcvLz83Mz8vLz8vM0M3NzszMzsvM0c7O0dDPtrTBPDuGAQFpAABqAABq\r\n        AABqAABrAABrAABrAABsBwdvBwdv////////////////////////////////////////////////////\r\n        ////////AABzAABzAABzAABzAAB0AAB0AAB0CAh5xcLS3Nna2NbV09HQwb+/pqSjycbGsq+woZ+f////\r\n        ////AAB4AAB5AAB5AAB5AAB6AAB6////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////AACC\r\n        AACCAACCAACCAACDAACDAACDAACDAACDAACDAACDAACDAACD////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAB7AAB6AAB6AAB6AAB5AAB5AAB5AAB4AAB4AAB4AAB4AAB3////////////\r\n        ////////trSzAAB1AAB1AAB0AAB0AAB0AABzQ0KQ08/P0s3P2NHP2NLO0c3Nz83O0c7O0c/O08/P087P\r\n        0MzMzsvLzsvLz8vLzsrKzcvKz83M0MzMzcnKzMnJzcvLzcnKzcfGzsjFy8fFzMfGz8nHz8nHzcfGy8jG\r\n        qqe4DQ1tAABnAABmFBNvuLS9yMTFyMXFyMbGxcPDxMLCxMHCxMLCxMPDxMLCxMHCxcLDxMHCwr/Awr+/\r\n        wr6+wL29wL2+w8HBwsDAwb2+wb6+v729vru7vbq6vbu7u7q5uLW1t7O0u7i4vbq6vLq6vLq5ure3ure3\r\n        ube3uLW2uLW1t7SztLGxs7CxtbKytLGws7CvtLGxtbKytbKytLGxtLCxsq+wsa6vsK2tsK2tsa6usa+v\r\n        sa6vrqysrKqpq6moqqenq6iorKmpq6ioq6ioq6moqainqKamp6SkqaanqqenpqOjpaChpaKipqWkpKKi\r\n        pKGhpaKipaGioZ6en5ycnZqam5iYm5mYnZubnpudnJqampiXmpmYmZeXmZeXm5iXmZaWl5OTl5GQmJKR\r\n        mJOSl5KRlpCQkY2OlJKSm5eXmpaWlJOR////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////qqeoqqioqaeop6WlqKSkqqenqaioqqioqqeorKqprayrrayr\r\n        sa6us7CxsbCwsq+vs7Cxs7Gxs7Gxs7KytbSzs7Gwsa+us7GxtrO0trW0trS0t7S1t7S1uba3u7m5uri4\r\n        uri5vLm6vLq6u7m6vLm7vbu8vbu7vLq7vLu7v7y9vbu8vbu7vry8vry8vry9vr29wL6+wL6/wb/Awb6/\r\n        wb+/wcC/wb+/wsDAw8HCxsPExsTExsXFx8TExMLCxMLCYF+MAQFYAABYAABZAABZAABZAABaAABaAABb\r\n        AABbAABcAABcAABcAABdAABdAABeAABeAABeAABfAABfAABgAABgAABhAABhBgVkrqy6zMjJzcrKzMnI\r\n        ycbGysjJzcvLz8vLzsvLz8zM0c7Pz87OzszM0M7N0c7O0c7PyMbMLi6AAABpAABpAABqAABqAABqAABr\r\n        AABrAABsAABr////////////////////////////////////////////////////////////CAh1AABy\r\n        AAByAABzAABzAABzAAB0AAB0aGek3NnZ393e4d/g3t3d2djXycbGsq+woZ+fo6K7JSWEAAB4AAB4AAB5\r\n        AAB5AAB5AAB5////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////AACCAACCAACCAACC\r\n        AACDAACDAACDAACDAACDAACDAACDAACD////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AAB7AAB7AAB7AAB6AAB6AAB6AAB5AAB5AAB5AAB5AAB4AAB4AAB4////////////19PU29nZtrSziomx\r\n        CAh4AAB1AAB1AAB0AAB0AgJ1aGeh09DR1tLQ08/O0M3O09DP09DQ0s/O1NDQ0s/Q0c3N0c7N0M3NzszM\r\n        z83N0c/P1NDR08/Qz8zLzsvKzsvLzMnKy8fHysfHy8jHzsrIzsrJy8jIycXFycXFrKm5IyN5AABnAABn\r\n        Dg5unpuxysbGysfIycbHyMXFxsTDx8TExsTExcPExMPDxcLDxMLDxMLCxMLCxMLBw8DAwr+/wb+/wcDA\r\n        w8HBwr+/wr6/wb6+v7u7v7u7vbu7vbu7vLm5ure3ube2uLa1ura3vLm5vLq6u7i5u7e4uba2t7S0tbOz\r\n        s6+wtLGxtrOytLGxsq+wtbKzt7S0tbKytbOytLKytLKys7Gws7Cwsa6usK6usa+wsq+vr6urramprKqp\r\n        qqinqqenrKqpq6ioq6morKqqq6moqKamqKamqaamqqenqaampqOjp6KjqaSkp6Sjp6WkqaampaOjoqCf\r\n        oJ6dnZuam5mYnJmZnZubnZubnJmZnZqanZycmpeYmpeXmpeXmJSUlpKRl5KRmJOTmpaVm5aWmZSUkI2O\r\n        joyNlZKRk5CPk5CP////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////qaeop6WlpaKkp6Wmp6WmqKWmqqamqqinq6qpq6qqrqyssq+wsrCxsa+w\r\n        sa6usa6usa+vsa+vsbCvsK6ur6yssq+vtLKytLKytbKztbOztbGys7CxtbO0t7a3uri5vLm6vLq6u7q6\r\n        u7m6vLm6vLq6vb29vr6+vry9vbu8vLm6u7m5vLq6v76+wcDAwL+/wL7Awb7AwsDBwcDAwL2+v729wb+/\r\n        wsHBxMHCxMLDxMHBxcLCxMHBu7m9RUR8AgJYAABXAABYAABYAABZAABZAABaAABaAABaAABbAABbAABc\r\n        AABcAABdAABdAABdAABeAABeAABfAABfAABgAgJhBwdke3mgtLK+zMnIxsPDx8TEyMfIzMvLzszMzMnJ\r\n        y8jIzcrKz8zMz87Nzs3MzszM0M3N0s/O0s/PvrvFMzOBAABpAABpAABqAABqAABqAABrAABrAABrAABr\r\n        ////////////////////////////////////////////////////////CAh1AAByAAByAAByAABzAABz\r\n        AABzAAB0GxuA1dPW3drb3Nra3dvb4N7f3Nna1NPT09PSo6K7JSWEAAB4AAB4AAB4AAB4AAB5AAB5////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////AACCAACCAACCAACCAACCAACCAACDAACD\r\n        AACDAACDAACDAACDAACD////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////AAB7AAB7AAB7AAB7\r\n        AAB6AAB6AAB6AAB6AAB5AAB5AAB5AAB4////////////////19PU29nZzcnJ08/PcnCpAwN3AAB1AAB1\r\n        AAB0AAB0AAB0lpS11NLR0s/P0s/P1NDP0c7O0c3N0c/O09HQ08/O087O0c7O0M3N0c/P09HR09DR08/P\r\n        0s/O0c3M0MzMzsvLy8nJycfHzMnJzcrKzcvLysjIyMXGyMXFvLnAERFwAABoAABoAABniYeoycbGyMXF\r\n        ycbFyMXFx8XFx8TFyMbHx8XGxcPDxcPDw8HBw8HBxMPDxcPDw8HBxMHBwb+/v7y8wL2+wb69wL29wL6+\r\n        wb29wb29v729vry9v7y8vbq7u7m5uri3uba2ura3u7i5vLm5u7e3ura2ubW2uLa2trOztbKytbKys7Cw\r\n        tLGxt7S0t7S0trO0trS0tbSztLKxtbOytbKytLCxsa6vsa6usa+vr6ytr6ysrqurrKmpq6ipq6mpqqin\r\n        qaenqqioqaenqqinqqinqaenqKemq6mop6WlqqamrainqaWlqKWlp6WkpKKioZ+foZ6en5ybnpybnpuc\r\n        n5ycnZqZnJmZnZubnJqampiYm5mYm5iYmJWVmJWUmpeXnJmam5eXmpaWmpeYlJKSjIqKlJGQk5CP////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////paKkp6Wmp6WmqqamqqamqKamqaenqaenqaemrKmqr6ussa2us7Cws7CwsrCvr62t\r\n        r62tsK6usq+vs7GwtLCxsq+wtLKztbOztbKztrOztLOztbO0t7W2uLe3ubi4ube4ube4uri4u7m5uri5\r\n        u7m7vLq7vbq7vLm5u7m4vbu8vry+wL6/v72+wL6/wb/Awb/AwL/Awb/AwsDBwb7AwL6+wL6+wb+/wb++\r\n        wL++wb++qKWxNTRzAABWAABXAABXAABYAABYAABZAABZAABZAABaAABaAABbAABbAABcAABcAABcAABd\r\n        AABdAABeAABeAABeAABfBARhQkGCmJavu7nBxsXGxcPDyMfHzczNzMzLysjHycbGyMbGysjIzcrKzcrK\r\n        zcrLzcvLzszL0M3NzszLzMrKrq28JCR6AABpAABpAABpAABqAABqAABqAABrAABrAABr////////////\r\n        ////////////////////////////////////1dLTISGBAABxAABxAAByAAByAAByAABzAABzCwt4oqC9\r\n        2tfX29nZ29nZ3Nra3dvc3dzb3Nvcl5W7ExJ/AAB3AAB3AAB4AAB4AAB4WViU////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AACCAACCAACCAACCAACCAACCAACDAACDAACDAACDAACD\r\n        AACD////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////AAB8AAB8AAB7AAB7AAB7AAB7AAB6AAB6\r\n        AAB6AAB5AAB5LSyJ////////xMLCzMnJ19PU2dfX2NXV19LT1tPTSEeWAAB1AAB1AAB1AAB0AAB0GBh/\r\n        zcrP09DQ08/P09DQ0c/P0c7O0s/P09HQ1NDP0s7N0s7N0c7N0c7O0M7OzszL0c3N08/P0s7N0c3N0MzM\r\n        zsvLzsvLzszNzMrLzMrKzMnJy8nJy8rJq6i4CwtuAABpAABoAgJpgoClyMXGyMXFycbGycbHyMTFx8TF\r\n        yMbHysjIyMbHyMbHx8XFxcHBwsDAw8DBw8DBxMLCxMPDwsDAwL29wb69wb+/wr/Awb+/wb++wb+/wb6/\r\n        wb6/v729v7y8v7y8u7i4u7m5vbq7vbq6vLm5u7i4u7i4u7i4ure3ubW2t7S0trKyt7O0uLW1trSztrS0\r\n        t7W1t7a1trS0trS0t7S0tbKztbOztLKxs7Kxs7KzsrCxsa6tr6ysraqqq6ipq6mpq6mpqqioqqiorKmp\r\n        rKmpqKamqKWlqaamp6Wkp6Wkqqioqaamp6SkpaKhoZ+eoZ6eoZ2dop6en52doaCfo6CgoJ2dnZqbnZub\r\n        mpeXmJaVmpeXmpmYm5qZnJuanJubnZubnJmZnJqZnJubmJeWkpCPl5KSl5KS////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////qqamqqamqKampqWlp6Slqaamraurr6ytraqqrqysr62usa+vsK2urqyrr6ytsK6usq+v\r\n        sa6usa6usrGxtLOztrS0t7W1trOzs7CxtLKztbS0t7W2trS1t7W1ure4uLa2t7O1uLW2uri4ube4urm5\r\n        vLq6vbu8vbq7vbq7vbu7vLu7vby8vbu8v7y9wb/Awb/Av72/v7y9v729v7y9vry8vru8vru8hIKcExNf\r\n        AABWAABWAABXAABXAABXAABYAABYAABZAABZAABaAABaAABaAABbAABbAABcAABcAABdAABdAABdAABe\r\n        AABeAABfCQhjIyJxOTh8aGeUlJSrtbO+ysjJy8jHyMXFyMbFycjHy8nJzcrKzcrLzcrKzcvLzMnIycbH\r\n        yMbGy8nIzcvLraq7ERFwAABoAABpAABpAABqAABqAABqAABrAABrAABr////////////////////////\r\n        ////////////////1dPT1dLTXl6dAABxAABxAABxAAByAAByAAByAABzAABzXl6e1dPV2tjZ2tjX29nZ\r\n        29na2dbW2dXVhYSxAgJ3AAB3AAB3AAB3AAB4AgJ5WViU0c7PysfGsa6u////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AACBAACBAACCAACCAACCAACCAACCAACCAACDAACDAACDAACDAACD////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////AAB8AAB8AAB8AAB8AAB7AAB7AAB7AAB6AAB6AAB6AAB6LSyJ\r\n        x8XEysXFxMLCzMnJ1NHS2tfY2tfX2dbW1tPSw7/JIyKFAAB2AAB1AAB1AAB1AAB0WVib1dHR1NHR1dHR\r\n        1NHR09HR1NLS1NDQ08/O0s/O08/O0s7O0M3O0M3M0MzK0s7N0s/P0s7N0s3M0MzLz8vL0M7O0c/Qz83N\r\n        zszMzszMz83N0M7NvrzFKip+AABpAABpAgJpamiaysjIysjIy8jIy8fIycXGyMbGyMfGycbGysfHysnJ\r\n        ysnJyMXFxcLCxMHCxMHBxMLCxcTDxMLCwr+/w7+/w8DAw8DBwsDAwsHBw8HBw8DAwb+/wb+/wb6+wL29\r\n        wL69wcC/wL69vbq6vbu7vbq6u7m5uri4ure3u7i4ura3ubW2ubW2ube4ube3uLW1uLW2uLa2uba2uba2\r\n        uLa2t7S0t7W0t7W1t7W2uLa3tbKzs7CvsK2sraqqraussK2trqyrq6mprKqqraqqq6moqaamqKWlqKWl\r\n        p6WkpqSjpqOjpaOipaOjpKGhoJ6eo6GhpKCho5+foJ6doaCfo6Khop+foZ2dn52dnpubnJmZnJuanJqZ\r\n        nJqanZubnZuanZuanZqaoJ6enpuamJaWk5GSlpKSlpKS////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////pqWlp6SlqaamsK6vsK6urKqqqqmqrKqrrqytr6ytr6usramqraqrrqusrqusrqursK6usbCv\r\n        s7Kxs7Gys7Cxs7Cws7GxtbKztbOzt7W1uLa2uLW2trS0uLS2ube3uLa2ube4u7q7vbu9vLm6urm4vLq5\r\n        u7m5urm5u7m5vLq7vLm6vbq7vLu8vby8vry8vru8vLm6vLq6v7y8vbq8dnWVBARXAABVAABWAABWAABW\r\n        AABXAABXAABYAABYAABZAABZAABZAABaAABaAABbAABbAABcAABcAABcAABdAABdAABeAABeAABeAABf\r\n        AABfCQllHR1vQT+BYF6RdXOcoZ6zx8TGycfHycfHycfHz83N0c7OzsrLy8fIyMXFxsPDyMXFzcrKzcrL\r\n        lZOvFhZzAABoAABpAABpAABpAABqAABqAABqAABrAABr////////////////////////////////1dPT\r\n        1dPT0M7OhoSuAgJxAABwAABxAABxAABxAAByAAByAAByFRV9zMvS2NbV1tLS2NXW29nZ19TUzcrOSUiV\r\n        AAB2AAB2AAB2AAB3AAB3DAx8gH+v0c7PysfGsa6u1dHSy8jIs7Gx////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////AACBAACBAACBAACCAACCAACCAACCAACCAACDAACDAACDAACDAACD////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////AAB9AAB9AAB8AAB8AAB8AAB7AAB7AAB7AAB7AAB6AAB6R0aYx8XEysXF2dbV2dfW\r\n        2dfX2tjY29fX29nX2dfW2dbWp6TBDw99AAB2AAB1AAB1AAB1AgJ1lpO219XV2NTU1tPS1tTU1tPT1c/P\r\n        1M/O1dLR1dLS1NDS0tDQ1NDO1dHP09DP0c7O09DP1NDO0M3Mz8vL0M7N0s/P0tDP0c/P0tDQ0M3O0s/Q\r\n        0c7SHh55AABqAABpAABpXVyVyMXGy8nKzMrJy8nIysfIy8nJycjHyMTEycXFysfHycfHycbHycbHycfH\r\n        x8XExsPDxMDAwr+/wr/Awr6/wsDAxMHBw8DAwsDAw8DBw8DAwb++wcC/wb+/wb++w8LBw8HAv7y7vbq6\r\n        vLq6vLm5u7m4ure3ure3u7i4vLm4uba2uLW1ube3vbu7vLq6uri4ure2uba2ure3uLa2t7W1t7O0uLa2\r\n        uri4ure3t7Ozs7CwsrCvsK6usa+usK2trauqrKmqrKqqraupq6moq6iprKmpqqioqqemqKakp6SjpqSk\r\n        p6WlpKKio6GhpqWkpaOipKKhpKCgo6ChoqCgpKGgo6Gfop+foJ6fn52dnpucnZubnZqaoJycoJ2dn5yc\r\n        npucm5mZmpeXk5CRkY6PlpGRlpGR////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////sK6vsK6uraurr66uraysrKqqraqrrqusrKmqrKqqrqytrqusr62trqysr62tsrCwtLKzsq+wsa+u\r\n        srCvtLGytbKztrS0tbOztbKyt7W2uLa3t7a2t7W1ube4u7m5ure4ube3ube3urm5uri5ube3u7m5vLq7\r\n        u7q6uri5vLm6u7m5u7i5vLq7u7m5vbq6vry8u7m5TEp9AABUAABVAABVAABVAABWAABWAABXAABXAABX\r\n        AABYAABYAABZAABZAABaAABaAABaAABbAABbAABcAABcAABdAABdAABdAABeAABeAABfAABfAABgAABg\r\n        CAhkAwNjExNrREOEdnSdoqCyxcLCy8rKz87OzMvLy8nKzMrKycbGx8PDysfHzcrKy8jIjIqqDg5vAABo\r\n        AABoAABpAABpAABqAABqAABqAABrAABq////////////////////////////29nZ29nZ1NHRvbvHDQ11\r\n        AABwAABwAABxAABxAABxAAByAAByAABylpW51tPT1NHR1tPU2NbW19XUxcPLHByCAAB1AAB2AAB2AAB2\r\n        AAB3ExN/mZi63dvb29nZ19XV1dHSy8jIs7Gx1tPUycbHsK2t////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////AACBAACB\r\n        AACBAACBAACCAACCAACCAACCAACCAACCAACDAACDAACD////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AAB9AAB9AAB9AAB8AAB8AAB8AAB8AAB7AAB7AAB7AAB6joy12tfV2NXV29jY3NrZ29nY2tfX2dbW2NXV\r\n        2tjX3NnZ3NnZe3mtAAB2AAB2AAB2AAB1AAB1ExN+wr/L2dbW19TU2NXU19TT1tLR19LS2NXV19XV1tTU\r\n        1tPT1dPR1dLR1NHQ08/P1NHR1tLR087N0c3N0tDP0M7N0c7Oz8zMy8jI0M3O0s/Q0c7SDg5wAABqAABq\r\n        AABqR0WKyMTFzMnJzsvLzcrLzMrLzcvLzMrJycXFyMTFysbHysfHysbHysjIycfHyMbFxsPCxcLCxcPD\r\n        xMHCw8DAw8HAxsPDxMHBw7/Aw8DAxMHBw8DAwsC/w8HBw8HBw8DAwL29vru7v7u7vru7vLm5vru6vbq6\r\n        vbu7vLq6vLm5ure3uLa1ura2u7m4vby7vbu6vLm5u7i4ure3ure3uLa1uLO0t7S1ube3ube3t7S0tLGx\r\n        tLKxtbOzsq+vsKysrqurr62tr62trqyrraqprKmprKqqq6ioqaampqOjpqSkqqmoqaempqOjpqOjp6Wk\r\n        paOipqKhpqKjpqSkpaOio6GgoqCfoZ6eoJ2enpubm5iYnZqan52doZ6epKGho5+fnZqamJaXlJOTkY6O\r\n        kY2NlY6OmZSU////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////raur\r\n        rKqqraurqqioq6mprKqqq6mpq6morKqpq6iorKqqrqusrqytsbCxtLKys7GxsK+vr62tsK2us7CxtbKz\r\n        tLKytLKztrS1t7W1uLW2ubW2uLa1t7W1trS0trS0trS0trSzuLa2t7W1uLa1ure4uri4uri4ura2urW2\r\n        uba3uri5ube3u7e4vbq6sa+0REJ4DAxaAABUAABUAABVAABVAABWAABWAABWAABXAABXAABYAABYAABZ\r\n        AABZAABZAABaAABaAABbAABbAABcAABcAABcAABdAABdAABeAABeAABeAABfAABfAABgAABgAABhAgJi\r\n        AwNjGBhuODZ9WliOl5WvysnJycjIysjKzMvLysnKycjHysfHysfHzcrLdHOgAABnAABoAABoAABpAABp\r\n        AABpAABqAABqAABqAABq////////////////////////1NHR19TU1dPS09HQMTCGAABvAABwAABwAABw\r\n        AABxAABxAABxAAByLi6H09DS1NLS19XU2NTV19TUqajAAAB0AAB1AAB1AAB1AAB2AAB2FxeAtLPG29nZ\r\n        29jZ3dvb4d7e4Nzd29fY1tPUycbHsK2t09DRx8XFraur////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////AACBAACBAACBAACBAACB\r\n        AACCAACCAACCAACCAACCAACDAACDAACD////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////AAB9AAB9AAB9AAB9\r\n        AAB9AAB8AAB8AAB8AAB7AAB7DQ2By8nR3tva3drZ2tfW2tfW2tbW2dXV2dbV2dbW2tbX3NnZ29rZ2NXX\r\n        NzaQAAB2AAB2AAB2AAB1AAB1WVec2NXV1tPT1tLS2NTS2dTS2tXT2tbU2NXV2NXV2dbV19TU19PS1tLS\r\n        1NDR1NDQ1tHQ19DO1dDQ0c/OzcrKy8fH0c3Ny8jI////////////Dg5wAABrAABqAABqQD+J09HQ09HR\r\n        0M3OzcrKzsrLzszMzszMzMnJysjJy8jIy8jHysjIysfHycbHyMXGx8XFx8XFyMXFxsPDxsPCx8TEx8TF\r\n        x8TFxcPDxMHBwr+/w8DBw8DAwb6+wr6+wL29wL69wL+/wsDAwb6+v7y9wL6+wr6/wL29vru8vbq6vbq5\r\n        ure3ubW1ure3vLq5vbq6vLm5u7i4u7m5vLu7u7m5ura2ura4uba3uri5uLa2trOztbOztbOztLGwsq+v\r\n        sq+vs7GxtrSztLGxr6ysrKmoqqenqqenp6WlpKKjpqSkqKamqKWlp6WkqKWlpqKjpaKio6CgpKGhpKGh\r\n        op+foZ6eoZ2foZ6foJ2doZ+foZ6eop+foZ+eoJ+eoZ+eoJ6em5qamJiZk5GSjoyMjYqKj4uLmZSUmZSU\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////rKqqp6Skqqenqqen\r\n        q6iorKqqraurrampq6ioqqmprKqqraysr62tsK2tsK2tr62ur6ytsK6usa+wsq+wsa+vtLGytLKztbO0\r\n        t7W1t7S0trOztbOztbS0tbW0tbO0tLKztrOzt7S0t7S0uba2uLa2uLW2t7O0trO0ube3ure5ube4uLa2\r\n        ura2t7S1mJambGuPHBxiBARWAgJVAABVAABVAABVAABWAABWAABXAABXAABYAABYAABYAABZAABZAABa\r\n        AABaAABaAABbAABbAABcAABcAABdAABdAABdAABeAABeAABfAABfAABgAABgAABgAABhAABhAABiAABi\r\n        AABiHh5yVlSOdXSfpqW3tbS+t7W+yMXFyMbFysfIyMXJYWCWAABnAABoAABoAABoAABpAABpAABqAABq\r\n        AABqAABq////////////////vr291NHRz8vL0c7O0M3QbGugAABvAABvAABvAABwAABwAABxAABxAABx\r\n        AAByqqm/1dLT2NbW19XV1dPUZmWiAAB0AAB0AAB1AAB1AAB1AAB2LCuJ09HT29jY29jY29nZ3Nra3Nna\r\n        3tvc4N7e2tjZ1dPT09DRx8XFraur19TUycjHr62t////////////////////////////////////////\r\n        ////////////////////////////////////////////AACBAACBAACBAACBAACBAACBAACCAACCAACC\r\n        AACCAACCAACCAACC////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////AAB+AAB+AAB9AAB9AAB9AAB9AAB8AAB8\r\n        AAB8AAB8QUCX39vb39zb3dva3drZ3NnZ29fY29jY29jY29jY29jY3Nna3dra3dnaubbKDw59AAB3AAB2\r\n        AAB2AAB2Bwd4pKS/1tTT1tPT19PS29XS3tjU2tfV19PT19LS19TT2NXV2dXU2NXV19TT19PQ2dPS2dTU\r\n        19TU1dLS0M3Nwb++sa2tsa2t////////////AABrAABrAABrAABrCQlewb/H2tnZ0s/PzsrJzcnJzszL\r\n        zszLy8jJy8jJzMrKzMjJy8nJy8jIy8fIysfHycbGyMXFyMXEyMXEx8XEyMbFyMXFyMXFx8TFxcPDxMHB\r\n        w8DBxMHBwr+/wsC/wr/Awb++wsHAw8HBwr6+wL29wL6+wr+/wr2+v7y8vru7vbq6vbq5u7i4vLm5vLm5\r\n        vLm5vLi4vLi4u7m5uri5u7m5vLm5u7m5uba2t7S0uLe3uLa3t7S0tLGxtLGxtLGxs7Cwsq+vsrGwtLKz\r\n        s7CwsK6tr6ysq6mqqKenqKenrKurrKqpq6mop6Wlo6CgpKKio6GhoZ+fop+go6Gho6GhpKGhpKKjpKKi\r\n        pKGhpqOjpqSkpKKjpaKio6GhoZ+foJ6eoJ6enpqampOTmJOTm5mZop+fqaWkramo////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////p6SkpqWlp6WlqKWlqaemp6WlqKWl\r\n        qaamq6ipqqeoqKamqainq6mpq6ipq6ipraqrrqursa6usK2tsK2us7CxtLGxsq+vs7GysrKysq+ws7Gx\r\n        tbO0t7a2trW1tbO0trO0tbOzt7W1t7a2t7W1trO0t7S1uLW1ure3u7m5urm5uLa3trO0u7i4vbu7t7a2\r\n        mJajcXCPRkV5FxdhBARWAgJWAABVAABWAABWAABWAABXAABXAABYAABYAABZAABZAABZAABaAABaAABb\r\n        AABbAABcAABcAABcAABdAABdAABeAABeAABeAABfAABfAABgAABgAABhAABhAABhAABiAABiAABjAABj\r\n        GBdvNjV+SEeHeHaffXuhp6a2y8jJy8jJTk6KAABnAABnAABoAABoAABpAABpAABpAABqAABqAABq////\r\n        ////vr29vr290M3NzMnJzcvL09LSkI+yBQVwAABvAABvAABvAABwAABwAABwAABxAgJyaGeh1dLT19XV\r\n        1dPT0tDRKCiFAABzAAB0AAB0AAB0AAB1AAB1YF+f19TV2tbX29fY2tfY3Nra3dnZ3NnZ29nZ2dfX29jX\r\n        3tvb3dvb2dfX19TUycjHr62t1dLSxcPDq6mp////////////////////////////////////////////\r\n        ////////////////////////////////AACBAACAAACBAACBAACBAACBAACBAACCAACCAACCAACCAACC\r\n        AACC////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////AAB+AAB+AAB+AAB+AAB9AAB9AAB9AAB9AAB8AAB8aWiq3dna\r\n        4N3d4N7d4N3c39zc3tvc3tzc3dva3dra3NrZ3NjY3dna3tva3drZeXitAAB3AAB3AAB2AAB2AAB2KyqI\r\n        1M/T2tfW19TU2dTU29TT2dTU19PU1tPT1tPS2dTT2tTU2tbU29fT3NfT3dfU3NjV2tbU2NXV0M3Nq6ip\r\n        sa2t////////////////AABsAABsAABsAABrAABkwb/H3Nvb1NHSzsrKzMnIzczLzs3MzsvLzcnKzMrK\r\n        zMnKzMnKzMnJzMnIy8jHysbHyMXFyMbFycfGyMXFx8TDxsTDxsLCxcLCxsPDxsTExsPDxcPDxcLDxcLC\r\n        xcHCw8HBw8HBxMDBwr6/wL29wL28wb29wb29wL++wL29v7u6vru6vry8v7y9v729v7y8vrq7vLi4u7e4\r\n        u7i5vLm5u7i4uri4ure3uLS0ube3u7m5uLW0tbKytbKytrOzs7Gxsa+urqyrr6yssK2tsa6us7Cwr66u\r\n        rKurrqyssrCwsK6tqqiop6Sko6GipaOkpKGipKGhp6Skp6alp6Wlp6SlqKenqamop6alpqSkqKWmqKam\r\n        p6SkpaKipaOjpqSkoaCfoJmYopqaqqWlsK2ssq+ur6yrramoramo////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////paOkpaOkp6WlpqSjoZ+foJ6fo6Ghp6Skp6Skqaenq6ip\r\n        q6ipq6mpqqmpqqmorKqrrKmqraqrr6yrr6ytsK2usK2usa+vsa+wsK+wsa+wsrGxtLKztrO0trO0tLKy\r\n        tLOztbOztrS1t7S1tbKytrOzt7S1uLW1t7W0uri4u7q6t7W2tbO0ube3trS0rKqqqaenrKmpsq6unJqp\r\n        dHOUQUF4FBRgAwNXAgJWAABWAABWAABXAABXAABYAABYAABYAABZAABZAABaAABaAABaAABbAABbAABc\r\n        AABcAABdAABdAABdAABeAABeAABfAABfAABgAABgAABgAABhAABhAABiAABiAABiAABjAABjAABkDg5r\r\n        BgVnGBdwKCh5Z2aZgoCgDg1qAABnAABnAABoAABoAABoAABpAABpAABqAABqAABq////ubjEzszMzcrL\r\n        zs3N0M3N0c7Ox8TKCQlyAABuAABuAABvAABvAABvAABwAABwAABxKCeDyMXM1NHS0c/OtrTCDAx4AABz\r\n        AABzAAB0AAB0AAB0AwJ2d3Wq1tPU2dbW2tfX2dbW2tfX2tfX29jY3Nna29jY2dfW2tfX29fX39zc5OHh\r\n        393d2tfX1dLSxcPDq6mp3dra3NnZwb6+////////////////////////////////////////////////\r\n        ////////////////////AACAAACAAACBAACBAACBAACBAACBAACCAACCAACCAACCAACC////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////AAB+AAB+AAB+AAB+AAB+AAB9AAB9AAB9AAB9CAh/kY+63Nna3tzc39zc4Nzc39zc\r\n        39zd39zc39zb3tvb3NnZ29jY3NjZ3NjY3NjY2dbXHBuEAAB3AAB3AAB3AAB2AAB2hICw3NjY2NXV1tTU\r\n        29TT3tTS3NbV2NbW1tLS1tLR2dXU2tfV2dXT29XU3djV3NbT2NTS2dbV0MzNq6ip////////////////\r\n        ////////AABsAABsAABsAABk////3Nvb1NLT0M3NzMrKzMvLz83N0M7Nz8zLzcnKy8nJzMrKzMnJzMnJ\r\n        ysfHy8jHy8jIy8nJysfIx8PFx8TEyMXFxsPCxsPCx8TFxsPFx8TEyMbFyMXFxsPExcLDxcLDxMHBxMHB\r\n        w8DAwr+/wr6/wb6+wr+/w8HBwsC/wb69wr29wr6+wr/Awr+/wr+/v72+v7y9vru7vLm5u7i4ure3uri4\r\n        u7i4u7i3ure3u7i4ube3trOzt7S0uLW1t7S0tbKysKysrqqpsa6us7Kxsq6ur6urrKipr62usrCwr62s\r\n        raqpqqenqKamqKamqaamqqiorKuqqqenqaamqqioqqenq6mpqainqqenqaemp6WkpqSjqKSkqqenp6Wk\r\n        oJ2do56dq6emsa6tsq2sr6mosKuqsKurrqqr////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////paOkqKWmpqSjoqCgoZ+gpaOkpqSlqKWlq6qqr6ytrKmprKmpraurrKqq\r\n        rKqqrKqqrKmqrqqrrqurraqqrqusr62tsq+vsa6vsa+vsa+vsa+usa+vs7GytLKys7KytbOztLGytbKz\r\n        tLKytbOytrO0tbKytbKytrS0uLa2t7W0ube3sq+wo6ChoZ6epqSkqaWmrqurube3vry9vry8mJembm2P\r\n        Pjx2EhJfAwNYAQFWAABWAABXAABXAABYAABYAABZAABZAABZAABaAABaAABbAABbAABcAABcAABcAABd\r\n        AABdAABeAABeAABeAABfAABfAABgAABgAABhAABhAABhAABiAABiAABjAABjAABjAABkAABkAABlAABl\r\n        AABlBARnAABmAABnAABnAABnAABoAABoAABpAABpAABpAABqAABqubjEz8vMy8jJ0M7Oz83NzMnJxcHF\r\n        PDuJAABtAABuAABuAABvAABvAABvAABwAABwAwNxk5G109DR0s/PiYivBgZ1AAByAABzAABzAAB0AAB0\r\n        EhJ8qqnA09DQ1dHR1tPT2NbV2dbW19TV2NXW2tfX2tbX2dfX29jY2tfX29jY3tzc3tvb3tvb4N3c3Nva\r\n        29nZ3dra3NnZwb6+wb6+wb6+wb6+wb6+////////////////////////////////////////////////\r\n        ////AACAAACAAACAAACAAACBAACBAACBAACBAACBAACCAACCAACCAACC////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AAB/AAB/AAB/AAB+AAB+AAB+AAB+AAB9AAB9FxeHoZ7C39vb3tva3tvb3trb39zc3tvb39ra3tva3dra\r\n        3drb3dra29fX2tbW2dXV2NXVkY+3AgJ5AAB3AAB3AAB3AAB2JCSG2dbY2tbW2NXV3djW4NfU3dbU2dbW\r\n        2NXV2dXT2tbU19TT1tLT19PT2dTT2tXT1NHR0c7Ovru7vru7////////////////////////AABtAABt\r\n        AABsAABp2dbX2dbX19TU0s/PzsvMzszMz8zMz83N0M3MzsrKzMjIzMrKzsvLzcrLzcnJy8jIy8nJysjI\r\n        yMXGycfIy8nJy8jIycbGycbHysbHycTFyMXFycbFyMXGxsTFxcPEw8HBw8DAwsHAxMLBxMHBw7/Aw8DA\r\n        xMDAxcDAw7/Aw8DBxMHAw7+/w8DAw8DAwr+/wsDAwr+/wb6+vru6vbq6vLq5oaCreniWg4Kbure5ure4\r\n        ube2uba1uLa1uLW2t7S0ubW2t7OztbGytbKytbSztbKxsq6ur6ysraqrraurq6ioq6inraqqrKqqraqq\r\n        raurrqysrauqrKioq6emq6elqqamqaamrKmpraqqq6ioqaamqaamqaamqaenp6Wkop2eqKOjrqqqsa6t\r\n        r6mpr6mosaursKurrqqrr6usraqr////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////paOjpaOjpKKhpaKip6Slp6WmqKanqaenq6mqqqipqaemqKWlqqeoqqioq6mpraurramqramp\r\n        q6ioqqioq6qprauqrqqrr6usrqursK2usa6usK6vsa+vs7Gxs7Gxs7Cxs7Gxs7CxtLGytbKys7Gxsa+v\r\n        s7GxtbOytLGxt7S0ubi3rqytoZ2fp6SjsK6tsK6tsrGxuLe3vbu8vbu8u7m6uba2t7S0k5Gja2mONjVy\r\n        KilsHh1mCAhbAABXAABYAABYAABYAABZAABZAABaAABaAABaAABbAABbAABcAABcAABdAABdAABdAABe\r\n        AABeAABfAABfAABgAABgAABgAABhAABhAABiAABiAABiAABjAABjAABkAABkAABkAABlAABlAABmAABm\r\n        AABmAABnAABnAABoAABoAABoAABpAABpAABqLSx/uLS/y8jIzcvLz8zNzcvLysfIZmSbAQFtAABtAABu\r\n        AABuAABuAABvAABvAABvAABwSkqT0M7P0c/QTEuTAgJzAAByAAByAABzAABzAABzJyeGrqzB1NDQ0c7N\r\n        0c7O1dLS2NXW2dXV2NTU19TU19TU2NbW2dfX2dfW2tjY3dvb3dvb3Nra3Nra3Nna19TU3dra3NnZwb6+\r\n        wb6+wb6+////wb6+////////////////////////////////////////////////////AACAAACAAACA\r\n        AACAAACAAACBAACBAACBAACBAACBAACCAACCAACCAACC////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////AAB/AAB/AAB/AAB/\r\n        AAB+AAB+AAB+AAB+AAB9ISCMvLjP4t/f4N7d39zb39zc4d7e4d3d4d3c4Nzc3tra4Nzc4N3c3dnY3NjY\r\n        29jY2tfX19TWPj2TAAB4AAB4AAB3AAB3AQF3c3Gq3dnZ3dnZ3NnY29fX29bW2tfX29jZ3tjX3dfW2dTV\r\n        2dXW2dbV2dXU3NfX0s/Ps7Kyvru7////////////////////////////AABuAABtAABtAABp////2dbX\r\n        19TU0c7Oz8zN0M3Nz8vMzcrLz83M0MzMzsnJzsrKzsvL0M3Mz8vMy8jJycfHysfGysjIzcvLzszMzMjJ\r\n        ysjIzcjI0MjEzsXBycXEyMbHyMXGyMXFy8TBx8HAw8HBxMLCxcPDxsPDxMHBxcLCxcHAx7+8xr++w8HC\r\n        w8HBwr6+xL/Aw8DBwsC/w8C/wr6+wLy9sq+1mZioZmWNHh1nERFfFxdjoqKuu7m4ura1vbm3u7i3uLW1\r\n        t7W1uba2uri3uLa2trS0tLKytbKytLOxsbCvrKqqq6ipp6Slp6Wlr62ssK6trqusraqsrqyrqqenpqOk\r\n        qaamqqalqaalqKemqaamq6enramprKqqqqenqqanqqioqKempqKiqqSkr6qrsq6usq+usq2tsq2tr6ys\r\n        r6ysr6usraqrr62urqqqqqem////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////oJ+foJ+f\r\n        oZ+fpKGipqOjpaKjpqWlqKampqOkpaOjpaOjpqSkp6Wlqqeoq6ipq6ioqqanq6inqqioqainq6morKmp\r\n        rKmpq6iorKmprqussq+wsa6vr62tsK2ssa6usK2usK2tsa6usq6wtLKys7GxsrCws7Cws7CwtLGytbKz\r\n        tLOyrqysraurtLKyuLa2tbOztrS1uLa3u7i5uri5uLe4ube4ube4ure3ura2tbK0nZunjoygY2KLNjVz\r\n        GhplBwdaAABYAABYAABZAABZAABZAABaAABaAABbAABbAABcAABcAABcAABdAABdAABeAABeAABeAABf\r\n        AABfAABgAABgAABhAABhAABhAABiAABiAABjAABjAABjAABkAABkAABlAABlAABlAABmAABmAABnAABn\r\n        AABnAABoAABoAABpAABpAABpSUiMwb7DzcrL0M7O0M/OzcvLnJqyBgZvAABtAABtAABtAABuAABuAABv\r\n        AABvAABvCwt1xMLIwb3FJiWBAABxAABxAAByAAByAAByAQFzREOSv77J19TU1NHQ0s/P1NHR1dPT19TU\r\n        19TT2NTU19TU19TU1tTV2NXV2tfX29nZ3NnZ3tvc393d4N3d19TU////////////////////////////\r\n        ////////////////////////////////////////////////////////AACAAACAAACAAACAAACAAACA\r\n        AACBAACBAACBAACBAACBAACCAACC////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////AAB/AAB/AAB/AAB/AAB/AAB/AAB+AAB+\r\n        AAB+ISCMvLjP6ebm5uLi5ODg4uHg4uDg4d7d4d7e4d3d4d7d4t7e497e4d3c4N3d4Nzc39zc3tvboqDB\r\n        CAh7AAB4AAB4AAB3AAB3Cgp8u7nL4Nzc3NnY2dbX29ja3drb3dra3dna3NjZ29fZ3NnZ3NnY3dnY3djX\r\n        ysbGs7Ky////////////////////////////////AABuAABuAABtAABu////3tze1tTV0s/P0M7N0M3O\r\n        zsvMzcvLzszM0MzN0MzNz8vLzcvLz8zMzsvMy8jJysfHy8nJzcrKzcvLzszLy8nJy8fH0MjF1MjB0sbA\r\n        y8TDx8TFx8XFy8TD0sXAzsXCx8XFxsTFx8TEx8TExsPDxcPExsLBy8G/ysLAw8HAwr+/w7++xcDAxMHB\r\n        wb69vLe6trS4e3maQD96Hx5oAABYAABXAABXAABWioigv7y7vbm5v7q6vru7u7m5u7m4u7m5u7i4trSz\r\n        tbOztLGysK2tsbCvr62tr66vrq2tqaenqqmpsrCvsrCvr62sraqrrqurqqiopKOjp6Wmqqiop6Skp6Sk\r\n        pKChpaKirquqr62sq6ioqqenqqeoqKWlqqWlrqmosKytsq+vsK2ssKussayssa6tsa2tsa2ur6ytr62u\r\n        rqqqqqemqaWkqKOjqqWm////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////oZ+goZ+gop+gpKKio6Cgop+g\r\n        pKKipaOioZ+foqGgpqSkp6amp6WlpqOkqKamqaenqaamqaanqaioqaenqqenq6mqrKqqrKmpqqenrKmp\r\n        raurrqusraqrrqqqr6usrqusq6iprayssK6usa+vs6+xsrCwsq+vsa6vs7Cxs7Gxr6ysp6WlqqiotbOz\r\n        t7W2tLKztbS0t7W2uLe4uLa3uri5u7m6ubi4ube4ure4ube2uLa2ube3trS2pKOtiYifX16JNTRzLy9x\r\n        CgldAABYAABZAABZAABaAABaAABaAABbAABbAABcAABcAABdAABdAABdAABeAABeAABfAABfAABgAABg\r\n        AABgAABhAABhAABiAABiAABiAABjAABjAABkAABkAABkAABlAABlAABmAABmAABmAABnAABnAABoAABo\r\n        AABoAABpFhVzqKa5zsrLz87NzszMzMnIxsLEHR15AABsAABtAABtAABtAABuAABuAABuAABvAABve3mm\r\n        q6m8IiJ/AABxAABxAABxAAByAAByAgJzT06W0tDQ1dPT1dPU1dPT1dLS09DR0s/Q1dLS19TU2NXU1tPT\r\n        1tTU2NbW2tfX2tfX3NnZ3tvc393d4N3d////////////////////////////////////////////////\r\n        ////////////////////////////////////////AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACB\r\n        AACBAACBAACCAACC////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////AACAAACAAACAAAB/AAB/AAB/AAB/AAB+AAB+////////6ebm\r\n        5uLi5ODg5+Xk5OPi4t/f4N3d393d4N3d4t7f4t7e4d3e4d7e4+Dh4d/g4N3d3trbOzqTAAB4AAB4AAB4\r\n        AAB4AAB3YV+i3drb3dra29jZ3Nrb3tzd3dvb3Nna3Nna3Nna29na2tjY39vb29fXvru7vru7////////\r\n        ////////////////////////AABuAABuAABuAABu3tze3tze2NfY09HR0c7N0c3Nz8zM0M/P0M3Nz8rK\r\n        0c7N0s/OzsvLzMrKzszMzcvLzMjJy8jIzMjIzMnJzcrKzMrKzMjH0MjG0sjF0cfEzsbDycXFyMXFy8XE\r\n        zsbDy8fFycfHyMbGyMXFyMTEyMXFx8TEx8PDyMPDx8PDx8PCxsLBxcLCxcLBv7u9jImjUlGEMjJ0AABa\r\n        AgJaAABZAABYAABYAABXPTx3lI+kwr69wLy+wL2+wL6/wb6/v7y8vbq5uba2trS0t7S0tbOzsq+wsa6v\r\n        raqstbO0trS0r62sr62ts7CxtLGxsq+ur6ysrqysq6mpqqenqqmoqaiopaKio56eo5+go6GhqainrKmo\r\n        qqinqaemp6SkqKOjraamsKyrsq+vsq2ur6qprqmpsaytsa6tsa6vsa6vsa+wraqqqqemqaalqaWkqKOj\r\n        qqWmrKinsaurs6+u////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////n52dn52doZ+foaCgoaCgoZ+hpKGio6GhoZ+foaCf\r\n        pKKjp6WlpqSlpqSlp6WlqainqKemp6amqKWmqaamqaWlqqenrausrausqqioqqenqqeoq6mpraurrKqq\r\n        rauqrqysrausr62tsa6usK2usK2vr66ur66usK6usa6usrCwr6yspaKjpaKjs7Gxubi4tbO0trS0t7W2\r\n        trW1tbS0uLW3uri5ubi4t7W1t7S0uLW1uLa2ube3ure3ure3u7m5tbO2o6Gtrq2yiIefVlaGLi5xCQle\r\n        AABZAABZAABaAABaAABbAABbAABcAABcAABcAABdAABdAABeAABeAABeAABfAABfAABgAABgAABhAABh\r\n        AABhAABiAABiAABjAABjAABjAABkAABkAABlAABlAABlAABmAABmAABnAABnAABnAABoAABoTUyOvbrD\r\n        zsvLzsvLy8nJysfHycXGWViTAABsAABsAABsAABtAABtAABtAABuAABuAABvISF+eHelEA93AABwAABw\r\n        AABxAABxAABxAABygX+r08/P1NHR09LS1NHS1tPT1dLS09DQ1NHR1dLS1tPU2NXV2dbW2dfX1dHS2tfX\r\n        3NnZ////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACBAACB\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////AACAAACAAACAAACAAAB/AAB/AAB/AAB/AAB/////////////////////5+Xk5OPi\r\n        4t/f5uPj4+Dg4t/f4t/f4d/e393c4N7d4+Hh4+Dg5ODf5eDfoZ/BAwN6AAB5AAB4AAB4AAB4FBSAxsTQ\r\n        3Nra3drb3Nra3dvd3tzd3tzc3tzd3tzd3dvc3dvc2tjY2tjYx8XFx8XF////////////////////////\r\n        ////////AABvAABvAABvAABu////3tze2dfX1dLS0s7P0M3M0MzN0c/P0c/Oz8rJ0cvL0s7Oz8zMzcrL\r\n        0M3N0c7Oz8zMzsvLzMnJzMfHzcnJzsvLz8zMz8vLzcnJzcjIzcjGysbFycXFysfGycfHyMbGycXGysbG\r\n        ysfHycbGycXGycXFyMXFxcTExsPDycXEysbFp6SzcG6WPj18AABcBgZeAABbAABaAABaAABZDg5gIyNr\r\n        dHOVtLG2wb2+wb6+wb29wb6+wL6/wb+/wsDAv7y7u7i4uri4ube2tbKytLKzsrGxraystLKytbOzsa+v\r\n        sa+vuLW1uLW1sK2trKmprKqppqOjpKKhq6moq6mppaGhpaCfpqOjpqSkpKCgoJ2doZ+fqKamq6inrKem\r\n        saurs7CwtLKytK+vsq2ssKyssa2usq+wsrCxsrGxsa+vrKioqqamqqalqKKhqaOiqaSlrKinsaurs6+u\r\n        sKuqq6qps7Gy////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////nJqanJman5ydoaCgoJ+fo6GipKGio6GhoqChoqGhpKKipKGipKGhpKOj\r\n        p6Wlp6amp6WlpqSkqKWmqaWmqKWlqKemqqioqaenqqmorKqqq6mprKqqq6qqq6mprKuqr62tr6ytr6yt\r\n        rqussK2usa+wr66vrqytrqysr62tr62tr62uqqiop6Wlr66uubi5tbO1trS1uLa3t7W2tbO0tbO0t7a2\r\n        t7W2tbOztLGytrKzuLa2uLa2uba3uba3ure4uri5u7m6u7q6ube3uba4sK61oqGueXeXPDt4DAxfDw9i\r\n        AQFaAQFbAABbAABbAABcAABcAABdAABdAABdAABeAABeAABfAABfAABgAABgAABgAABhAABhAABiAABi\r\n        AABiAABjAABjAABkAABkAABkAABlAABlAABmAABmAABmAABnAABnDQxug4Cmy8jIzMnJysjIx8XFyMbG\r\n        zMrJhIOoCAhvAABrAABsAABsAABtAABtAABtAABuAABuAABuHR18AABvAABvAABwAABwAABxAABxAgJy\r\n        oZ650tDQ09HR09DQ08/Q1dHS1tLS1dTT19TV1dHS1tPT2NXV09DQ2dfX1dHS////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACBAACBAACB////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AACAAACAAACAAACAAACAAACAAAB/AAB/AAB/////////////////////////////////5uPj4+Dg4t/f\r\n        6ebm5ePj4uDf4N7e4d7e4N3d4t3d4t7e39vdMzKQAAB5AAB5AAB4AAB4AAB4b26q3trc39zc3tva29na\r\n        3dvc3t3d3tzd3tzd3t3d3dvbzMrKycfHx8XF////////////////////////////////////AABvAABv\r\n        AABvAABvERFuzMrL2NXV19XU1dHR0s7O0s/P0c3Oz8vL0M3N0c3O0M3Nz83Oz83N0c7O0c7O0c7Oz83N\r\n        zsvMzsvLzcrKzcrKzsvMz8zMzsrKzcnKzcrKy8jHyMXEyMXEysfHy8jHysfHycbGysfGysjHysbHycXG\r\n        yMbGxsTEsK64jIqmV1WKExNnDAxjAABdAABcAABcAABbAABbAABaODd3dXOWsK21wL29wL28wL69wL6+\r\n        wb6/wr/Awb6+v729wb+/wcG/vry7uri3uLW1t7S1trS0tbSzsq+vs7GxtbS0s7GxtLGxuLa2uLW2s7Cx\r\n        sK6ur62sqKalp6Wkrqursa6ur6yssbCwsbCvsK+vrKmpoqCgnpydpKKir6qqsa2ts7GxtrS1trS1tbKy\r\n        s6+wta+wtK6vsq+vs7GytLK0sa+vraiorKmoq6emqaOiqqKirKWlrqelsqups6yqsKuqq6qps7Gyraqr\r\n        qaan////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////mZeXnJqanZqbn5ydnpycnpycoJ6eoqCgoZ+foZ+foZ+go6GhpKGhpKKipqSlpqSlpaOjpaKjpaOj\r\n        pqSkqKWmpqSlp6alqaalqKWlqaenqaenqKWmqaeoq6mpq6mpraurrausrKqrrKqrrKqqraussK6vrqyt\r\n        rqussK2tsa6usK6ur62urq2tqqinq6mpsrGwtbO0tbO0uLa3t7a3tLO0trS0t7a2tbOzs7CxtLOytbKz\r\n        trS0tbOztrS1ube4uba4ube4uri5u7i4ure4ure3uri4uri4u7i4u7i5rayzjo6kX16LNjZ2LS1xFRVm\r\n        BARdAABcAABcAABcAABdAABdAABeAABeAABeAABfAABfAABgAABgAABhAABhAABhAABiAABiAABjAABj\r\n        AABjAABkAABkAABlAABlAABlAABmAABmAABnJSR4pqW2yMbGyMXFx8TExcLCxMLCx8bFqqe2CgpuAABr\r\n        AABrAABsAABsAABsAABtAABtAABtAABuAABuAABvAABvAABvAABwAABwAABwHRx+zcrN09DQ09DQ0s/P\r\n        08/P1NHS1NLS1tTU1NHR1dLS1tPU2NXV09DQ////1dHS////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACB////////////////////////\r\n        ////////////////////////////////////////////////////////////////AACBAACBAACBAACA\r\n        AACAAACAAACAAAB/AAB/////////////////////////////////////////////6ebm5ePj4uDf5+Pk\r\n        5uPj5eLi49/f4d3e4N3elZO8BAN7AAB5AAB5AAB5AAB4FBSBwsDP4Nzd3tzc3dvc3t3e393e3drb3dna\r\n        4d3e29nZuLa2ycfH////////////////////////////////////////AABwAABwAABwAABvERFuwb/L\r\n        1NHS1NLS1NHQ09DQ1tTU1NHRz8vM0M3N0c/P0MzN0M3O0M/O0M7O0tDR0tHR0tDQ0M3Oz83Oz8zMzcrL\r\n        zszMzszMzsvLzs3Nz83OzsvMy8jJycbHysfHzMjIy8jHysbFysfHy8jIy8jIwr/Dm5mwZ2WUHh1uFxZr\r\n        AABeAABeAABeAABdAABdAABcAABcLCtzf36esK22wr+/w8DAw8DAyMTAxsG+wb69wb/Aw8HCw8HBwr/A\r\n        wb6/wb+/v7y8vLm5uba3uLW2uLW2uLW1tbOztLGxtrSzt7a1t7W1t7W1tLOysa6vsa6vs7GxtbSztrSz\r\n        t7SztrSzt7W1uLe4t7W2t7W2t7W1sK6uq6mpr6ystLCwtrW0t7W1t7W1t7S1tLGys7CytbCxtK+vsa6u\r\n        tLGytbO0srCwramprKemrKalqKKhp6GhqKCeqZ2ZqqCdr6mosa6trqyrtbS0raqrqaanqqenqqmp////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////lJGSmZeXm5mYnZuc\r\n        npyenZubnJqanp2dn56doZ+foJ6eoZ6fop+gpKGhpKKipaOkpaOkpaKipKGho6Cho6GhpKKjpKGjpKGg\r\n        paOhpqSkqKanqKamqKWmqaenq6ipq6iprKmprKmprKmqraqrrKurraytrqysrqysrqurrqusrqussK2u\r\n        sK6us7GxrKmqpKCgrKqptbW1tLO0sq+vsq6vtbK0tbO0raqqpqOjrqurtbOztbOztbOytLKztLOztrSz\r\n        t7S2t7W2uba3ure2ure3uLa3uLe3ube2ube3ube3uri5vbu7u7m4rquxn52rgoCdaWeQU1KFKilwBARe\r\n        AABcAABdAQFdAABdAABeAABeAABfAABfAABgAABgAABgAABhAABhAABiAABiAABiAABjAABjAABkAABk\r\n        AABkAABlAABlAABmAABmTUyLu7m/xsTDxcHBxcLCxcTExcPDxcPDxMLCMjGAAABqAABrAABrAABrAABs\r\n        AABsAABtAABtAABtAABuAABuAABuAABvAABvAABvAABwRkWQz8zO0s7P0s/P0s/P09DP1NHR09DQ0c/P\r\n        xcLCwb6+1tPU////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAB/AAB+AAB/\r\n        AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACB////////////////////////////////////////\r\n        ////////////////////////////////////////////////AACBAACBAACBAACBAACAAACAAACAAACA\r\n        AACA////////////////////////////////////////////////////////5+Pk5uPj5eLi6eXm5+Pk\r\n        5eLi39zeLCuNAAB6AAB5AAB5AAB5AAB4dnSt393e39ze3tzc393d393d3dvc3tvc4d7f19TUuLa2////\r\n        ////////////////////////////////////////AABxAABxAABwAABwAwNwsa7C1NHR09DQ1NLT1tTV\r\n        2NXW19TT0tDQ0s/P0s/P0c7O08/Q09DQ0dDP0tDR09HS0tDQ0c7O0M3O0M7O0c/O0c7O0M7NzszLzszM\r\n        0M7O0M3Oz8vMzsrLzMnJzcrJzMjIy8fGycbHqKa3h4WmMzJ7IB9xAABgAABgAABfAABfAABfAABeAABe\r\n        CAhhHx5tcnCYyMXEx8TDxcLCw8HBxcLBysfDzszDycTBwb/AwsLCxcPCx8TDxsPCxMDBwr+/wb6+v7y9\r\n        u7m5uba3uri4uri4uLa2uLW1uba2uri3ube3tLKxrauqraqrsrCws7Gxt7a2u7m4u7m4uri4ubi4uri5\r\n        uri5uri5u7i5trS0s7CwtrGyt7W1ubi4uri4uLW0t7S0trS0t7W2tbS0tLGytLGytrO0t7W2trW0rqyr\r\n        q6alrqemrKenqqamqqakpZqZo5mZrKurtba2rq2st7a2raqrqaamqqenqqmprKqq////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////lpWVlJGSmZeXmpiXm5iZm5mam5qam5mZm5mZ\r\n        npycop+foqCgoZ+foZ+gop+gop+foZ6fop+gop+goqCgo6Ggo6Cfo6Cfo6Cgo6Cgo6CgpaKipqSkp6Wm\r\n        p6anqqioq6ipqqipqaemqaWlqqenq6eoraysrq2uraqrq6mprKuqq6iprKmqrqussK2usa+vpqKknpuc\r\n        qaintLSzs7Kyr6qrraiotLGysrGyqKampqSjsK2ttbOztLKytLKytLKzs7Gxs7GwtbKztrO0trS0uLW1\r\n        uLW2ube4ube4ubi4uri4uba3uba2uba2uLW0t7S0uba3uLa2s7Czure3sK6zoJ+rcG+TTUyCKipxGxtq\r\n        FRVoAgJfAABeAABeAABfAABfAABgAABgAABhAABhAABhAABiAABiAABjAABjAABjAABkAABkAABlAABl\r\n        Dw9sf36ix8XFxcLDxsPExsXFx8XFyMbGyMbGyMfHammaAgJrAABqAABrAABrAABrAABsAABsAABsAABt\r\n        AABtAABuAABuAABuAABvAABvAQFvc3GjzMnM0c7O0c7O0c7O09DQ1NLS1NHR09DQu7m5wb6+////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAB+AAB+AAB+AAB/AAB/AAB/AAB/\r\n        AACAAACAAACAAACAAACAAACBAACB////////////////////////////////////////////////////\r\n        ////////////////////////////////AACBAACBAACBAACBAACBAACBAACAAACAAACA////////////\r\n        ////////////////////////////////////////////////////////6eXm5+Pk5eLi6Oble3qyAAB6\r\n        AAB6AAB5AAB5AAB5ISGI2dba4N3d4N3c4Nzb39zc3tvc39zd3t3cyMfHyMfH////////////////////\r\n        ////////////////////////AABxAABxAABxAABwCwt2o6G+2NXU1NLR19TV2NXW2NXV19TU1tTU1NLR\r\n        09DP1dHR1tTU1tPU09DQ08/Q09DR09DQ0s/O0c7O0c7P09HR1NHR0s/P0c7O0M7Oz83Nz83M0M3N0M3N\r\n        zsvK0MzMv7vDkY+sS0qIKSl3AABiAQFiAABhAABhAABhAABgAABgAABfAABfLSx1bmqVqKKyy8bFycbG\r\n        ycXFxcLCw8HBxMLCycbDzMjDycTCxcPDxMLCxsLByMTBxsLBxMHAxMHAw7+/wLy8vry7vru7u7i4ube3\r\n        ubi4vLq6vLi4uba2vbu6t7a1rqursK6utbOytbKxtLKxtrS0uLa2u7m5vLm6ure3u7i5vLm7u7m6uLe2\r\n        trOztbKyt7W2ure5vrm5vLi2ubW2ube4ubi5uLe4t7S2uLS1t7S1uLa3uLe3srCvramoraior6yrr62t\r\n        raqqqKOin5mZpKOksrOzrq2st7a2sK6uraysrKqrq6mqrKqqr62t////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////lpSUlpWVmZeYmJaXm5mam5iYm5iZnJqbm5mZmJWWm5manZubn52coJ6e\r\n        oJ6foJ2fn52doJ6foJ6foJ6foJ6foZ6eoZ2eop+epKGgo6KipKGipKGhpKKipKKipqSkp6WlqKamqaen\r\n        qaamp6SlpqSjqKamqaioqaeoqKWmqqemqqmpq6qqrKqqramqrqysrKqqpKKjoJ6fpqSjrq2tsrCwsa2v\r\n        sK2usbCwsbCxr62usa+wtLKztbS0tLKzs7CxsrCws7GxtLKzs7KytbKytrOztrS1trS2t7W2uLa3uba3\r\n        ure4ube3uLa3ubW1trOztbOztrOztbKys7CxtrS0urm4uri5u7m5vbu6rq20k5Glg4GeZ2aRTEqCLSx0\r\n        AQFfAABfBQViAgFhAABgAABgAABhAABhAABiAABiAABiAABjAABjAABkAABkAABkJiZ3o6GyxsPExsTE\r\n        x8XGyMbGyMXFycfGycfHysjJmZiwCQhtAABqAABqAABqAABrAABrAABrAABsAABsAABtAABtAABtAABu\r\n        AABuAABuDg51hIOqzcrLz8zMz8zM0M3NzcrKzszM1NHR2tjYu7m5wb6+////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACA\r\n        AACAAACAAACA////////////////////////////////////////////////////////////////////\r\n        ////////////////AACCAACCAACCAACBAACBAACBAACBAACAAACA////////////////////////////\r\n        ////////////////////////////////////////////////////6Oble3qyAgJ7AAB6AAB6AAB6AAB5\r\n        AAB5mZe84N3c4d7d4N3c4d3c39vb4dzd29jZuLe3uLe3////////////////////////////////////\r\n        ////////AAByAAByAABxAABxAgJxhoSx2dfX19XV2NXV19XV19XV19XV19TU1tLS1NDR1tTU2NbW2NbW\r\n        1tLU1dHS1dLS09DQ0tDQ09LS0s/R09HS1dPS1NLS09DS09DS0c/P0c/O0M7Nwr/Fqqi5ZWSXPz6EAABk\r\n        AwNmAABjAABjAABiAABiAABiAABhAABhCgplHh1vcW+ZvbW8zcTB1MvGzsnIy8jIysfHx8TExsLDx8TF\r\n        xcPCycTCzcfEzMfExsLCxcHCx8TCxsLBxMHBw7+/wr6+wLy8wL28v728u7i3uLa2ube3vry8vLm6ure3\r\n        wcC/xMLCvLi5ube3uba2uLW0tbOytbKyt7S0ure3uri4t7S0ubW2vru8vr29vLq6uLa2uLa2ubi5u7m6\r\n        vLi4vLi4u7i5u7m6u7q7uri6uri5ube4ube3uri4t7W1s7CvsKysr62sr62trqurqaSlqqalop2doqCh\r\n        sbCwsK6uube3s7GxtLOzsK6vraqrraqrr62tr62t////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        l5SVmJSUlpSUl5WWmJaXmZeZmpmanZubnJmanJqbnJmam5iZmpiZmpmZm5manpydn52fnpyen56en56f\r\n        oJ+goJ6eoJ6en5ydoJ2doZ6eoZ+eo6ChpKKipKKjo6Cho6Cgo6GhpKKipKKipqOkpqSlpqWlp6amqaio\r\n        p6OkpKChpqOjqaamqaanqaeoqqeoqqanq6mpqqipq6mqqaioqKWnq6iprqytsa+xsK+xsK6vsK6vsbCx\r\n        srCxsq+xsK+wsa+vsa+vsq+vtLGytLKzs7GxtLKytrS1trS1tLK0tLKztLOytbO0t7S1uLa2t7W1t7S0\r\n        tbKytLKytrO0tbKys7CwtLOyuri4ure4uba3u7i4vLm5vLq6vbu7t7S4tLK1uLa3pKOveniaYV+NRkWB\r\n        OTh7IiJxAgJhAABhAABhAgJiAABiAABiAABjAABjAABjAABkU1KMu7m/xcLDxcPDxMLCxcLDxcLDxsTE\r\n        x8bGyMbGwL3CHx93AABpAABpAABqAABqAABrAABrAABrAABsAABsAABsAABtAABtAABuAABuJCN+oZ61\r\n        zMjIy8jIzsvLzMnJt7S0zszM////2tjY////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////AAB+AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACA\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        AACCAACCAACCAACCAACBAACBAACBAACBAACB////////////////////////////////////////////\r\n        ////////////////////////////////////////////AgJ7AAB7AAB6AAB6AAB6AAB5QD+W4N3d4t/f\r\n        4N7e4N3d4Nzc4t7e4N3euLe3////////////////////////////////////////////////AAByAABy\r\n        AAByAABxAABxa2ql2dfY2tfX2NXV19XW2NbX2NbW19TT19LS1tPT1dTU2NbW2NfX19XW19TV19TU1dPT\r\n        1NLT1dTV1NLT1NHS1dPS1dLS1NHS09DRycbLuLbDeHaiS0qLAABmBgZoAABlAABlAABkAABkAABjAABj\r\n        AABjAABiAABiMzJ7bmyZtbG9z8nI08rF0sfC0MjGzcjIzMnJy8jIysfHzcnHzcfGy8bEzMjG0czIzcfE\r\n        xsLCxsPEx8XGx8XFxsPDxMDBwr+/wr+/v7y8vbq6vbq5ure3uba2v729wL29u7m5v729xsTExcPDwb+/\r\n        vbq7u7i5uba3uLW2u7i4ure3t7S0trS0uLW2vLq6vr29vru8vLm6vLq7vLm6u7m5u7i5ube4u7m6vLq7\r\n        vLm7vLm7vLq7u7m6urm6vLq6ube3s7Cvrauqq6inrKioq6enqaSlq6enrKursbCxt7a2srGxuri5tbOz\r\n        tbOztbKzsa6wr66usbCxtbO0////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////lZKUlpSVl5SVmJSUl5OTlpOU\r\n        mZaXmZiYmZeYmpeZnJmZmpiZnJqbnJqbnJqanpycnpydnZydnp2dnp2dnZucnpucn5ydoJ6doJ2eoJ2e\r\n        oJ6doJ+eoJ6fo5+go6Cgo6Gho6GipKKjpaOjpKGho6ChpKKjpqSlpaSkp6anqaeoqaamqKWlqKamqaeo\r\n        qKWmpqKjp6SlqaanqaanqqiorKqpsK+vsK+xrqusrKqrrayur66vr62usK6vr66usK+vsa6wr62urq2t\r\n        sa+wsrCxs7Gys7CxtLGytbO0trO1tbK0tLKztbO0tbKztbO0trW2trW1trS1trO0trO0t7S0uLa2ure3\r\n        uri3uri4u7m5uri4t7S1uLS1ubW1u7i4vbq7vLm5u7m5uri4vLq7vru8vrq7sa+1qKexo6GwmJaqcG6Y\r\n        SEeEOzp+JCRzIiJzAgJjAABiAABjBARlX16RxMLCxMLDxMHBxcHBxMHCxcPExcTExsTFx8XFx8XFYmGW\r\n        AABoAABpAABpAABqAABqAABqAABrAABrAABrAABsAABsAABtAABtAABtMzKFtbK9y8fHy8nJz8zMycbG\r\n        t7S0////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////19bV////////////////////////\r\n        ////////////AAB+AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACA////////////\r\n        ////////////////////////////////////////////////////////////////AACCAACCAACCAACC\r\n        AACCAACCAACBAACBAACB////////////////////////////////////////////////////////////\r\n        ////////////////////////////////AAB7AAB7AAB6AAB6AAB6BQV8xcPU5eLi4+Hg4N3e4d7e4+Lh\r\n        4N3euLe3////////////////////////////////////////////////AABzAABzAAByAAByAAByTU2X\r\n        1tTY3Nra3NnZ29nZ29nZ2dbX2dbV2NXV19TU2NXW2dbX2NbW19XV19XV2NbV19XV1tPU1NPU09LR1dPS\r\n        1NHSysfM0tDQf32mW1qVFhZzDAttAABnAABmAABmAABmAABlAABlAABkAABkAABjAABjAABigX+ns7G/\r\n        z8zMzcrKzcnIzsfFysTDycbHy8jJzsrKzcrKzsrI0s7Iz8rGzcjGzcjHzsrHysfFx8TEyMXFyMXFyMXF\r\n        x8XFx8TExsPDxMHCwL6+vru8v729vry7v7u8wr+/wb6+vLm5uri4v729xcTExcTEwr/Av7y9vbm6vbq6\r\n        v729v7y8vLi4u7i4uri5ube3vLu7v7u8wLy9vLq6ubS0ura2vr29vbu7u7m6vLm7u7i6u7m6vbq6vbq7\r\n        vLq8u7m6u7m6trSzqqempaCgq6Slrampraqrr62utba1urm5ure3srGxu7u7t7W1trS0trS0trW1t7S0\r\n        t7S1tbO0tbO0////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////lZKUlZKUlpSVlZOUlpKTlZKSlpOUl5OVmJWVlpSUl5SV\r\n        mJWWmZeXmJeXmZiYmpeYnJmam5mZm5mZnp2dnpycnZmanZqanJqanZubnpycnp2dn56dn52doZ+go6Ch\r\n        o6Cgop+go6GipKSkpaOkpKKjo6GipaSkpqWmpaOlpqOlqaeoqKinp6elpqSlqaeoq6mqqqeoqaioqqmp\r\n        qqeoqqioraqrraurr6ytrqutrKusrKysr66ur62tr62usK6vsLCws7KysrCwsbCvsrCwsrGxsbCxs7Cx\r\n        srCxtLKztrS1trO0trW1t7W2t7W2t7W2uLa3t7W2t7a2uLa2uLW2uLa2uri4vb29vr6+vLu8vLq7u7q6\r\n        u7m5uri3u7q5vbu7vry8vb28vLu7vbu7vLm5vry8wL6/wcDAv7++wL++wsDAwcDBwcDBs7G4np2wo6Gy\r\n        lJKqcnGaSEeGQECCioilxMLCxcPExsTEyMbFyMbGx8bGycfHx8bGxcXExsbFlpWvAQFoAABoAABpAABp\r\n        AABpAABqAABqAABrAABrAABrAABsAABsAABsAgJuTUyQycbHz83Nz87O0c/PzMrKzMrK////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////sK2t////////////19bVz83Nq6io////////s7GxoZ+f////////////AAB9\r\n        AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACA////////////////////////////\r\n        ////////////////////////////////////////////////////AACCAACCAACCAACCAACCAACCAACB\r\n        AACB////////////////////////////////////////////////////////////////////////////\r\n        ////////////////AAB7AAB7AAB7AAB7AAB6AAB6Ojp+5eLi4+Hg5eLj4d7e4+Lh////////////////\r\n        ////////////////////////////////////////AABzAABzAABzAAByAAByODeN2tna3dzc3tzb3dvb\r\n        3dra29jY2tfX2dXW19TV2dfY2dbW19TV1tTV19TU19TU2NfW19TU1NLSy8jNz87Rh4asYV+ZGRh1CQlu\r\n        AABpAABoAABoAABnAABnAABnAABmAABmAABlAABkAABk////////////gX+n2NXW1NHRz8zMzMrKysjI\r\n        ysfHysfHzMrKzcvLzMnJzsrH0MzIzMnHy8bHycTFyMXGzMnHzcnHyMXFx8XFx8TFyMXFx8XFx8XGyMXF\r\n        yMXFxcPDxMLDxMPDwr/Awr6/wL69v729v7+/wsHBx8XFx8TEwr+/wL+/wr+/wr28wr6+wcDAwb6/wL29\r\n        vby9vLq6vrq7vbm6v7y8v729u7e3u7m5v72+wb6/vbu8vby8vby8u7m5vLq7wL29vry8u7m6vLq7uri3\r\n        rqysrKmqsq6vs6+vsq+xtLKzt7W2uLa3uLa2srKwvLy7uri3uLe2trS0uLW1uLW1t7W2t7a2t7a2////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////jouMkY+OlpONl5SRkY+QkY6OlpKQmZWQk5COkpCPlI+PlpSTlJKSlZGRmZWW\r\n        mZeXl5WVmZeWmpiXnJqZmpiYmJWWmZeWmZeVmJaUmZWVm5iZnp2cn56dn52doJ2cnpyanp2bnpyaoJ+e\r\n        npycnJqbn56doqCfo6CgpaGiqaWmp6WlpKOio6GhpKGio6KhpaOipqOipqSjqaempqWlpaWjqKalq6mn\r\n        qainqaioqqipqainq6moraqqqKeoo6KipaKiq6morq2trqysraurrayrr62sraysq6ytrq2usbCwsbCw\r\n        sK6usa+vsrCxtbS0t7W1trSzsrGwrKqrrqyrs7KxsbCwraysr6yssa6utbOzuLi3tbOzraysrauss7Gx\r\n        tbSzsrCwsa+vt7W0vLq5vry8vr29vLq5vrq3v7q5u7m5vLm4vLm4vLq5vbq5wL28v769v728wb6+trO7\r\n        vry/wL69wr+/xsTExcTDxMHAxMLBxMPDw8HCxMHBxcPCrau3GBhyAABoAABoAABoAABpAABpAABqAABq\r\n        AABqAABrAABrAABrAABsAABsf3ylxcPCwsC/z87O0c/PzMrKzMrK////////////////////////////\r\n        ////////////////////////////////////////////////////////////////19PUyMXGycjIzMnK\r\n        y8jJsK2tz83NxMHBxMLB19bVz83Nq6io0c/PzszMs7GxoZ+fycjHsbCw////////AAB9AAB9AAB9AAB9\r\n        AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACA////////////////////////////////////////\r\n        ////////////////////////////////////AACDAACDAACCAACCAACCAACCAACCAACC////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAB7AAB7AAB7AAB7AAB6Ojp+////////5eLj////////////////////////////////////////\r\n        ////////////////////////AAB0AAB0AABzAABzAABzISCBwb/N3dvb4N7e3NfX2tnY3d3e3Nna2tXU\r\n        29jX3dva4N/f3t3e2dfX1dLR2NXU09DV2NfXlJOzbWugMTGECgpwAABqAABqAABpAABpAABpAABoAABo\r\n        AABoAABnAABnAABmAABl////////////////////////2NXW1dHQ0MzLzcrKzcrJycbGycfGzczLyMbH\r\n        wb+/xMHCx8PDxsPDycfGyMXFxMHBxcLDx8XExcLCxcPCxsPDwLy8xMHAxsPBv7y8wL28xMC/vru7vLq5\r\n        wr69vLi3uba1u7e2ure3t7S0uLS0u7e3uri2ube2tLKxs6+vtbGwubW0vLm4u7e3ubW2vbu6u7i3u7e3\r\n        u7e3t7SzubW2vbm6vLi4vbm5vbq5u7q5uba3uLS0uLS0t7O0trO0ubW1vLa1ubWzuLS0u7i4vbu8u7i6\r\n        uba3uLa2trS0tLCvtrSyuLa2uLW1uLa2uLa2uLa3t7e2t7a1uri4urq5urq5////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        jouMjouMjoyLlJGNkpCNjImKjoqLko6Ok4+NlpKOlJCOk5CQlJKSk5GRkY6Oko+PkpCRlJGRlZOSl5SU\r\n        lpSUlZOTlZKSl5STlpWUl5SUmZaWmZeYmZeYm5iZnZybnZuanZqanZuan5ycn56enp2dm5mZm5iYnZyc\r\n        oJ6en5ydoJ2eo6Cgo6Kho6Cgop+foZ+goZ+fpKGhpKKjo6GhpaKipqOjqKWlqaanqaenqKemqaioqKen\r\n        qqenqKWmpaOjpKKjp6Okqaamq6mpqqeoqqenq6mprKmqrqurrqysr62tsK6vsK2ur62usK6vr62usa6v\r\n        s7Kys7GysrCwraqqrqyss7GxtbOzsK6urKmqr6yts7KytbOztbOzsK2tr6ystbOzuLa2tbOztrS0uLW1\r\n        uLS1uLW2u7m4vrq4v7q5vbu7u7i5u7m5vLm6vbq7vbu7v7u8vry8vby7v729v729v7y9wsC/xMLCw8HC\r\n        wb+/wr+/xcLBxcLDwb6/wL6/w8HCvr2+RESGAABnAABnAABoAABoAABpAABpAABpAABqAABqAABrAABr\r\n        AABrAABspqO4xMLBwsC/////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////19PUyMXGycjIzMnKy8jJzszMz83NxMHB\r\n        xMLB0c7O3NnZ1dLS0c/PzszM0M3O1NHSycjHsbCw0s7PxsTEHBx3AAB9AAB9AAB9AAB9AAB+AAB+AAB+\r\n        AAB+AAB/AAB/AAB/AAB/AAB/////////////////////////////////////////////////////////\r\n        ////////////////////AACDAACDAACDAACDAACCAACCAACCAACC////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAB8AAB8AAB7\r\n        AAB7AAB7AAB7////////////////////////////////////////////////////////////////////\r\n        ////////AAB0AAB0AAB0AABzAABzBwd2x8fT393f4t/h4d7f4d/e4eDg4N3e39zc4N/e397e4d/f4d/g\r\n        2Nba29nanJy7dnapODeJDQ1yAABsAABsAABrAABrAABqAABqAABqAABpAABpAABpAABoAABnAABnAABm\r\n        ////////////////////////////////1dHQ39zd2tfY1tPT0M7O0c/P0tDQ0c7PzcvMz8zN0M7O0MzN\r\n        0M7Nz8zLzcrKzszNz83OzsvMzcvMy8nIyMbFzMrKzcvLysfIycfGy8jIycXGxsPCy8bEx8TDxMPDx8TE\r\n        xcLBwsC/xcHBxsPDxMLBwMC/vby7vru6wb69xMDAxcHBw8DBwsDBw8HAwsC/w8DBxMLCwsDAw7/AxMHC\r\n        w8DBwsC/wsDAw8HBwb2+wb2+wcDAwL+/wL69v729wb6+v7y7vry7vr29vru8vrq7vbq6u7m5u7m5vLq5\r\n        vby6ube4ube3uLe3uLW2tLKzsa+wsK6tsa6uq6mqq6mq////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////jImJjImJi4iIjYmK\r\n        kI2Lko6LkoyLkoyLko6Kl5ONk5COkY6PlJCQkY6PjouMj4qJk42Lko6Ok5CQlJGRk5CRlJKSlpOTlpKS\r\n        lZKTlpOTl5WVlZKSlZKSl5SUmJWVmZaWmpaXm5mZm5iZm5iZnJmZnJqZnJmZnZqbnpybnJqanJqbn5yd\r\n        oZ+foZ6eoZ6foZ6fop+go6Cgop+hoZ6eop+fo6CgpKKipqSkpqSkqKWlqKWlp6Wmp6WmpaOkpaKjqaen\r\n        p6WlpaKjqaanqKamqaamqaanqaeoq6iprKmpq6ioraqrrqusr62ur62urqusrqyssK+vsK2ur6ytsa6u\r\n        sK6usq+wtrO0srCwpqOjpqOkr66urauqsq6usq+vsq+vs7CxtLGys7GxtbOytrS0tLGytrKyurSzu7a1\r\n        u7e4u7m6u7m5u7m4vLm6vbm6vLq6vbm6vbu7vby7u7m6vLm6vLi5vrq6vbu7vbq7vru8wL69w7+/wr+/\r\n        wL29wL29wr+/v7y9h4WiAABmAABnAABnAABoAABoAABoAABpAABpAABqAABqAABqAABrIyJ7ysfHtbKx\r\n        tbKx////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////raqqxcLC19PU0s/R0s/P1tPT1NHS1NHS2tfX2dbX1dPT09DR1tPU2dbX\r\n        29nZ2NbW19XV3NnZ3NrZ1tPT0s7PxsTEenmeAAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/\r\n        AAB/AAB/AAB/////////////////////////////////////////////////////////////////////\r\n        ////AACDAACDAACDAACDAACDAACCAACCAACC////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAB8AAB8AAB8AAB8AAB7AAB7////\r\n        ////////////////////////////////////////////////////////////////////////AAB1AAB1\r\n        AAB0AAB0AAB0ExN9q6rH4d7g4d7g5ePl4+Hi4N3c3tvb3tzc3tzc3Nna3NjZpaLAeXirQ0KPCQlzAwNw\r\n        AABtAABtAABtAABsAABsAABrAABrAABrAABqAABqAABpAABpAABo////////////////////////////\r\n        ////////////////////39zd4t/g2dbX19XW1NLU1NLS1tPT1NHT09HS1NPT08/R0c7P0s7O08/Q09DR\r\n        0dDR0c/Q0M/QzcvLzszMz83OzczNzczNzczNzcrMz8zNzcrLzcvLz87Oz83Ozs3OzszNz8zMz87Pz83O\r\n        zczMyMfHxsTEysjHzczLzcvMy8jJycjIyMbGyMTFycbHy8jJycfHxsXGxsTEx8TEx8XGxsPExcPExcPD\r\n        xsPDxcLDxcPDxMPDxMLCw8LDwsHDv76/v76+wsDBwb6/wb6+v729vbq7vbq7vry8wb+/u7i5vry8vr6+\r\n        ubm6sK6vrqqrrampqKGioZycoZyc////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////i4eHioiIioeIiYWGkoyJlpCMko2LkYyJ\r\n        ko2Lk4+Mj4yMj4yNkY6Ok46OlIyKl4yHmZCLlI+Oko+Pko+PkY6Ok5CQlJGSlJGRlJGRlJGRlJGRlZKS\r\n        lZGRlJGRlJGSlZKSl5SVmpeYmpiYmpaXm5iZnJmanpubnZqanZqanpydnp2enpucnpycn5ycoJ2eoZ+g\r\n        oZ+goZ+gn56eoJ2coZ2doZ6eoZ+foqChop+go6GhpaKjpqOkpqWlpaSjpqSjqKemqaiopaOkpaOipqOj\r\n        qaemq6eoqqenqainqaenq6eoq6mprKmqrqysrqysrKmqrqurr6urrqqqrqursK6tsa6ur6yssK2tsK2t\r\n        q6moq6iosK+vrKmprqqps7GwtLGxs6+wsa6vsq+vs7CvtLKxtbKytrKyuLKzuLS0uba2ube3ubi3u7i4\r\n        vLi5u7m5u7m4vbq5vru6vby7vbq6vbq6vry8vLu6ubi3u7e3vrq6vru6vrq6v7u8wL69wr++wr69wby8\r\n        tbK4ExNvAABmAABnAABnAABnAABoAABoAABpAABpAABpAABqAABqZmSZxMHBnpubhoOD////////////\r\n        ////////////////////////////////////////////////////////////////////////////1NHR\r\n        ysfHyMPEraqqxcLCzszN0tHR0tDQ09HR1NLS1dLS1tPT1NLS0c7O09DQ1dPT1dLT1dLT1dPS19TT19TV\r\n        19XV2tbW3NjZ2NXVz8zPPTyUAAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/\r\n        ////////////////////////////////7uzs7uzs////////////////////////////AACDAACDAACD\r\n        AACDAACDAACDAACDAACD////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAB9AAB9AAB8AAB8AAB8AAB7AAB7////////////////\r\n        ////////////////////////////////////////////////////////AAB1AAB1AAB1AAB0AAB0AAB0\r\n        lJK84N7f3tvc3Nrb393e3tzc3dvczcvUpKK+aGeiS0qVAABwCgl0AABvAABvAABuAABuAABtAABtAABt\r\n        AABsAABsAABsAABrAABrAABqAABp////////////////////////////////////////////////////\r\n        ////////4t/g2djZ1tPU1dPU1NLT1dPT1dPU09LT0tHS0c/Q0M7O0M7O0c/O0c/P0c/Qz83NzcvLzcnK\r\n        zMnKzczOzczNzMvLzMrMzMrMzMvKzMvLy8rLzc3OzszMzcvLzs3NzMrMysnLzczNzMzMysjJyMbGysnI\r\n        ysnKycjJysjJycjIyMXFyMXGycjJzMzLycjIxsTFxMPEw8LCxcPEw8HCxcPExcLDxMLCw8HCwr/Awb6/\r\n        vry9v7y+wMDAv76+v7y8wb6/wL6/vbu8vbu8v729v729vbq7v72+vry8v769uLe4sbCwr6urraipr6qr\r\n        raioq6inq6in////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////i4eHi4eHjIiHioaHioaGkIqHkoyJjYiGi4iHi4iJi4iIjYqKkIyM\r\n        kI2NlI6NmI+KmY+ImI+MkY2Nj4uLkY2Mk4+Pk4+PkY6OkI6OkY6Oko+Pko+OlZKRlpOSlpOTlZKSk5GR\r\n        lZOSmJaWmZeWm5iYm5iam5ianJqanZuam5iZm5mam5qbm5mZnZqbnpubnpqbn5ydoJ6foZ+fn52dnJmZ\r\n        oZycoZ6eoZ+foZ+foZ6foJ6eoZ+foZ+fpKGhpaOhpKKgpqOjqKamp6WloqCgpKKiqKalqqamqKSlqaam\r\n        qqioq6ipqqipqqamramoraqqrKqrq6ipraipr6qqrquqrqqqr6yrrqqpq6iorqussq+vs7Cwsq+wr6ys\r\n        r6yssrCvtLGxtK+ws7Cws7GxtLGxs7CwtLGxtbKytbKzt7W0t7SztrOytrOzubW1ura3uLa2ure2vLi3\r\n        u7i4u7i4vru6v7y7vry8vb28u7m5vbq5vru6vrq6vbm5vru7wL29wLy8wb69wr69wL6+UE+JAABmAABm\r\n        AABmAABnAABnAABoAABoAABoAABpAABpAABqZWSXvru7paOihoODhoOD////////////////////////\r\n        ////////////////////////////////////////////////////////1NHR1NHRysfHyMPExsPDzczM\r\n        z87O09HR09HR0tHQ09HR0s/Q09HR0tDP0MzM1NDR1dLS1NDS1NLS1dLR1dLR1tPU1tTU1tTU19TU1tLR\r\n        2tXUsa7HEBCDAAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/////////////////\r\n        ////////////////////7uzs7uzs3NnZtbOz////////////////AACDAACDAACDAACDAACDAACDAACD\r\n        AACD////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////AAB9AAB9AAB8AAB8AAB8AAB8////////////////////////////////\r\n        ////////////////////////////////////////AAB2AAB2AAB1AAB1AAB1AAB0fHqv5OPi3t3e19TU\r\n        u7nHrqzEZWSjRkWUAABxCQl1AABxAABwAABwAABvAABvAABvAABuAABuAABuAABtAABtAABtAABsAABr\r\n        AABr////////////////////////////////////////////////////////////////////3drc3drc\r\n        1NHS1tPU1NLT09DR09HR09HT0M/Q0c/Q0M/Pz87Oz87O0M/P0dDQz83NzMnJzcnKy8fHzszNzs3NzMnK\r\n        zcnLzcrMy8jJy8jIysjIysjIysjIy8jIysfHxsTFxcLEycfIycfHx8bHx8bHx8XFx8XFxcTFxsPFx8TE\r\n        ycfGysjHyMfHycnIycbGx8LDxcLDw8HBw8HAwsDAw8LCw8HCwL6+wL+/wL+/vru8vLu8vru8v728wL69\r\n        wLy8wLy8vbu8uri5u7i5v729wL+/v729wb6+wL+/urm6qKaoqaOjsa2sr6qqsq+vs7GxtLKxtLKx////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////ioaEioaEjYiFioeGiYeHi4iIjomGj4uGi4iGiIaGh4SEioiHjYqJjouLkYyMlY6LlY6K\r\n        kIqKj4uLjomIkIuLk46Ok46PkI2Nko+OkY6NkY6OkY6Nko+OlJCQlpKSl5OTlZKRlpSTlpSTlpSTl5WV\r\n        mZaXmZeXm5iZnJmZm5mZmJWWmZaWmpeWnJmYm5iYnJiZnZqbn52doJ6dnpqanJiYnpuboJ6eoJ2dop+f\r\n        oqCgoJ6enpyboJ2dop6eo6CfoqCfop6epaGipqOjpaKipqOjp6WkqKWlqKWmqKSlqKSlqKWlqKWmqaan\r\n        qqanrKmqrKurrKqqq6iprKmprKmorqqpr6yrrqurraqqrqussa2usa6usK6usa6usq+vsq+us7Cvs7Cw\r\n        s6+wtLKytbKztLGytbKxtbOytbKytbKxtbKxtbGxtrKytbOztrOztrKztrKzt7OztrKzt7S0ure2u7i3\r\n        uri4vLm6vbq6vbq6vru6vru7v7y8vru6vrq6vbq6v728wb++v7y8gH6fCAhpAABlAABmAABmAABnAABn\r\n        AABnAABoAABoAABpAABpICB3wsC/u7m4raqqraqq////////////////////////////////////////\r\n        ////////////////////////////////////////0M3N09HR0M7O0M3N0M3O0M7P0c7O0c7P0c7O0c/O\r\n        0M7Nz8zM0M3N0c7O0s/P1NHR1NHR1NHS1dPT1dLS1NLS1dPT1dLS1dPS1dPS1dHR19LR19PSZWSlAAB8\r\n        AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB+////////////////////////////\r\n        ////7uzs7uzs3NnZtbOz09DQtLKy////////JiV+AACDAACDAACDAACDAACDAACDAACD////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////AAB9AAB9AAB9AAB9AAB8AAB8////////////////////////////////////////////////\r\n        ////////////////////////AAB2AAB2AAB2AAB1AAB1AAB1WlmexcTUpaXFV1ebPDuNAQFzBQV1AABy\r\n        AAByAABxAABxAABxAABwAABwAABwAABvAABvAABvAABuAABuAABtAABtAABs////////////////////\r\n        ////////////////////////////////////////////////////////////3drc2dbX1dPT1NLT09HS\r\n        09DR0tDP0c/Q0c7P0M/P0c7P0c/Q0M/Q0c/P0M7Oz83Oz8zNzsvLz8zMz8zMzsvLzsvLzcrLy8jKy8nJ\r\n        y8jJzMfGy8jHycfHyMXFyMXFyMbGyMXGyMTFycbGycbGycbGysjIycbGxcHBx8PDy8bGysbFx8TCxsLC\r\n        xsHBxsLCx8PDxcHAwr6+wr+/wb+/wL+/v7y8v7y9wcC/wL+/wL+/wcDAwb69wb6+vry7vru7v7y8vbq6\r\n        u7m5u7m6vLu7vry8w8HBw8HBvr6+q6qrqKGhsa2ss7CwtbOytbKxtLKx////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////hoKD\r\n        ioeGioeGiYaGh4eHhoOFj4qGk5GIjouHiIWFh4WFiIWFi4iHjIiIjYmKjoqKjouLjoqKjoqJjomIjoqJ\r\n        kIyMj4uLkI2Nk4+Ok5CPko+QkY+PkI2NkY2Nko+Ok5CPk5CQlJGRlpKTl5SVl5SVlZOTlZOSmJWVmpeX\r\n        mZeWmZeXmJWVmpaWmpiYm5mZmpiYm5mYm5mYnJmZm5iYm5iXm5iYnJmZoJ2coZ6foJ6fnZubnZqaoJyc\r\n        oJ2dop+goZ+fn5ycop6epKGhpaKjpqOjpqOkp6Wmp6Wlp6Wkp6OipqKhpqOjqKanqaaoqqeoraqqrKqq\r\n        q6ipqqiprKqqrKqqrKmqrKmrrausr6ysr6ysr62tsa6tsa6usK6tsq6tsq+usq+vsq6vtLGxtbKys7Gx\r\n        trOztrOztrKxtLGxtrOztrSztrSztrS0trSztrOztLGytLGytLKytrS0t7S0trO0uLW1uLa2ure3u7e4\r\n        vLm6vbu7vLu7vLq6vbm5v7y7vry7vry7vru7sKy1CAdoAABlAABlAABmAABmAABmAABnAABnAABoAABo\r\n        AABoAABpenmfw8DApaKipaKi////////////////////////////////////////////////////////\r\n        ////////////////////ysfH0M3N0tDPzsvLzMrKz83Nz83Oz8zMz8zM0MzM0M3Mz8zLz8vL0M3N0c7O\r\n        0s/O0tHQ09HR09LR1NLS09DR09HR1NLS09HR09HQ09DR0tDQ09HQ1tPSu7nIDAyAAAB7AAB8AAB8AAB8\r\n        AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB+////////////////////////////////7uzs6Obm\r\n        5uPk09DQtLKy09HRxsTFJiV+AACCAACDAACDAACDAACDAACDAACD////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////AAB9AAB9\r\n        AAB9AAB9AAB9AAB8AAB8////////////////////////////////////////////////////////////\r\n        ////////AAB3AAB3AAB2AAB2AAB2AAB1FRV/OzqSBgZ3AAB0AAB0AABzAABzAABzAAByAAByAAByAABx\r\n        AABxAABxAABwAABwAABvAABvAABvAABuAABt////////////////////////////////////////////\r\n        ////////////////////////////////////////////397d397d19XV1NLS1tTV1dPU09HQ0c/P0tDQ\r\n        0tDQ09DQ0tHR09HR0s7P0M7O0tHR0c/Qz83Oz83Nz87Nz87NzszNzcvLy8rKzMrLzcvMzcnIzMnIysnI\r\n        yMfHycjIysnJysjIycbHzMbFzsjEzMnHzcvLzMfHx8PDx8XFyMTExsHCx8PDx8HBxcHBxsXEyMbFxsPC\r\n        w7/Awb/AwL29wL6+wb/Awb6/wsDAxMLCwcDAwL/Aw8HBw8DAv729v729wL2+vby7vby7u7i4uba2vbu7\r\n        w8LCw8LCxMXFube4raOjsaemtbKws7CwtbCvtbCv////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////hoKDhoKDh4SEh4WFh4aGhYOE\r\n        hIGBi4aCjoqGiIaGiIWFhoSEiYaFioiHi4iIjYmJjouKjYiIjYmIjImIjIiIjoqKjYqKjYmJjoqKkY2N\r\n        kY6NkY6OkI2NkIyMkY2MkY6Nko6OkI2Nj4yMko6PlpOTlZOUlZOUlJKSlZOTlpOUlpOTlpSUl5WWmJWW\r\n        mpiYmpmZmZiYmJaWmZaWmJWWmZWWm5iYmZWWmZaWnpuboJ2dnJmanZqZnZqanZqbnJqaoZ6eo6CgoZ6f\r\n        oJ6eoZ+foZ6fo6GhpaKipKKipaKjpqOjp6OjpqOipqSkp6SlqaanqKenqqenq6eoqqanq6iprKqrq6qr\r\n        qqipq6mprampraqqrKqrrqyssa6tsK2tr6yrr6ursK2tr6ytsK2tsq6usrCvsa6vsq+wsq6us7CvtrOz\r\n        t7O0trOztbOzt7SzuLW0t7S0trS0trO0t7S0trOztrKztrKzt7W1t7S0trOzubW2ure4uri5u7m5vbu6\r\n        vry8v728vbu6vLq6v728v7y8Pz6AAABkAABlAABlAABlAABmAABmAABnAABnAABnAABoBARqjYuoura3\r\n        paKi////////////////////////////////////////////////////////////////////////////\r\n        ysfHysfHycbG0c7OzcvLy8jIzMrJzsvLzcrKzsvLz8zM0MvM0MzM0M3N0M3O0c7P0c/O0dDQ0s/Q0M3O\r\n        0c7O0c7Q0c/P09HR09HR0s/P08/Q09HR09HR1NHS1NHScG+pAAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9\r\n        AAB9AAB9AAB+AAB+AAB+AAB+////////////////////////////////////6Obm4N3d2dXV1dLS09HR\r\n        xsTFV1aZAACCAACCAACCAACDAACDAACDAACD////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////AAB+AAB+AAB+AAB9AAB9AAB9\r\n        AAB9////////////////////////////////////////////////////////////////////AABlAAB3\r\n        AAB3AAB2AAB2AAB2AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABxAABxAABw\r\n        AABwAABvAABv////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////397d29ra1tTU1dLT1NHT1NLS09HR09LS09HR0tDP1NLS1dPU\r\n        0tDQ0M7P0tDQ0tDQ0M7P0M/P0M7Pz83OzczNzcvMzcvMzszNzszNzcvLzszLzszMzMrLzMrKy8rKzcvM\r\n        y8nKycbGy8jGy8nHzMnJy8fIyMbHx8fHxcTFxsPFx8XGyMfGyMbGx8bGxsXExsXFxsTFxMLDw8HCw8HB\r\n        w8HBwsDBw8DCxMLDw8LDwL6/vr6+wL+/w8DBw8DBwL6+vrq7v729vry8vLm5v72+xMPCwb/Awr++vLe1\r\n        tquotqmmta6ts66tta6uta6u////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////g4KCg4KCg4CBhIKChoSEhoKDhIKBhIKBhIGAg4CA\r\n        hYKChoODhoSDiYWFiYaGi4iIjImIjIiHioeHioeHioeHjImJjImJi4iIjYqJjYuLj4uLj4uMj4yMj4yL\r\n        j4yMj4yMkY6OkY2NjYqKjouLko+Oko+Qk5CQlZGRlZKSlZKTk5CQlJGRlZOTlpSUlpSUmZeXmZaXmZaW\r\n        l5aVl5WWmJSUmJaWmJWVmJOUmpeXnJmZnJiYnpuaoJ6dnZubnpybnpyboJ2doZ6foZ+foZ6foJ2eop+f\r\n        oqCfoZ6fo5+ho6Chop+fpKKip6alqKamqKamp6Wlp6WlqKenqqioqqipq6mqqqipqaenq6inrKmpq6ep\r\n        q6ipq6mqraqrrqqqr6qpr6urrqurr6ussKussKysrqyssK2srqysr6yssa+vs7Cws7Cxs7CxtbKytbOy\r\n        tbKytbKyt7OytrOztrOzuLS1t7S0t7S0t7S0t7S0uLW1ubW1ube3ube3ura2ure3vLq5vbu7vbq7u7i5\r\n        u7m5vLm5jYujAABkAABkAABkAABlAABlAABmAABmBQRoAABnHx91TEuKu7i7s7Cwi4iIi4iI////////\r\n        ////////////////////////////////////////////////////////////////zszMzszMyMXFy8jJ\r\n        zMrKy8fIy8jIzcrJzcnJzcnKz8vMzszMzs3MzszMz83M0M/O0c/Pz83Oz8zMzsvLzsvL0M7O0c/P0tDQ\r\n        0s/Q0c7P0c/P0tDQ09DQ0tDQ09DQy8nOHx+IAAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB9\r\n        AAB+AAB+AAB+////////////////////////////////3tvc3tvc29ra29rZ4N7d3draioi2CAeFAACC\r\n        AACCAACCAACDAACDAQGD////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////AAB+AAB+AAB+AAB+AAB9AAB9AAB9////////////\r\n        ////////////////////////////////////////////////////AAB5AABlAAB3AAB3AAB3AAB3AAB2\r\n        AAB2AAB2AAB1AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAAByAABxAABwAABw////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////4eDg4eDg29ra19TV09DR1NLT09LS09HS1NLS0tDR09DR1NHR0tDQ09DR1NLS0tHR\r\n        0tDQ0c/Pz87Oz87Ozs3Oz87Oz87Oz87P0M7O0M/O0M7O0tHRz87O0M7O09HR1dPU0dDQzMrLy8nLycfI\r\n        ycfHysjJycfIyMXGxsTFxsXGyMbGx8XFyMbHyMbHxsPExcPDyMbHx8bHxcTFxsTExcLCxMLBxcPDxcPF\r\n        w8HCwL6+vLq6vr29w8HCxMLDwsDAwL29wL6+v729wb6/wr/BxsTFwr/Aw729w7y6wLq3vbWyubOyt7Cw\r\n        ta6u////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////gn5+hYODgoCBg4GBhIGBhYGBhIGBh4OCh4SDg4GBhIGBg4GBgoCAhICA\r\n        h4ODiIWFiIWFiIWFiYaGioeHi4iIjYmIjYiIiYeHiomJjIqKjoqKj4uMjouLj42MjouLjYqKjIuLjo2N\r\n        jouLj4uKkY2Mk46Nk46Ok4+QlJGSlZKSlZKSk46Pk4+Ok5CQlZKSl5SUmZaWlpSUlZKTl5SUmpaWmJKS\r\n        l5KRmJaVmJeXmJSUmpaVm5iYnZuanZuanZycm5qanZuboZ6foJ2dn5ycnp2doJ6eop6fop+foqCgop+g\r\n        o6ChpKKjp6WmpqSkpaOjpaOjp6WmqKanqaeoqKanqaenqqipqaeoqaenqqioqqeoqaanqqeoq6eor6mo\r\n        saqpr6qpraqqr6urtK6tsq6tsK6usK6urqysrqyrsK2tsK2tr6ysr6yssa2usq+usq+vs7CwtLCwtLKx\r\n        trOzt7S0tbOztbKytrOztrO0t7W1t7S0uLW1uLS0tbGxtrOyt7W1uba3uLa2t7S0uba2uLa2rqywGxtv\r\n        AABjAABkBQVmAABlGRlwMzJ8V1aNfXuelJGou7i6wb29t7S0npubhYOC////////////////////////\r\n        ////////////////////////////////////////////////0M3NzMnJxsLCx8TEy8jIzMjIysfHysfI\r\n        y8jIzMnJzcvLzszNzczLzcvLzszMz8zN0M3Nz8zLzcrKzMnJzcrJz8zM0tDP0dDP0c7O0s7P0c/P0s/P\r\n        0s/Q0s/Q0c7O0M3NhoWwAAB6AAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB9////\r\n        ////////////////////////////////3tvc3tzc2dbW2tfX2tfXubjMDAuGAACCAACCAACCAACCAACC\r\n        AQGDX16jrqyt////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////AAB+AAB+AAB+AAB+AAB+AAB+////////////////////////////\r\n        ////////////////////AAB6AAB6AAB6AAB5AAB5AAB4AAB4AAB4AAB3AAB3AAB3AAB2AAB2AAB2AAB1\r\n        AAB1AAB1AAB0AAB0AAB0AABzAABzAABzAAByAAByAABx////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////4eDg393d2dfX1dTT1tPU1NHS1NLS1tTV1dTU09HR09DR1NHS1NHS1NHR0tDR0tDQ0tDP0M3NzszN\r\n        z87O0dDP0dDR0dDQ0c/P0c/OysjJyMbHz87O0M7O09HR1dPU0dDQ1tXV09HSz8zNzMrKy8rKzMnJzMnI\r\n        ysfHycnIysnJysfIysfJycjIx8bFx8TFx8TFx8bGx8XGxsPExsPDxcPDxcTEw8HCw8DBwb++vLu6vbu7\r\n        wL29wsDBw8HCwr+/wb6+wb6+w7+/w76+xsTExsTEx8TEyMPDxL69vrm4urS1ubKyubKy////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////gn5+gn5+hIGAhYODhIKDg4CBgn+AhYGAiYOBh4SCgYCBhIODhIKCg4CAhIGAhoSEhYODhIGBhoKD\r\n        iYWFioeGiYaGi4iHi4eHioeHioaHioeHjImKjImJjYqKjYqLj4yMjoyMkIyKkouJkIqJjYqKj4uKk4uI\r\n        lo2LmI+Nlo6Mko+OkpCRk5CQkY6Oko+PkY6Ok4+QlZKSlZOTk5CRlpOTmZaVmZWVlpGRmJaWmJiXl5SU\r\n        mJSUmZaVm5mZnJucnpyenZqbn5ydoJ6eoJycn5ydn56goJ6eoqCgoqCgo6GhpaOkpKOkpKOjpaOjpqKj\r\n        pqKipqOjpaOjp6SlqKanp6Slp6SkqKanqKanp6Wmp6Wlqaamq6ioqKanq6alsq2rs7Gtr6uprKioramp\r\n        rqqqrqyrsK6vsa+vr6ysr6urr6yssa2ur6ysrqurrqqrr6yrsK6tsa+usa6usq+vtbKytLGxsa6vsK6u\r\n        srCwtLCxsrCws7GxtrKzt7OytbKxtbKytbKzs7Cxs7CxtbKyuLW1trOztbKxZmSQBARlSUiEWlmNiYih\r\n        joyju7i4s7C0vLi4vbq6vbq6vbq6vrm6sKyshYOChYOC////////////////////////////////////\r\n        ////////////////////////////0M3N0M3Ny8jIycbGyMTGycbGy8fHysbHysfHzMnIy8jIycfHy8rK\r\n        zcvLzsrKzcnKzMrKzsvKzcvKy8jIzMnJzcvLz8zM0M7O0M3Nz8zM0c7O0M7Oz8zM0M3N0s/P0c7Oz83M\r\n        zcrLJiaJAAB6AAB7AAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB9////////////////\r\n        ////////////////////3tzc3NnZ2dXW29jYwsHQHByMAACBAACCAACCAACCAACCAACCX16jrqyt1NDQ\r\n        ycbFsK2t////////////////////////////////////////////////////////////////////////\r\n        ////////////AAB/AAB/AAB+AAB+AAB+AAB+////////////////////////////AAB8AAB8AAB7AAB7\r\n        AAB7AAB6AAB6AAB6AAB5AAB5AAB5AAB4AAB4AAB4AAB3AAB3AAB3AAB3AAB2AAB2AAB2AAB1AAB1AAB1\r\n        AAB0AAB0AAB0AABz////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////4uDg4uDg29na\r\n        19XW2NXW1dTU19bW2NfW2NbX2NbX2NbW1tTT1dLT1NLS1NLS1NLS0tDQ0c7O0c/P0s/Q0s/Q0tLR0tHQ\r\n        0dDQz87Pu7u7yMbH////////////////////1tXV09HSz8zN09LT0M/PzsvKzMnJzMnJy8rKzMrKysjJ\r\n        y8jJy8nJycjIysjJysnIycfHycbHysjIyMjHx8XFx8XFxsPDwsDBwsHAv7y8wLy9wL6+wL+/wsHCw8HB\r\n        wsDAwsDBxsXExsPBw8HAyMXGysjIyMTFxsLCwr7Avrm6urW1urW1////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////f3x8f3x8fnx8\r\n        gH5+g39/g35+gX1+g4B/hoSCg4GBgoCAg4GBgoCAgn9/hIGBhoSEhYKChICAhYKBiYWFiYSDiISDh4SE\r\n        iIaFjoaEkIaEiYaFiYiIiYaGi4iIjImJi4iJjIqKlIqHl4qFj4mIjIqKjYmKkYiHmIuFmo6Ilo2KkI2N\r\n        kpCRlJKRk5GRkpCQkY6OkI2Nko+QlJKSlZOSlJGRlpOTmJSUl5SUlZOTlpOTl5SUmJWWmJaVmpeYm5ma\r\n        nZqcn5ycnpubnZubn5ycoJ6fnpydn5ydnp2dn56eoqCho6GioJ6foJ6eo6GhpaGhp6KhpaKhpqOjpqOj\r\n        pqKkpqKjqKSlqKamqKWmpqOlpKGip6Ojq6inqaenqaSjsKypsK+srKqpqqanrKmoq6ioq6iorKqprquq\r\n        r6urr6ursayssKysr6ysrqursKyssK2ssa+usK6tsa2tsq6us7Cwsq+vsa6usq+vsrCwsq+vsK2tsa+v\r\n        s7Cws6+vtrOyt7S1tbKzsrCws7CwtbO0t7S0ubW0uba2uLW2kY+jtrS1ure3ure4ubW2t7S0uba1ure2\r\n        u7i4vLm5vLq5v7u7trKzoJ6eoJ6e////////////////////////////////////////////////////\r\n        ////////////ysbGysbGycbFycfIycbHx8TFyMXFycbGy8nIy8nJysjIyMXFycfGzMnJzsnKy8nJysfH\r\n        zMjJzcrKy8jIzMnJzsvLzszMz8zNz8vMz83N0M3NzcvLzMrKz8zM0MzM0MzM0c7N0c7OkZC0AAB6AAB6\r\n        AAB6AAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB9////////////////////////////\r\n        ////////3NnZ3NrZ29nY1tXZSEifAACBAACBAACBAACCAACCAQGCRUWe19TU1NDQycbFsK2t1dPTyMXF\r\n        rqyr////////////////////////////////////////////////////////////////////////AAB/\r\n        AAB/AAB/AAB/AAB+AAB+AAB+////////////////////AAB8AAB8AAB8AAB7AAB7AAB7AAB7AAB6AAB6\r\n        AAB6AAB5AAB5AAB5AAB5AAB4AAB4AAB4AAB3AAB3AAB3AAB2AAB2AAB2AAB1AAB1AAB0AAB0AAB0////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////4uDg3drb19bW19fX2NbW2dfX\r\n        2tfX2NbW2tnZ19XU0cvK0s3O1tbW1tXU1dPU1NHS09HR09LT1dLU1NLS09HR09LSzs3Oz83PwcDBwcDB\r\n        ////////////////////////////////09LT09DQzMnLycfIy8nJy8rKysnJycfHysjIysjIycfHysnJ\r\n        zcvLzMrKysjHysjIysjHycfGycfHx8XGxMHDw8DBxMHAwr6/w7+/w8C/wb6+v72+wL2+w8HBxcPCwsHB\r\n        w8DByMXGy8nJyMbHxMHBxMDAxcLCurW1////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////enZ3fHl6enh4end3f3t6gn17fnp5\r\n        gH59g4GCgYCBgX59gX5+gH59gX9+gn9/hICAhYGBhoODh4WEh4SFiIODhoKBh4WFh4SFjIWCjYSBioWF\r\n        iYeIiYaGioeHiYeHh4WEh4WFjoeFkIiFjYqKjYqLjYuLjomJlIqFlYyHko2Nj4yNko+PlJOSk5GRkY+P\r\n        kI2Nj42NkY6PlpGSlpOSlJKSk5CQlpCQl5STlZOTlJCRl5OUlpSVl5SVmpaWmpiXm5mZnJqam5iYm5eY\r\n        nZqanpubnZubnZqanpybnpycnpydm5iZm5eXnZqaoJ6eoZ6eo56epKCfpKCgo5+go56fp6GgqKOipqOk\r\n        pKGhpqGhpqOjp6SjqKWkqKSlp6OkqKSkqaSkqKOjqqalq6inq6inqKWlp6WkqKSkqqalq6inrqqqrqqq\r\n        rKmorqqqr6uqr6yrsK2trqyrrquqr62ssK2tsq6us6+vtLCvsq+vsrCvs7Gws7Cwsq+vsa6vs7CwtrS0\r\n        tbOytrSztbOztbKztrOzuba2uba2t7S1t7S0tLKytrOzure2uLSztbGxuLa1u7m4u7i4vLm5v7u6wL29\r\n        vLq6rqurnZmY////////////////////////////////////////////////////////////////zMnI\r\n        x8PDx8LDxsTExcTDxsTDyMTEycjHycjHycfHysjIyMbGx8TEycbGzMrJysjHyMTEy8fHzcnJzcrJzsrL\r\n        zcrLy8nJzcvLz83Nz83NzszLzMrKzcvLz8zMzcrKzcrK0M3M0c3Oz8zNNTWOAAB6AAB6AAB6AAB7AAB7\r\n        AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9////////////////////////////////////39zc39zc\r\n        2NbV2dfXeXiyAACBAACBAACBAACBAACCAACCLy+V1NLX4N3c3dnZ2dbW1dPTyMXFrqyr1NHRx8PFrqus\r\n        ////////////////////////////////////////////////////////////AAB/AAB/AAB/AAB/AAB/\r\n        AAB+AAB+////////////////////AAB8AAB8AAB8AAB8AAB8AAB7AAB7AAB7AAB6AAB6AAB6AAB6AAB5\r\n        AAB5AAB5AAB4AAB4AAB4AAB3AAB3AAB3AAB3AAB2AAB1AAB1////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////4uDf4uDf3Nra29ra29jZ2tfY29jZ2dbX19fW1dPS\r\n        1M7O19TT2tnZ2NfX1dPT1dTU1dXV1dXW19XW1tTU09HS0dDRxMLCuba3wcDB////////////////////\r\n        ////////////////1dHS1dHSzcvMy8jJzMnKzMrKysjIysjIy8rJy8nJycfHysjHzMnKy8nJysjIycfH\r\n        ysfHycfIx8bGxsTFxcTFxcLDx8XFx8bGxsPExsHBxb+9wby7v7y8xcPDw8DBwL2+x8PDysfIy8nKxcTF\r\n        wr6/x8LCyMbFyMbF////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////enZ3enZ3e3h5end3e3h4e3l5fHl4e3l4fnt7gH1+f319f3x8\r\n        f318gH59gH19gX5+g3+AhYKChYSDhYODhoSEh4OEiISDiIWFh4SFh4ODiYSEiISEiIWFiISFiYaGiYeG\r\n        h4aEhoSEh4WFiIaHi4iJjYqLjIqJjYqKjomJj4uLjYuMjouLkIyMkI6Oj4yNjouMkI2NkY6Oko+Pk5CQ\r\n        lJGRk5GRkpCQko6NlZGRlZOSlpSTlpOTlZKTlZKTmJWVmZaVmJaWmJaWm5iYm5iYmZaWm5iYnZqanZub\r\n        npubnpucmpiYmpaWnJeXnZqanpubnpuboJyaop6doZ2dn5ydo5+epaCdo5+dop+go6CgpqCeqqOgpqKh\r\n        o6CgpqKip6Slp6KiqJ+eqqCfqaSjqaWlqKOjp6SjpaKip6Ojp6KjqKSkqaanqqeoq6inrKenraiorKmp\r\n        raqqrKiprKmprKqprquqr6ussK2ssa6tsa6utLGws7Cwsa6usa6usrCvsa6usq+vtbOytrSztrS0tbKy\r\n        tbOytLKxs7CvtbKzt7S0t7SztrKyuLSztrOytbGxt7S0uLa2u7i4vLm5vru6v7y8wL29t7S0nZmYgn9/\r\n        ////////////////////////////////////////////////////////zMnIzMnIyMXFxsLCxMLCw8HA\r\n        xcPDyMTFxsPEx8TEyMbGyMbGxsPDxsLDyMbFyMbFx8PExsPDycbGysfHzMnJzMrKy8rJycfGy8jIzszM\r\n        z8zMzMrKzMnJzcrKzcvLzcrLzsvLzsvLzsrLz8zMqqm+Cgp9AAB6AAB6AAB6AAB6AAB7AAB7AAB7AAB8\r\n        AAB8AAB8AAB8AAB9AAB9AAB9////////////////////////////////////39zc2dXV1tLToqDAAQGA\r\n        AACBAACBAACBAACBAACBAQGCwb/O29nZ3NnZ39zc4eDg39zc2tfW1NHRx8PFrqus1tTUxMLBp6Sk////\r\n        ////////////////////////////////////////////AACAAACAAAB/AAB/AAB/AAB/AAB/////////\r\n        ////////////AAB8AAB8AAB9AAB8AAB8AAB8AAB7AAB7AAB7AAB7AAB6AAB6AAB6AAB5AAB5AAB5AAB5\r\n        AAB4AAB4AAB4AAB3AAB3AAB2////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////4uDf4t/g3drb29nY3NnZ2dbX2NbW2NfW2dfX3Nvb3tzc29jZ19XW\r\n        1dPT1dTT1tXV19XW1tTU1dPT09LT1tTVw8DBuba3////////////////////////////////////////\r\n        19TU19TUzs3NzszMzsvMzcvMy8jJzMnKzMvLzMvLy8nJy8nKy8nKycfIycjIysjIycfIyMbIx8XGx8XG\r\n        x8bHx8fHyMfIy8rKycjJyMTEycTCyMLAxcHAxsPExsPExsHAysbEysjJyMXFw8DBxsLDycbGx8TEx8TE\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////dXFydXFyeXZ2end3e3h4end3end3fHp6fnt7fXp6fXp5fnt7fnt8fnt7f3x8gH19\r\n        gn9/goCAgoCBhIGBhYKChYKDhoKChoKBhYKBiIWFh4SFhoODhYKChoODhoOEiIWFh4WFiIaGioeHioeH\r\n        ioeIi4iIi4mHi4iIi4iKi4iJi4iHi4iIjYuLjYmJjIiKjouMkI6PkY+OkI2MkI2Nko+Pk5CQkZCPkY+P\r\n        k4+QlZKRlpSTlZSUkpCRlJGRlpSTmJaXlJKTlZGRmZaWmpeXmJWVmpiYnJmZm5iYm5iZm5iYmpeXmpeX\r\n        nJmZnJman5uboZybpZ+bpZ+co56dop6do6Ceop+en5yboZ6eo6Cgpp+eqJ6cpZ6doJ2eo6CgpqKiqqOi\r\n        raOgq6KgqKKip6KiqKOkqKWkqKWkp6SjqaSlqqanqaamqaamq6ioq6inrKmpraqqrKmoramqramqrKqp\r\n        rKmpraqqraqqraqqr6yssq+vsKysrKioraqqr6ysr6ysr62tsa+vsrCvs7GxtbOzsq+vr6yrsK2stLGx\r\n        trOzuLW0trSztbKyuLW1uLa2trOztbKyuLW1u7e3ure3u7m5vru8vLm5rquqgn9/gn9/////////////\r\n        ////////////////////////////////////////ysfIysfIx8PDxcPDxMLCxcLCxcLDxcLCwr29w8DA\r\n        x8bFxsLCxMHBxcLCxsXExMHBxMDBx8TFx8XFx8TDycbGycfHysjIy8jIy8jIzcrKzsvLzMnKysfHysfH\r\n        zMnJzcrKzsvMz8zMzcvLzsvLz8zMWlmeAAB5AAB5AAB6AAB6AAB6AAB7AAB7AAB7AAB7AAB8AAB8AAB8\r\n        AAB8AAB9AAB9////////////////////////////////29jZ29jZ2NXWwL/NHx+MAACAAACBAACBAACB\r\n        AACBCQmFmZe92tfY29jZ29jY3NnZ3dvb4N7d4t7e3Nna2dbX1tTUxMLBp6Sk0tDPwr+/qqam////////\r\n        ////////////////////////////AACAAACAAACAAACAAAB/AAB/AAB/////////////////////////\r\n        ////AAB9AAB9AAB8AAB8AAB8AAB8AAB7AAB7AAB7AAB6AAB6AAB6AAB6AAB5AAB5AAB5AAB1AAB4////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////4+Hi4+Hi3Nrb2NbW2tfX2NXW19XU2NXV29nZ3t3d29na19TV1tPU1tTU1tTU19TU1tPU\r\n        09HR1tTU0c/Qz8zNw8DBuba3////////////////////////////////////////2dfX2dfX0c/QzcvL\r\n        zszNz83PzcvMzcvMzMvLzMrKzcrMzcvMzMrLycfJysjIy8rJycjIycbHysfIyMfHycjJy8rLysfIysfI\r\n        ysjJyMXEycTDysfGycbEx8TDycXFy8fGy8jIysjJxcLCxcLCysfIyMXHx8TE////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        hYSEcW5udHJxd3R0eXZ2eHV1eHV1e3h4fXx8fHl5e3h3fXp6fXp7fXp6f3x8f3x9f3t8gHx8gX5+hIGB\r\n        g4CBg3+AgH5+gX59gn59hIKBhYODhYGBhYKCg4CAhIGBh4ODiISFh4WFiIaGiYWGioeHioeIi4iIioaH\r\n        iYeHioeHiYaGioeHioiHi4mIjYmJjYyLjYuKjYqLjoqLkI2Mko+OkY6Oko+QkY+Qko+Qk5CQlZGSlJOT\r\n        k5GRko6OlJGRl5WVlpWVk5GRlJGRlZGSlpOTmZeXmpiYmpeXmpeXmpaWmZaVmpeXm5iZnZqanpqbo5+d\r\n        pqGepqCdpaCco6Ccop6co52cop2cn5yboZ6doZ2eo52dpJ6dop6eoZ6epaGgpqGgqKGgp6OipqKipqOj\r\n        qKWkqKalp6WkqKWkqaWlqaWmqKSkqaemq6ioq6moq6mpq6ipq6ioraqprqurramqrKmprKmqrqqrrqqr\r\n        r6ysrqurraqpq6ioq6mprKiorampr6ysraurraursK2ts7Cws7CwsrCvsrCvsrCvtLGwtbKytrOztrS0\r\n        uLe3urm5uLa2tbKytLGxuLS0ube2t7S0uLW1u7m5s7KymZeXmZeX////////////////////////////\r\n        ////////////////////////z8vLxsTExMDBxMLBxMHBw8DBw8HBw8DAwb28wb29xMLCw8DAxcHCxcLC\r\n        w8DAwb6+wr/AxsTExsPDxcLCx8TEycbGysfIzMjKzMrKzMvLzcvKzMnJysfHyMXFycbGysjHzMrJzsvL\r\n        z8zLzsvMzsvLr6y/CQl9AAB5AAB5AAB6AAB6AAB6AAB6AAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB8////\r\n        ////////////////////////////4N/f4N/f3tzd1dPTOTmVAACAAACAAACAAACBAACBAQGBcnGt2NbW\r\n        2dbW2tfX29nZ3Nra3Nna3dnZ2tnY3dvb4d7f3Nnb1tXU0tDPwr+/qqam0tDQwb/Aqaeo////////////\r\n        ////////////AACAAACAAACAAACAAACAAAB/AAB/////////////////////////////////AAB9AAB9\r\n        AAB8AAB8AAB8AAB8AAB7AAB7AAB7AAB7AAB6AAB6AAB6AAB5AAB5AAB1////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        4+Hi4eDg2dfX19XV2tjY29jZ1tPT2NXW3tzd3Nva2NfW2NbW2NbW2NXV19XV1dLT1NLT1dTUx8XGz8zN\r\n        ////////////////////////////////////////////////////2dfX0c/Qz8zN0M3Oz83Oz83Ozs3N\r\n        zcvLzMrKzcvMzszMzcvLy8nKzMnKzMvLysjIysfIy8jJysnIysrKy8nKycfIycjIysfIysTFycTDx8bF\r\n        yMbFycbFysjIx8bHzMvMzMnKycXFxsLCx8TEx8PEx8PE////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////hYSEhYSEenl5dXJxd3R0\r\n        d3V1d3R0d3R0end3fHp6e3l5eXZ2fHl5fnx8f3x8fnx8fXt7fnt6f3p7gHx8gH19gH19gHx8f318gH18\r\n        gH19gH59gn9/hoKChYKChIGBhIGBh4ODh4SFhoSEhYODhoOEh4SDh4WFiIWGiIWFiYaGioiHioeIioeI\r\n        i4mJjImJjImJjImIjYqJjYqKjouLkIyMkI2NkIyMkI2Oko6PkY+PkY6PkY6PlJKSlJGRko6Oko+OlZOT\r\n        l5aWkpCQj4yMk5CQl5WVmZaWmZeXl5SVmJWVm5aWmpWVmZWVmZeWmZaWnJman5ycop6eoZuaoZyZoZ+d\r\n        oZ6dop6doJ6dnpuan5qboJ2do5+eqKKepZ6coJycoJ6eoZ6doJ6eo6CfpKGgpaGhpqOipqOjp6Ojp6Ok\r\n        qKWlp6Skp6SkpqOjp6SkqKWlqKamqaanqqemqqenq6inq6inrKiorampraqprqurrqurrqqqrqurr62t\r\n        rqurrKmprKmpraqpraqqraurr6ussKyssq+vs7CwsrCvsa6usa2ts6+vtLGxtbKytbOyt7a2uLe3t7O0\r\n        tbGxt7Ozure2uLWztbKxuba2u7m5oqCgpaOk////////////////////////////////////////////\r\n        ////z8vLz8vLyMTExMHBwr+/wb6+wb6/wr+/wb29wL69wb+/wb+/wr+/xcHCxcLCwb69vLi4wL6+xMPC\r\n        xcLCxMLCxcLCx8XEycfHycfIycXGycbGycbGyMbGycfHycbGx8TEyMbGy8nJzMnKzMnKzMrKzcvMzMnK\r\n        c3GlAQF4AAB5AAB5AAB5AAB6AAB6AAB6AAB7AAB7AAB7AAB7AAB8AAB8AAB8AAB8////////////////\r\n        ////////////////4N/f4d/f2NXVf3yvAACAAACAAACAAACAAACBAACBQUCZ0tHT2NfX2tbX2tfX2tjX\r\n        2tfX2tfX2dbW29nY3drb3Nja3drb3tzb2tfW19TU0tDQwb/Aqaeo0dDQvb29pKGi////////////Cwpu\r\n        AACBAACAAACAAACAAACAAACA////////////////////////////////////AAB9AAB9AAB9AAB8AAB8\r\n        AAB8AAB2AAB7AAB7AAB7AAB6AAB6AAB6AAB6AAB6////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////5uPj5uPj3tvb29nZ\r\n        3dva3dzc29ja29jZ3tzc3tzb2dfX19XV19XV19TU19TU19PU2NbX1NLStbO0tbO0////////////////\r\n        ////////////////////////////////19XV19XV0tDR0s/Q0c/P0c/P0M7O0M7Oz87OzczMzsvLz8zM\r\n        zcvMzMvLzszMzszMzMrLy8nKysfIy8jJy8rKysjJycfIysjIy8jJy8fIyMbHyMbHyMfHysfJycfIx8bH\r\n        zcvMzszMx8LCw7y7xr++x8LCx8LC////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////lJOTlJOTlJOTjoyNhIKCfHl4d3RzeXd3eHV2\r\n        eXZ2e3l5fHp7e3l5fXp6fXp6fnx8f35+fnx8fnt7f3t8f319fnx8fXt6fXl5fnt7gH18gX5+gX5+g4CB\r\n        hIGBg4GBg4CBhIGBhoSEhYODhIGBhIGBhYKChYKCh4SEh4SEh4SEiYaGi4iJjImKjImKi4iIiYaFi4eH\r\n        jImJjIqKi4mJjoqLj4uNj4yMkI2NkI2Mj4yNj42Oko+Pk5GRlJGSk5CQlJGRlZKTlZOSj42Mj4uLk5CQ\r\n        lpSTl5SVl5SVlpSUlpOTmJWUmpaWl5SUk5CQlpOTmpiYnZmYn5iXnpmYnJiYnZqanpqboJycoZ+eoZ6e\r\n        oZ6doJ6dop6cpJ6co56boJyan5ycoJydop+fop+foZ6dn5ucop6epaKhpqOjpqOkp6Skp6alpqSkpaGi\r\n        o6CgpKGhpKCgpaKipqOip6Sjqaalqqinq6enq6enramorKioq6inq6moraurrKmprKqpraqqrKqqrKmp\r\n        rauqr6yrrquqsK2tsa6usa6usa6usa6us6+vsa6ur6ysr62ssa6us7Gxt7a2uLS0uLSzuLW1uba2ure3\r\n        t7S0tbGyvLi5uLa2paOkpaOk////////////////////////////////////////////////z8vLx8TD\r\n        xMDAwr+/wr6+v7u7v7u7v7y8wsDAw8HAwb69w7/Aw8HBxMHBxMDAwr69wb6+w8HBw8HBw8DBwr+/xMHB\r\n        yMbFyMfGyMfGycXFyMTEx8TEycbGysfHycfHycbGy8jIzcnJzMjJzMnJy8rJzMnJy8nJLi6KAAB4AAB5\r\n        AAB5AAB5AAB6AAB6AAB6AAB6AAB7AAB7AAB7AAB8AAB8AAB8////////////////////////////////\r\n        ////4d/f3drZrKrDCwuDAACAAACAAACAAACAAACAHx6NxMHM2dXW2NXV2dbV2tfX2tfX2dbW2dXV29jY\r\n        3dvc3drb29na2dfX2tfW3dvb4eDh3dzd2NXW0dDQvb29pKGi0tDQt7OzkY6XCwpuAACBAACBAACBAACA\r\n        AACAAACAAACA////////////////////////////////////AAB9AAB9AAB9AAB8AAB8AAB2////AAB7\r\n        AAB7AAB7AAB7AAB6AAB6AAB6////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////5uPj5eLi4d/f3dzb29nZ3Nra3Nrb\r\n        393e4N7e2tbX2NXV2NXV2NTT29bW2tjY2dfW0c7OtbO0////////////////////////////////////\r\n        ////////////////3Nrb3Nrb1dLT09DR0tDQ0dDQ0M/P0M/O0M7OzszNz8zMz8zMzMvLzcvLzMvLy8jJ\r\n        y8jJysnJysjJy8jJzMrKy8nKy8jJysfIysjIy8jJy8jIysfIycfHyMfHysfHzMrKz87OzMrKwru6wbe2\r\n        yL68x8LC////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////lJSUlJSUlJOTlJSUlpWWlZSVjoyMhYODe3p6d3V0fHl5fHt7e3l6\r\n        end3e3d3fHl4fXp6fXp6fXt7f3x8gH5+gH9+fXt6fHl5e3l4fnx7gH19gH5+gX9/gn5+gX5+f3x8gH1+\r\n        gn9/gn9/g4B/hoODiIWFh4WEhoSDh4SEhoOEh4SEh4SEioaHi4iIiIaFh4WFiYaHiYeHiIWFioeGjIqK\r\n        joyMjoyMj4uLkI2NjouMjYmKjouKkI6NkpCQkpCRkpCQlZGRkY6OjouKkY2Nk5GRk5CQlZKSlpOTlZKS\r\n        lZKTlpSUmZaWmJSVlJKSlpSTmpiXmZWVnJeWnpqZnJmZmpeXnZmYnZqanpybnpycoJ6dop+gop6doJua\r\n        n5uan5yboJ2doZ6eop+fop+fop6doZ2doZ6do6Cgo6GhpKGhpaKjpqSkp6SlpaKipKGgpKCgpaGipaOi\r\n        p6SkpqOipqOjp6SjqKWkqqanrKioq6enqaalqqinqqenqqenqqiorKqqrqurrqurraurrKipraqqr6ys\r\n        raqqrampsa6usrCws7GxsK6urKmprqyrsKyssq+vtbKztrOytbKyt7W0uLa2uLa3t7W1qqanm5iZuLa2\r\n        paOkpaOkpaOk////////////////////////////////////////////xsTExsTEw7+/wL29wL29v7u7\r\n        wLy9w8HBxMPCwb++wb28wsC/wb+/wb6+w8DAxcLCwsDAwL69wL69wL29wb6+v729w8DAx8TEycfHycfH\r\n        yMXFyMXEyMXFysfHy8fHycbGysfHysnIysfHysbGyMXFx8XFycfHjoyvAAB4AAB4AAB4AAB5AAB5AAB5\r\n        AAB6AAB6AAB6AAB7AAB7AAB7AAB7AAB8AAB8////////////////////////////////29nZ29nZz83S\r\n        MzOTAAB/AAB/AACAAACAAACADAyFrqvE1dLS19XV2tjX2tfX2NbW19XV2NTU29jZ3dzc29nY2NXV2dbX\r\n        29jY2dbW19TU2tjY397e4N7f3dzb3Nvb0tDQt7OzkY6XFxZ/AACBAACBAACBAACBAACAAACAAACA////\r\n        ////////////////////////////////////AAB9AAB9AAB9AAB9AAB9////AAB7AAB8AAB7AAB7AAB7\r\n        AAB6AAB7////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////6Ofn6Ofn5eTj4N7d3dra3tvc393d3tzd3dvb2tjY2tjX\r\n        2dfX2dXV2tfX2tjX2tbXy8nJy8nJ////////////////////////////////////////////////////\r\n        ////3Nrb1tTU0tHR09LR09DR0M3P0c/P0tDQ0M7Pz83Nz83MzszLzMvLy8rKy8nJy8jIzMrKzMvLzMrK\r\n        zMrKzMvKzcvLzMrLzMrKy8nJysjIysfIysjIysjHzMrKz83N0c/Py8jJw7q5xbq3x767x767////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////lJOTlJOTlJOTlJSUlZWVlZSUlJOUlJOTlJSUjYyMhoODgH9+fXp7e3h5enZ3enh4e3l5\r\n        fXl6fHl5fXp5fnx8gH59gH1+fHp6e3h4fXl5f3x8fnt7fnt7fnt6f3x8gH19gH5+gH19gn5+hYOChoWE\r\n        hYODhIOChYSDhYOCh4SEhoSEhoODhoODiIWFhoSEh4OEh4SFhoSDiYSFioeHi4qJjIqKjYuLjYqKjoyM\r\n        joqLjYmJjYqKj42MkI6Oj42OkY6NkY+OkY+Pj4yMkY6Ok5GRlJKSlZKSlpOTlZKTlJGRlZKTlpSUmJaW\r\n        mJaWmZaWl5WUlZKSmJWUnJmXm5iXmpeXnJiXnpmYm5mXmpiZnJmanpubnJqZnZiXn5mZn5ycoJ2dn5yb\r\n        oZ6doJ6eop2dn5ubn5ycoJ2doZ6doZ6dop+fo5+gpKGhpaOipKKhpqKipaOjpqWkp6Wlp6OjpqKip6Sj\r\n        qKWkqaWmqqenq6iorKioqqanqqinq6enrKmprKqqrKmpq6ioq6iprKmprqurrauqqqemq6insK2ssa6t\r\n        sK6tsK6tr62sr62tr6yssK2ssq+ws7CxtLGxtrSzuLa2ure3vLm5oZ+gm5iZ////////////paOk////\r\n        ////////////////////////////////////////z8zNz8zNx8TFwb+/vru7vru7wL29wb+/wb+/wb69\r\n        wr6+wL28v7y8wb29wb28wr+/w8HBwb++v7y8wL29wr6+vry8vry7xMHBxsPDxcPDxsPDx8XFx8TFycbG\r\n        ycbGyMTFyMbGyMfGyMXFyMXFxsPExsTDx8TEx8TENTSLAAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6\r\n        AAB6AAB7AAB7AAB7AAB8AAB8////////////////////////////19XV19XV19XUa2qoAQF/AAB/AAB/\r\n        AACAAACAAACAb26r0dHQ1tXV29fY2tfW2dbV19TV2NbW3dvc3tvc2tfX1tPT19XW2tfX2dbW1dLS1NHR\r\n        2NXV29jZ39zc5uPj5OPj1tTUtbPAJyeIAACCAACBAACBAACBAACBAACBAACB////////////////////\r\n        ////////////////////////AAB9AAB9AAB9AAB9AAB9AAB7AAB8AAB8AAB7AAB7AAB7AAB7AAB7////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////6Ofn4+Li4d7f4uHh4+Hh39zd2tjZ2tjY29jY2tjY2tjY2NbW2tjY19TV\r\n        1tPU0M7P0M7P////////////////////////////////////////////////////19TU19TU0tHR0tHR\r\n        1NLR09DR0s/Q0c/P09HR0tHQ0c/P0M7O0M7OzczLy8nJy8nKzMvLzMrKzMnJzcvLzczMzczLzszNz83N\r\n        z83NzczLysnIysjIy8nJzMvKzszMz8zN0s/PzMnJycC+y8C+xr68xr68////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        lJOTlJOTlJOUlZOTlZOTlJSUlJSUlZSUlZSUlpWWlpWWj42OhYODfXt6end3e3l6fHl6fHl5e3l5e3h4\r\n        e3h4fHt7fHp6fHh5fHh5fXp6fnt7fXp6fXt6fnx8gH5+gH5+gX5+hYKBhoSEg4GBgn9/goB/hIKChYKC\r\n        hoKDh4WFhoSEhoSEh4SFh4SEhYKChYODiYeHioiIiYeHiYaHioeHiYaGjIqKjYyMjoyMjouLjYuLjIuK\r\n        jouLj4uMkIyNkI6Nj42Nj42NkI2Nk4+Pk5GRlJKSlJKSlZKTlJKSlJGSk5GRlJKSl5SVmJaWl5SUlZKS\r\n        l5OSmZWTmpWVmZaWmpaVmZSSmZaVmJWWm5aXm5eWmpeWm5aWnZmZnJqanZqanpubnpqanpqbnpqaoJyc\r\n        n5ydn5ycnpuan52coZ+eoZ2doJyboZ6do6CfpKGhpKKio6ChpKKhpaKipqKjpqKjpqSjpqOip6Skqaam\r\n        qqenq6enq6inq6morKmnq6inqaamqqenq6iorKmpraqprauqrauqrampramqraqprKmorqyrsK2tsK2t\r\n        sa6urqyrraqqsa2ts7Gxr62tsrCwure3w8HBoZ+g////////////////////////////////////////\r\n        ////////////////////////////z8zNz8zNxcPEvru8v7u8vru7vbq6v7u7wb2+wL29v7y8vru7v7y8\r\n        vry7vry7wr+/xMHAwr+/wsC/wr+/wL29vbm5vry7wr+/xMDBxcHCxMHCxcLDxsTDx8XEyMbGycbGyMXF\r\n        x8TEx8XFxsTDxsTCxsPDxsPDrKm5DQx8AAB4AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6AAB7AAB7\r\n        AAB7AAB7////////////////////////////29jY29jY19XUtLLFAQF+AAB/AAB/AAB/AAB/AACAKyuR\r\n        09HR1dPT19TV19XV2dbW2NbW2NbW2dfX2dfW2NXU19TU2NbW2NXV2dbW19TU1NHR1dLS2tfX3NnZ3dna\r\n        3tvb3tzcz87OJSWKAACCAACCAACBAACBAACBAACBAACB////////////////////////////////////\r\n        ////////////AAB9AAB9AAB9AAB9AAB9AAB8AAB8AAB8AAB8AAB7AAB7AAB7////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////5uPj5uPj4d7f4t/g4d/f3NnZ2dfY2tjY2tfY29fZ3dnY29nZ3Nvb1NLSvbu70M7P////////\r\n        ////////////////////////////////////////////////1tTU1tTU09HR09HR1dPT1dTT09HR0c7P\r\n        0M7Oz83MzcrKzsvMz87O0M/O0M3NzcrLzszMzszMzMjJzsvLz83NzszMzsvMzszMzs3MzszLzcrKy8jJ\r\n        y8nKzcvLz83Nz83O09DRzsvLz8bFzcbFxr68////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////lJOTlJOTlZSUlJOT\r\n        lZSUlZWVlZWVlZWVlpaWlpaWlpaWlpaWlpSVlZWVjYyMhYODfHp6eXd3e3l5enh4eXZ2eXd2e3h5enZ3\r\n        eHV1end3fHl5fXp6fnt7fnt8fnx7f3x8gH19gX5/f319f3x8g4CAg4CAgoCAg4CBhYKChYKChYODhIKC\r\n        hoOEhoSEhYKBhIGCh4WFiIeHh4WGiIWGh4WFhoSEioeHjYuLjIuLjYuLjYuLjIqKi4iJjYqKjouMj4yL\r\n        jYuLjouLkI2NkY2NkY+PkI6OjYuMj4yMkpGQk5CQko+Pko+Qk5CRlJKSlJGSlZKSlpKSmJSTmZWUmpaW\r\n        mJSTlpOSl5WVmJaWmZaVmpaVmpaVm5iXm5mZmpeXmZaWm5iZnJmZnJiYnpqan5ycn52cnpybn5ycnpyc\r\n        oZ2boJycn52doZ2dop2eop+gop+foJ2eoJ6eoqCgo6Cho6Cho6Cgo6Gho6Cgo6CgpKGhpqOiqKSkqqam\r\n        qaamqKSjqaamq6moq6moqaamqqanqqinq6qpq6ioq6eorKioq6iorKmpraqqsKyssq+ur6ysrKmpsq+u\r\n        srCvnZqasrCw////w8HB////////////////////////////////////////////////////////////\r\n        ////////////////z8zNxcLDv7y8vrq7vbq6vru6vru6vru7v729wL6+vry7ure3vLq5vbu7v7y8wr6+\r\n        wsC/wsDAwsDAw8DAwL29vbm5wL29xcPDxMHCw8DAw8HBxcPDxMPCxsTDxsPDxsLDxsPDxsTDxcLCxMLB\r\n        xMLCxsLCxsPDYWCdAQF3AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6AAB6AAB7AAB7AAB7////\r\n        ////////////////////29jY29jY2tfX1tTUMC+RAAB+AAB/AAB/AAB/AAB/GhqKu7nI1NHR09HR1NPS\r\n        1tTU1tTU1dPT09HR0c/P1NHQ2NbV2djY19bV19XV1tTU2NbV2tjX2tjX2dfX2NbW2tjY29jYwb/FERGF\r\n        AACCAACCAACCAACCAACBAACBAACB////////////////////////////////////////////////////\r\n        AAB9AAB+AAB9AAB9AAB9AAB8AAB8AAB8AAB8AAB7AAB7////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////5uPj\r\n        5uPj49/g3tvb29nZ3Nra29ra29nZ3dnZ3dnZ3dra2tjZx8XFvbu7////////////////////////////\r\n        ////////////////////////////////19TU19TU1tTU1dPT1tTU1dLT09DR09DR0M/PzMrKzcnJ0M3N\r\n        0c/Q0c/Q0c/P0M3N0c7O0c/Pz87PzszMzszLzcrLzMrLzMrKzMrKz8vLz8rLzcrLzcrLzszMz8zNz83O\r\n        0tHR0c7OzsnJycXFycXF////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////lZSUlJOTlZSUlZWWlpWVlpWV\r\n        l5aWl5aWlpaWlpaWlpaWl5aWl5aXl5WWlZWVjYyLgoGBe3l5eXd2end3eXd3d3N0d3NzeHV1eXZ2enZ2\r\n        fHl5fHh5fXp5fnp6f3x8fnt8fHl6fHl5f3x8fn18gX5/g4CAgoCBgoCAg39/hICBg4GBhIGBg4CAhIGB\r\n        g4GBhoODiIWFh4WFiIaGiIaHiIWFiYaHioeIioiIjIqLjIqLi4iJioiIjImJjYqJjYmKjoqLj4yMkI2N\r\n        kI2NkI2OjYmKjYmJjouLjouMkI2Nk5GRlJGRko6Oj42Nko+PlZKRl5KSmJSTmJWUmZaWmpeXmpeYmJaV\r\n        mJWVl5WUm5aVm5eWmpmYmZaWmJWVmZaWm5eXmpeXm5iZnZqanZuan5ucn5uboZuaopuYop6doaCgoqCg\r\n        oZ6doZ6eoqCgo6Chop+fop6fo6Gho6Gho6Gho6GhoZ+fnpycoJ2dop6epKKhpqOjpqOjp6OkqKWmqaen\r\n        p6Wlp6OkpqOjpaOip6Wkqqioqaenqaamqqamqqinraqqr6yrsK6tsK2uraursK2trKqpnZqa////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        xsLDxsLDv7y8u7i4u7m5uba3tbK1mJaqq6q0wL6+vby7u7i3u7i4vLq6vLq6vru8v729wb+/w8DAxcPD\r\n        w8PCwL2+wby9w8HBw8LBwr+/w8DBw8LCw8LBwb++wb+/wsDAxMHAxMHBw8HBxMLBxcLCxMDBxMLBs7G7\r\n        EBB9AAB3AAB3AAB4AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6AAB7AAB7AAB7////////////////\r\n        ////////////2tfX1NPSfn2vAAB+AAB+AAB+AAB/AAB/AgKAiom009DQ0tDP0c/O0tDQ0c7O0c7O0s/P\r\n        0c7O09DQ19bW2NfX19bW2NXV19XV2tfX3NnZ2dbW2NbW2tnZ29rZ3NrasK7DHh2KAACCAACCAACCAACC\r\n        AACCAACBAACB////////////////////////////////////////////////////////AAB+AAB+AAB9\r\n        AAB9AAB9AAB9AAB8AAB8AAB8AAB8////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////6ufo6ufo5uTk4+Hh4N7e\r\n        3t3c3dzc3dva3dnZ29jZ3Nrb19XWsrCxsrCx////////////////////////////////////////////\r\n        ////////////////39nX39nX2tbW19XW1tTU09HR09DR1dPT09LS0dDQ1NLS1dTT1NHT0s/Qz83N0c/Q\r\n        1NHS0tDQ0M/Pz87OzszMz8zNz83OzcrLzMrKzszM0M3Oz83Nz83Mz83Nz87O0M/P09LR0c/PyMbFxcHC\r\n        xcHC////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////lZWWlpWVlpWVlpWVlpWWlpWVlpWV\r\n        l5aWlpaWl5aXl5WVlpWVlpWVlpWVlpWVjIqKg4GBend3dXJzeHR0eXZ1dnR0dnJyeXZ2e3h4fHl5fnp7\r\n        fnt8f319fnt8fHh5e3h3fHp5fnt7gH1+gX9/gn9/g39/g3+AhIGBhICAhYKChoSEhIODhIKChoOEiIWF\r\n        iIaGiIaHh4aGh4WGiYaHiYiIioiJi4mJioiIi4iIjImJjYuLjYqKjoqKjYqLjYuMjo2NkI2OkY6Oj4yM\r\n        jYqKjoqKkI2NkpCOlJCOkI2Mj42Nko6Ok4+QlZGRlZGQlZKSmZaWm5eYl5SVlpSUlpOTmJWUmJWUmJWV\r\n        mZeXm5iYmpeWm5iYm5eXmJWVmpaVnpqYnJmZnZmboJuaopuZoJuan5uaoZ2coJ6doJ6eoJ2doZ+eo6Cg\r\n        pKGgpKGhpaKipaKipKGhpaOio6KhoqCfoZ6eop6eoqCgoqGgo6GhpqOjp6SlpaOjpqOjpqOjpqOjpaKh\r\n        p6SkqaenqKemqKWlqaWmqaWlrKiorquqrq2sr6+uraurq6enmZaWdnN0////////////////////////\r\n        ////////////////////////////////////////////////////////////////y8fIy8fIv7y9uLa2\r\n        l5WmamiVLy59JCR6QD+Fp6Wxvbq6v728vry7vLi5vLm5vbq6v7y9v729wsDAxcLDxMLDw8DAwr6/w8DA\r\n        wsHAwb6+wr+/wsDAwcC/wb6+wL69wb+/wr+/wsC/wcC/w8DAxsLCxMLBwsHAv729cW6fAAB3AAB3AAB3\r\n        AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6AAB6AAB6////////////////////////////zcvL\r\n        0M7Nqqa9BweBAAB+AAB+AAB+AAB/AAB/NzaU0tHQ0c/Oz8zM0MzNz8rLzsvM0tDQ1tPT1dPT1dPT1tPT\r\n        2NXV2dfW2dfX2NbX2dbX2dbW2NbV2dfX2tjY3dravLnJHh6KAACDAACDAACCAACCAACCAACCAACC////\r\n        ////////////////////////////////////////////////////////AAB+AAB+AAB+AAB9AAB9AAB9\r\n        AAB8AAB8AAB8////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////6ufo6Obm5uPk4t/g397d3t3c3tzb3dra\r\n        3Nna3t3d1NHRsrCx////////////////////////////////////////////////////////////////\r\n        493b493b2tbX2NXW19bV1tXU1NLT1NLT1NPS1tTU19TV1dPT1NLS1NLR0M7O0s/Q09HSz83NzszL0c/P\r\n        0tDQ1NHR09HSz83NzsvL0M3O0M7Pz83Oz8zMzszM0c/Q1NPS1tTU0M7OyMTDxcHC////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////lpWVlpWWlpWVlpSVlpSVlZWVlpWWlpWV\r\n        lpWVlpWVlZWVl5aWl5aWlpaWlZSUi4mJgX5+eXZ2d3R0dnNzend3e3h4e3h4fHl6fXp6fXt6f319f3x8\r\n        f3x8fXp6enZ3e3h4fn18gH5+gH19gn9/g4GBhYGChYGChoSEhYODg4CBg4CAhoKDhYKChoSEiYeHiYaH\r\n        h4WGiIaGh4aGiIWGiYaHiYeHi4iIjIqKjYqKjIiJjIiKioiJioiHjIqJjouLj4yMj4yLkoyLk42MlI6M\r\n        kYyLkIyLkoyKko2Mko+Pk5GRk5CQk4+QlpOTlZOSk5GRlJCQlZKSlJGRlZKSl5STmpWWmpaWmZeWmJaV\r\n        mJWWmZWVoJmWn5iXmpWXmpaWnpqZoZybnZubnJmZnJiXnJmZnZqanpubnpubn5ybn5ycoZ6eoZ6eop6e\r\n        op+foqCfpKGgpKGgo6CgoJ6eoZ2coZ6eo6ChpaKipqOjpqOjpqKjpqOjpqOjpqOjp6SkqKamqKalqaam\r\n        p6WlqKWlqaamq6mpraqqraqqq6mpqaamlZGSdnN0iIeH////////////////////////////////////\r\n        ////////////////////////////////////////////////////y8fIxsXFvbq6SkiHAABpAABqAABq\r\n        AABqGBh1Y2GUpqOxvLq6vLm5vru7vry8vLq7vbu7v729wb+/wLy9wb2+w8HBwr/AwLy9v729wb++wb6+\r\n        wLy9wL29wL69wL69wb+/wL6+wL29wL29wr+/w8HAwb6+v729vLq9NTSKAAB2AAB3AAB3AAB3AAB4AAB4\r\n        AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6AAB6////////////////////zcvLzcvL0c/PysfMOjqUAAB9\r\n        AAB+AAB+AAB+AAB+AAB/ubjGz8zMzszM0c3O0M3O0dDQ1dPT19XU1tPT1dLS1tPS19TU19bV19TU19PT\r\n        19XV2NbV19TU1tPT1tTV2dbXubbGDg2HAACDAACDAACDAACCAACCAACCAACC////////////////////\r\n        ////////////////////////////raqq////s7CwRUNVCQhoAAB+AAB+AAB9AAB9AAB9AAB9AAB9////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////6ujo6ujo5eLj4t/f4N7e4Nzd39zc3tzd3tzc39vazcjEzcjE\r\n        ////////////////////////////////////////////////////////////////3t3d29jZ19TV19XV\r\n        2NXW2NbW1tPT1NHS1dPU1tTV1dLS09HR1NHS1dLS09HR0tDR0tDQ0M3O0c7O09HR1NHS09HR0tDQ0M3N\r\n        09DQ0tDRzcrLzsrLz8zMzcvL0M3N09DR1tTU0tDQz8vLz8vL////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////lpSVlpSVlZWVlpWVlpWVlpWVlpWVlZWVl5aW\r\n        l5aWl5aWlpaWl5aVlpaVlJOTiomIgH5+end2fHh4fHl5fHp6e3l5end4fHp6f318f3x8f3x8e3d4e3h4\r\n        fXx7gH5+gH5/gX9/gH5+gn5/g4CAgoCAg4GBgX9/gn9/g4CAhYKChYKCh4SFhoSEh4SFh4WFhoWEh4WG\r\n        iIWGh4WFh4WFi4mJi4iJioiJi4qKioiHiIaGiYeHjImJj4uKko2KkoyKlY6LlI2LkYuKkoqHlouIkouL\r\n        kIyNj42NkY6Ok4+Pko+PkpCQko+OlJCPlZGQlZGQlJGRlpKSl5OTl5WUlpOSlJGRlZKTnJaUoZuUoZ2W\r\n        nZiVnJeVnJmYnZubnJqam5mZmpaWmZeWm5iYnJiZnpqan5ybn52cnp2cn56dnpucnpuboJ2dop+fpKGg\r\n        oZ+fn52doJ6doJ2dn5ucop+fpaKip6Ojp6SkpqWkpqSjpqSjpqOjpaKipqKipqOjp6Skp6Wkp6SlqKWm\r\n        qqenqqenqqeoq6iopqSknZuciIeHp6Skm5iY////////////////////////////////////////////\r\n        ////////////////////////////////////y8fIxsXFsK28GBhzAABpAABpAABpAABqAABqAABrLi1+\r\n        g4Kiuri5vry8vry8u7m4ura4ube3uri4u7i4vbm6wL6+wb6/wLy9v728wL28v7y7v7y8wL6+wL29v7y7\r\n        wL29wL29v7y8wLy8wb29wL29wL29xMHAxcPCm5qzBwd5AAB2AAB3AAB3AAB3AAB3AAB4AAB4AAB4AAB5\r\n        AAB5AAB5AAB6AAB6AAB6AAB6////////////////////zcvLz83Oy8jJjo2yAwN+AAB9AAB+AAB+AAB+\r\n        AAB+X1+kzcvLzMrLz83N0s7P09HR09HR09DQ0s/P1NHR1dLS1dPS1dPT1dLS1dLS1dPT1tTU1tPT1dLS\r\n        1dPT2tfYmpi+AQGDAACDAACDAACDAACDAACDAACCAACC////////////////////////////////////\r\n        ////1dLSycbGraqq0c7Os7Cwo6GgbmyFBQV+AAB+AAB+AAB+AAB9AAB9AAB9AAB9////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////6ujo5ePj4uDg4t/f4t3e39zc393d3t3d6OPg2tPM2tPM////////////////\r\n        ////////////////////////////////////////////3t3d3t3d29na2tjY2djX2NbW2dXV2NTU1tTU\r\n        1tTU1tTV1tPT1dLS1NLT1NHS1NLS1tTU1dPT0tDQ09HR1NHR0c7O0c/P0M/P0M3O09LR0c/QzcrL0M3N\r\n        0M7NzcvM0M7O1NLS19bW0tDR0c3N0c3N////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////lpWVlpWVlpWVlZWVlpWWl5aWl5aWl5aWmJaXl5eX\r\n        lpSUlZSUlpWVmJeYlZSUioiJgn+Ae3p7fHt8e3l6end4enh4fHl5fnx8fnx8fXp6fXp6f319gX9/f3x9\r\n        fnx7gHx8f3x8f3x8gH19gn+Agn+Ag4GAhYGBhoODhIODhIKDhIGChYKChIKChoSEiIaGiIaGiIWFiIeH\r\n        ioiIiYeIi4iIioeHiYaGioeIjYiIj4qIkYqHkImHkYuIlI2KkYuKkImIkIqIkY2Mko6OkY6OkIyMkY6N\r\n        j46NkI2Nko6Nk46NlpCPlpGQlZCQko+PkpGPk5GQlZGRk5CRlZOTmpWToJuToKCVoJ6WnJeUmZWWnJma\r\n        nZqZm5qam5iYm5mYmpmZm5iYnJiYnpqbnpubnpycnZycnZubnpqan5ycnpybn5uboJ2doJ2dnp2cnJiY\r\n        nJmYn5ydoqCfo6GgpaOjpaOjpaOjpaKhpKCgop6eoZ2do6Cgp6SkpaOjop+epaKhqKWlqaenqqeoq6io\r\n        raqqraurqqiop6Skm5iYqqenp6OjmZaX////////////////////////////////////////////////\r\n        ////////////////////////////sK28BwdrAABoAABoAABpAABpAABqAABqAABqFBNzSEeJn52uvrq7\r\n        vbu7u7m6ura3uba1uri3vbq6vru7v728v729v729vrq7v7y7wL29v7y9v7u8v7u7v7y8wL29wL29wL29\r\n        v7y8v7y7wL69v729v7y+w8LCV1aWAAB2AAB2AAB2AAB3AAB3AAB3AAB4AAB4AAB4AAB4AAB5AAB5AAB5\r\n        AAB6AAB6////////////////////z8zNz8zNz83NysrKHx6JAAB9AAB9AAB+AAB+AAB+JCOLxsPIzs3N\r\n        0dDQ09DQ1NDR0tDQ0c/P0s/P0tDQ0tDQ09DQ0tDP1NHR1NLR1NHR1NDQ1NHR1NLR09HR2tjXfnywAQGD\r\n        AACDAACDAACDAACDAACDAACDAACD////////////////////////////////////1dLS1dLSycbG0s/P\r\n        0c7O0c/P19TUoqC5AAB/AAB+AAB+AAB+AAB+AAB9AAB9AAB9////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////6OXk6OXk5eTj5OLi5OHh4+Dg4+Dg4N7f6OPg2tPM////////////////////////////////////\r\n        ////////////////////////////3dvb3dvb3Nna3dvb29rZ2NbW2NXV2NXV1tXV1tTU1tTU1tTU19XV\r\n        19XW1NLT1NLS19TU2NXV1dPT09LS09DQ0c/P0tDQ0c/P0c7O09HS09HS0M7P0tDQ0dDPzszL0s/P09HR\r\n        1tTU0tDQ0c3N////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////lZWVlpWWl5aWlpaVmJeXmJeXl5aWlpWWl5aWmJeXmJeX\r\n        lpWVlJOTl5aWlpWUi4mJgX5+eXZ2enZ3e3l5fXx8fXt8fXp7e3l5fXp6fXp7fnx8f3x8f3x8fnt7fnt7\r\n        gH19gX5/gn+Agn9/g4B/g4GBhIODg4GChICAhICBhIGChYKCh4WEiIeGiIWGiIaGiIaGiISFiYSFiYeH\r\n        iYaHiIWFiISEioaGjYiGjYiHj4mHkYqIjoqJjImJjYqKj4yLko6Nj4yMkI2Nko+PkI2NjYqKj4yMkIuL\r\n        ko6OlZKRlZGRk5CQkY6NkI6Nko6PlJGRlpOSlZKRmZWSn5uTn5uSnJiVmZaWmZaWmpeWmpiYm5iYnJmY\r\n        nJmYm5iYnJmZnJmZnJqanJqZnZqanZuboZ6eoZ6en5ycnZqanpycnpubnpucnZqanJmYnZuanpybn56d\r\n        o6Gho6GhoZ6eoZ2doZ2dop6eop+fo6GgpaKio6GhoJ6dpKGgqaanqaanqKWmqKWlqKWlqKWlrKior62s\r\n        rKqqqqenp6OjmZaXqKamo6ChlpSS////////////////////////////////////////////////////\r\n        ////////////CQlrCQlrAABnAABoAABoAABpAABpAABpAABqAABqAABrBARtY2KVoqCwubi6vLq6vbm5\r\n        vLm4vLm5vbq7vbq6vbu6vry8v7y9v729wL69wLy9wLy9v7y9v7y8v728v769v7y8v7y8vry7vLu6uri6\r\n        vbu8w8HArKqxERF4AAB2AAB2AAB2AAB3AAB3AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6////\r\n        ////////////0tDQ0tDQzMvKysnJd3epAAB9AAB9AAB9AAB9AAB+BgaAhIOvzMvL0c/P09HQ09HR0c/P\r\n        0c7O0s/P0s/Q0M/P0c/Q0c7O0tDQ1dPT1NHR0tDQ0tDQ09HR0s/P0MzObm2mBQWEAACDAACDAACDAACD\r\n        AACDAACDAACD////////////////////////////////////3tvb3tvb2NXV3dra3tzc3Nra4d7ev7vP\r\n        HByLAAB/AAB/AAB+AAB+AAB+AAB+AAB9AAB9AAB8////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////6OXk5uTj\r\n        4+Hh2dfX4+Dg4+Dg4N7f////////////////////////////////////////////////////////////\r\n        ////////////4N3e3Nna29nZ3Nva3NnZ2tbW29bV2dXV1tTU19XV19bV1tTU2NbW19XW09DQ09HR1tTU\r\n        19XV19bW1tTV1NLS0tDQ1NPS1NPT09DQ09DR1tPU1dLS0c/P0tDQz8zM0M3N0M7O1NHRz83Nz83N////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////lpaVmJeXmJeXlJOTlZWVl5aWmpmZmJiYlZWVlJOTmJaWmpqZ\r\n        mJeXmJeXk5KSioiIgH9/enl5e3l6fHp6fHl5end3fHp5fn18f31+f319gH1+gH59f319f3x8f319fn1+\r\n        f319gX5+goB/g4GBg4CAg3+Agn9/g4CAhYKCh4SDhYODhIKChoKDiIOEiISEh4WFiIWFh4ODhoOChoOD\r\n        iISEi4eGj4qJj4uKjImJi4iHi4iIjIqKjYqKi4mIjIqJkY6OkY6Oj4yMjo2MjouLj4yNko+QlJGRlJGQ\r\n        k5CPk46Nk4+Ok5CQlZGQlY2Nlo+PmZSQmpWRmJWUmJaWlpSUl5OTlZOTlpSTmJSUm5aWm5iYnJqbnJma\r\n        mpiYmpiYm5iYnJmZnJqZnZqZnJiZnJmZm5iYnZqZn5ydn52dnZuanJmYnZqanpuboJ+eoJ2doJycn5ub\r\n        oJ2coJ2dop+fop+foqCgpKKio6Cgo6CgpqOjqKWlp6SjpqOjpKKipqOjqKWlqainqqinrKmorKmpqqin\r\n        qKamo6ChlpSSp6Ojo5+flZKS////////////////////////////////////////////////////AABm\r\n        AABmAABnAABnAABoAABoAABoAABpAABpAABqAABqAABqBwduLy9/cnGbvby8vry8vbm5ure3vLi4vLi4\r\n        ure3vLm5v7y9wb6+v729v7y8vLq6vLm6wLy8v728vr28vru6v7y8v7y8vLq6vLu7wL+/xMHAs6+wU1F+\r\n        AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB5////////////////zczL\r\n        zczLw8HBxcLDwb7DDQ2BAAB8AAB9AAB9AAB9AAB+RESXy8jIzs3N0M7O0tDQ0c/P0M7O0c/P0c/P0M7O\r\n        0M7P0M3N0c/O09HR0tHQ0c/P0tDQ0c7P0c7OysbLUlGeAQGCAACDAACDAACDAACDAACDAACDAACD////\r\n        ////////////////////////////////3tvc29nZ2tjY3Nra3NrZ3dra3dra1NHWGhqKAAB/AAB/AAB/\r\n        AAB+AAB+AAB+AAB+AAB9AAB8AAB9////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////6Obl6Obl4+Hh2dfX////////\r\n        ////////////////////////////////////////////////////////////////////////4N3e4N3e\r\n        3Nra2tnY2dfX2dbX2tjY3NnZ3NjY2dbX2NfX19bV19TU2NXW2NXW1dLS1dLT19TV1dPT1dTU19XW1tPU\r\n        1NLS1NLR09LR09DR09DQ1NLS09LS0c/P0M3NzszL0tHR19bW2dfXxsXGxsXG////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////lJOTlZWVl5aWmZeXmZmZl5eXlpaWmJaXmZiZmZiYmZiZmZeYmZiX\r\n        mJeXk5GRiYiIgoCAfHh4fHl4fHp5fHp6e3l5fnt7fnx8fXt7enl4e3l5fXp5fnp6fnx8f319gH19gH5+\r\n        gH5+f319gH59gH59gn9+hICAhIKCgoF/g4GAhIGBhIOChYOChoOCiISEiYWEh4SEh4ODiYaFioeHioiI\r\n        iYaGioaGjIiHjImJi4mIi4iHi4mIjIqKj42MjoyLjYuKjouKkIyNkY6OkY+Pko+PlJCQlpCOlI+Nk5GR\r\n        k4+Pl4+NlY2Nk4+Ok5CQlJCRlZKRlZGRlJCQk5GQkpCQlZGSlZKSlpOTl5SUmZaWmZaWm5iYm5iYmZaX\r\n        mZaWmZaWmZWVl5OTmZWVnJiYnZubnpycnZqanJqZnpubnpubnJuanpyboJ2doZ6dn52cn52doZ6fop+f\r\n        oJ6eo6GgpKGgoZ6epKGgpqSjp6SjpqKipaKio6GhpaKjpqSkqKWkqKalqKWlqaamrKmprKqqq6inp6Oj\r\n        o5+flZKSqqippaKjlpOU////////////////////////////////////////AABmAABmAABmAABnAABn\r\n        AABnAABoAABoAABpAABpAABpAABqAABqAABrBARtNDOBhYOjtLK2uLa2t7W0ure2ura2uba2u7i4v7y8\r\n        wr+/wL2+u7m5ure3vbm5vbq6vbq7vbq6u7i4vLq6vbu6wL28vr28vbu7s6+w////AAB1AAB1AAB1AAB2\r\n        AAB2AAB2AAB3AAB3AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5////////////zs3Nx8XFxMHBycXFycfH\r\n        VlWcAAB8AAB8AAB9AAB9AAB9Dw+Dqaa8ycfHy8nJz8zNz83Nz87N0M7Oz83NzszMzszMz83M0M7N0c7O\r\n        0M7N0c7O0c7O0MzN0c3N1tHQNjWVAACCAACCAACCAACDAACDAACDAACDAACD////////////////////\r\n        ////////////3tvc3tvc2dbW2tfX2tnZ2tjY29jY3drbycfTMC+UAAB/AAB/AAB/AAB/AAB+AAB+AAB+\r\n        AAB+AAB+AAB9AAB9////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////6Obl////////////////////////////////\r\n        ////////////////////////////////////////////////////////4eDg4eDg3dvb2dfX2dbW2dbX\r\n        29nZ3Nra3Nrb3dvb29nZ2NXV19PT2NXV2tjY2dfX2dbW2NXV1NLS09HR1dPU19XV19XV1dPT0tDP09DQ\r\n        0s7Pz8zM0c/P0tHQz8zMz83N19bV3Nva29rZxsXG////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////mZeXmZmZmpmamZmYmZeXmZaXmZeYmZiYmZiYmZiZmZiZmZiYmZiYmpiZ\r\n        kpKSiYaGf319eXR0e3V1end3eXd3end3eXd3eXd4fHd3fnZ0f3l3f318f3x9fnt8fnt7fnx8f31+f3x8\r\n        f3t7gX19g4B/hYKBg4GAgX9/gH5+goB/hIGCh4ODh4SDhYKBhoODhYODhoODh4SDiYWEiYSEi4aGioeG\r\n        i4iHjIiIioeHiIWFiIaFi4iIiYeHi4eHjYqKj4yNkY2OkY6OkY2OkoyNkY2MkpCPlJCQlJCQk4+PkI2N\r\n        kI6PlZKQl5KPk42NkY6Oko+OlJCQlJGRk5GRko+Pk5CQkpCPlZGRmJSUmZaWmZaWmZaXmpiYmZeWmJWV\r\n        mZaWmpeXmZaWm5iZnZqbnpubnpycnZubm5iYnJuZn5ycn5ycn52doJ6eoqCgoZ+en5ycn5ycoZ6doJ2d\r\n        o5+fpqOipKGho6CfpKGhoqCgo6CgpqKjp6Skp6Wlp6WlqKWlqaalqqamq6enq6ioq6ioqqioqqippaKj\r\n        lpOUqaeno6Cgk5CQ////////////////////////////AABlAABlAABmAABmAABmAABnAABnAABoAABo\r\n        AABoAABpAABpAABqAABqAABqAABrAABrR0eJiIajs7GytbOzt7W1uLa2ure2uri4v7y8wL29vry8vby7\r\n        vLm6ure3uri4ure3trOzt7W0u7m4vru7s7Cwvbu7////////////AAB1AAB1AAB1AAB1AAB2AAB2AAB2\r\n        AAB3AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5////zs3Nzs3NyMbGysfHy8nIysjIsa++CQl/AAB8AAB8\r\n        AAB8AAB9AAB9VFOdxsPEysfHzcrLzsvMzMvLzcvLz8zM0M7Nz83N0M3Nz83N0M3N0s/P0c7OzszM0MzM\r\n        0s3NxsHHExOIAACCAACCAACCAACCAACDAACDAACDAACD////////////////////////////////2dfX\r\n        2tfY1tTU19TU2tjY2tnZ2tjY3NjZ2tjZPz6ZAACAAACAAAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+AAB9\r\n        AAB+////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////4eHg4eHg3dvb29fY29jZ3tva3djY29nZ29na29ra\r\n        2tjY2NXW19XV2tjY3dva29ra29nY2tfX1tTU1NPS1dPT1tTU2NfW2NbX1tLU1NHR0MzMz8vL0tDP09HR\r\n        0tHR0tDQ19TU19TU2tfX2tfX////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////mpmamZmYmZeXmJaWmJeXmJeXmZiYmJiXmZiYmZiZmZiZmZiYmpiYmJeXmpeYlJGS\r\n        ioaGfnx8eHZ2eXZ2eXZ2eXh4e3h4gHZ0gXVxfnh2fHl5fXp7f3t7f3x9f319f3x8gH18f318gHx8gX59\r\n        g4CAg4CAgX9/gn9/g3+Ag4CAgX5/gn9/goCAg4GBhYKCiYWEiYSEiISDiYSEiYeGiYaFiYWFioaGiIWE\r\n        iIWFiYeGiYaGiYWGiYaHi4eHjoqJjYqJjYqKjouMjoyMj4yMkY6OkY+PkY+Pj4yOj4yNlZGPl5OPk5CQ\r\n        kY+PkY+OlJCQlJGSk5GQlJGRlJGRk5CQk5GQlJKRlpKSmJSUmZaWmZeWm5iYm5iYm5mYmpeXm5iYmZeX\r\n        mpeYnJmZnZubnpucnZmZm5iXm5iYnJmanpubn5ydn52doJ6dnpuboJ2cnpubnpyboJ2dop+foJ2coJ2d\r\n        o6GhpKKipaKipqKjpqSkpqOjpaOjpaKiqaWlqqamqKamp6WlqKamrKqpr6ytsK2trKmpqaeno6Cgk5CQ\r\n        rKmppKChk4+P////////////////AABkAABlAABlAABmAABmAABmAABnAABnAABnAABoAABoAABpAABp\r\n        AABpAABqAABqAABrBARtGhp2XlySo6Gst7S0u7m5u7i4uLa2trOzuLa1vLq6vr29vry9vLi5ure3t7W1\r\n        tbKytrOzure3u7m5pKKipKKi////////////////AAB1AAB1AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3\r\n        AAB3AAB4AAB4AAB4AAB4////npq3zc3MysrIycfHyMbHx8bFyMXFYGCfAAB8AAB8AAB8AAB8AAB9Dw+D\r\n        trPBzsvLzszMz83Ny8rJysfIzsvM0tDR0tDQ0c/Pz8zN0M3N09DQ0M7OzMrKzsvL09DOl5S1AQGBAACB\r\n        AACCAACCAACCAACCAACCAACDAACD////////////////////////////2dfX2dfX1tPT1tPT19XV29nY\r\n        3Nra29nZ29jY2tjYRUWcAACAAACAAACAAAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+AAB+AAB+////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////4+Hh4+Hh393d3Nvb3dzc3tvb3dnZ2tjY29nZ2tjY2tfX2NbW2dfX3Nra\r\n        3Nra3NnZ3NnZ29nZ2tjY2dbW2NXV19TV19XU2NbW2dbX2NXV09HQ0s/P1NHR1dLT1NLS1NHS2NXV19TU\r\n        29nY29nY////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////mJaWmJeXmJeXmZeXmZeXmZeXmZmYmZmYmpmZmpmZmpmYmpiZmpmZmpmZm5qZkpGRh4SE\r\n        fXp6eHZ2eXZ3fnVzgXZxe3ZzenZ3e3h4fHl4fHl6f318gX9+gH5+gH59f319f35+gX5+g4B/gn9/gn5/\r\n        gn5/gn9/gX9/g4GBhICAhYGAhYKCh4KCiIODhoODh4SEiIWFiYWFiYaGi4iHioeGiYaGiYaHiYaGiYeG\r\n        h4ODiIODjIeHjYiJioiHjYqKjYqKjoqKjoyLj42Mj4yMkIuLkYyLkY2Mko+Pko+PkpCQkpCPk5CQk5CR\r\n        lJGRlJCQlJGRlJKSlZKRlZKSlpOSmZaWl5aVlZOSmJSVm5eXmpeXmpeXmpiYmpeYmZWWm5eXm5mZnJqa\r\n        nJiYmZSUmpeXnZqbn5ubnpubnZqanpuboJ2cnpycnZmanJmZnpubnpqan5qaoZ2eop+gpKGho6Cho6Cg\r\n        o6CgpKGhoZ6dop6dp6Skp6WlpKKipaKip6SkqaamqqenqqinrKmprqursK2sraurrKmppKChk4+Pqaam\r\n        oZ6eWFZ/CQhmAABkAABkAABlAABlAABlAABmAABmAABmAABnAABnAABoAABoAABoAABpAABpAABqAABq\r\n        AABqAABrAABrFBN0XVySnp2suLW2trOzs7Cwsa6utrOzuba2u7m5v7y8vru8uba2tbOyuLa1vru7wb+/\r\n        qaenqaen////////////////AAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3AAB4AAB4\r\n        AAB4AAB4npq3yMbGx8bFyMfHyMbFxcTDxsXFwL7DFBOCAAB7AAB8AAB8AAB8AAB8YWCizszMz8zLzszL\r\n        zMvLy8jJzMrKz8zM0c/O0M7Oz8vMzsvLz83Mz8zMzMjKzMnK1dDNc3CnAQGBAACBAACBAACCAACCAACC\r\n        AACCAACCAACC////////////////////////////y8jI2dbW19TV2dbX2tjY2tjX29jX29jY2tfY2dbW\r\n        amirAACAAACAAACAAACAAACAAAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+AAB+AAB+////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////4uDg4uDg3tzc3dzc3tzc4Nzb39vb3Nra2tfY29jY29nZ29jY3NnZ3NrZ29nZ29jZ29jZ2tnZ\r\n        29nZ29jY2tfX2NbW2NXV19XV2NbX3dra29rZ1dPU1NHS1dLT1NHR2NXV3dva2dfX29nY////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////mZeXmZeXmZeXmpiYmZmZmpmZmpmZmpqampmZmpiYmZiYm5mam5ubm5qam5qakpGQh4SEfXl5\r\n        enV0e3d3enh3e3h2eXZ2end3fXp6f319gH59gH59gX9/gH9/f319f3t7gH19f31+f318gX59hIGBhIGB\r\n        hYCAhYCAg39/g39/hICAhIGBhIGBhoODiYWFioeGiYaFioWEiYSEh4SEhoODh4SEiYWFiISEi4aGi4iI\r\n        jImJjIqKjIqKi4iJjYmJjoqJj4yKko2Kk4yKko2MkI2NkIyMkYyMko6OkY6Pko+Pk5GQlJGRk5GRko+P\r\n        k4+QlZGRlpOSlZOTlZOTk5GQlJGQk5CQk5CQlZKSlpOTlpSUmJaVl5STl5SUmZeWmJaVko+PmJaWnpuc\r\n        m5iYmpeXnJmZnJmZnJqZm5iYnJeXn5qanZqanZuaoJ2doJ2dn52doJ6eoJ6en5ydoZ2doZ2doJ6dop+f\r\n        paOjpKGgpKGgpaGhpqKip6Wkp6amqKalqaemrKmorKmpraqrrKqprampq6enqaamoZ6eWFZ/CQhmAABj\r\n        AABjAABkAABkAABlAABlAABmAABmAABmAABnAABnAABnAABoAABoAABpAABpAABpAABqAABqAABrAABr\r\n        AABrIyN6YWCSnp2ptbKytLKytLKytbKytbKyuba2vby8vby8tbS0tLKyvru7wb+/qaen////////////\r\n        ////////////AAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3AAB3AAB4AAB4KSmIvrvA\r\n        xMHCxsTExsTEx8XFx8XGxsTFaGehAAB7AAB7AAB8AAB8AAB8DQ2Bmpm4zcrLzMrKysnJycjIy8nJzMrK\r\n        zMvLzcvLzsvMzMnJzcrJzcrKy8jJzMrL0MzLUE6aAwOCAACBAACBAACBAACBAACCAACCAACCAACC////\r\n        ////////////////////2NbWy8jI2dbV2NXV19XW19XW19XU2NTV2dbW2tfY2NXWfnyzAgKCAACBAACA\r\n        AACAAACAAACAAAB/AAB7AAB/AAB/AAB+AAB+AAB+AAB+AAB+AAB+////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////4+Hh4N7d\r\n        393d3tzd3dra3tva39zc4N3d39zd3dvc3tzc3dzb3dra3dra3Nva3Nvb3NnZ2NXW1tXU2NfW2tjY2dfX\r\n        2dbW2NXW1tXV2dfX3drb3Nna1tTU0s/Q1NDR3NrZ4d/e3dva3dva////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////mpiYmZmZmpmZmpmampqampqZmpmZnJubnJucnJucm5qam5mZnJqanJqanJuakpCRh4SEf317eXd2\r\n        eXZ2eXZ2e3h4fHl6fXt7fXp6fXp7f3x8fnx8fnt7f3x8gH19fnx7f3x8gX19gH18gX19g39/g4B/gn9+\r\n        gX5+gH19gH5+hIGCiIWFh4SEhYODh4KCiYWEh4aFh4WEh4ODiYWFioaGiIWFh4WFioeGjYmJjIqJiYeH\r\n        i4aFjoiHjoqJj4yJkIyKkIuLkYuKkYeHkYiHkIqKkI2NkI2NkI2MjIqKjYqKko6OlJGRlJGRk5CQko+P\r\n        k4+Qk5CQko+OkY6OkIyNk4+Ok5CPlZOSlpSTlZKRlJGQmJWVl5SUk4+QmJWVnpyclpSUk5CRmZeXnJma\r\n        mpiXnJiXpKCcpJ6cnZqZm5qZnpybnZqbnpubn52dnpqanpman5ycoJ6dop+eop+foZ6epKGgpaOjpaGi\r\n        pKCgpKGgpqOip6SkqKamq6mpq6ipqqenqaamqqenq6ior6urnJqjOjp6AABiAABiAABjAABjAABkAABk\r\n        AABlAABlAABlAABmAABmAABmAABnAABnAABoAABoAABoAABpAABpAABqAABqAABqAABrAABrCgpwLy5+\r\n        bGuWtrS0uLa2uLa1uLa1trS0uLa2vby8tbOztLKy////////////////////////////////////////\r\n        AAB0AAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3AAB4AAB4X16bwL6+xcPDxcPEx8TF\r\n        xsTExsTEu7nBGBiEAAB7AAB7AAB7AAB8AAB8LCyNyMbIycfHycfHyMbGycbHzMnJzMrKzcvKzMrKzcnK\r\n        zsrKy8nJycbHzMrKu7jFPjyVAQGAAACBAACBAACBAACBAACBAACCAACCAACC////////////////////\r\n        2NbW2NbW09DQ1NHR1tTU1dPT0tDQ0M/O1NLR1tPT2dbW2dbWiIe3BgaDAACBAACBAACAAACAAACAAACA\r\n        AAB7////AAB/AAB/AAB/AAB+AAB+AAB+AAB+AAB+////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////4+Hh4+Hh4d/f39/f397e393d39zd\r\n        3tvb3tvc397e39zd393d397e3tvc3dra3dva393d3dvb2dbX2NTV2NbW2NfX2NbW2dbW2dbX2NbW2NfW\r\n        2tjY29jZ2tfX1tPU1tPT3drZ393d29jZ29jZ////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        mpmampqampqZmpmZm5qanJqbm5ubm5mam5mZnJqanJubnJubnJubnJubnZyck5GRh4SEfnt7e3p6e3p6\r\n        e3l5e3h5eXZ2fHl5fnx7fnt8fnt7f3x7gHx8fnt7fXp6fnp7gn9+gn9+gX5+gn9+hIB/g39/gn5+g4B/\r\n        goCAhYGChYKChYGChYKBhoSEh4SEh4SEh4SEhYODg4KBh4OCjIWDioaFiYeIiIaGiYaFi4iIjIqKjImJ\r\n        jImJjImJjomIkomGkYmGkYyKj4uLj4uLkIyLi4iIh4SEj4yMkY+Pk5CQlZKSlZGRk5CQko+Pk5GQlJKS\r\n        kpCQkY6Ok5GQlJGRlJGRk5CQlZKRlpOTlpOTlJCRmZeXm5mYlpSUko+Ql5OUmpeYmZeWn5qYpqKeo52c\r\n        m5iYm5mZnJmanJmZnZqanZubnJmZnZuanpycn52doJ6en52dnpycoJycop6eo5+fo6Cgo6Cfo5+fop6f\r\n        paKiqKalqaWlqKWlqaenq6ioqqenq6eohIGYHR1tAABhAABiAABiAABjAABjAABjAABkAABkAABlAABl\r\n        AABmAABmAABmAABnAABnAABoAABoAABoAABpAABpAABpAABqAABqAABrAABrAABrAABsJyd7bmyVn52p\r\n        uLa1wL6+ube3vby8tbOz////////////////////////////////////////////AABzAABzAAB0AAB0\r\n        AAB0AAB1AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3AAB3Cgp7mJewxsXFxsXFxsTExsTExsTEx8bGiIau\r\n        BAR7AAB7AAB7AAB7AAB8AgJ9j42xyMbGycbGycbGysjIzcvKzsrKzcnJzMnJzMrJzMnJysfHysfGzcvL\r\n        mZi6HBuJAACAAACAAACAAACBAACBAACBAACBAACBAACB////////////////////2dbX2dbX1tPT1dLR\r\n        1tPU1dPT1NLR0tDQ09HR1tPT19TU19TUnZu+AACBAACBAACBAACBAACBAACAAACAAACA////////AAB/\r\n        AAB/AAB/AAB+AAB+AAB+AAB+AAB+////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////4+Hh4+Hh4N7d4N3e4t/h5OHi4uDg4N7f39zd393d3tvb\r\n        3drb393d39zd3tvb3dvb3dvb3dvb3Nna3dra29fZ19XW2tjX3NnZ2tfY2tjY29nY2dfW2dfX3Nra3drb\r\n        3Nra397d3tzd29jZ////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////mpmZ\r\n        m5qanJqbm5qam5mZm5qanJycnJycnZycnJycnJubnZycnZucnZycm5qakY+QhoSEfHt7e3h5e3d4e3l4\r\n        e3h4e3d4fHl6fnt7fnt7fnx7fHp6f3t8gn59gn99gHx8g39+hYGAhIB/gn19hH59g39+hICAhYKBhYGB\r\n        hYGBhYGBhICBgn+Agn+AhICAhIGAiIKAi4OCiIODhYOEiIWFiYWFi4iHjIiHjYiJi4iJioiIi4iHjomH\r\n        jYmHj4uKj4uLj4uLkY2NjoqKioaGjImIjYuLjouLkY6Nk5CQkpCQk5CQlZOTlpWUlJKRk5GRkpCQk4+Q\r\n        ko+PlJCQlJGQlpOSlZKSlpOUmJWVl5SUl5STmJSUl5OUmJWVmZaVm5eWm5eWmpWWm5iZnZubnpqbnJmZ\r\n        m5mZm5mZnJqanJuanZqanpqboJ2doJ+eoJ2doZqZoZiXoJycoZ+fpaKho6CgoJydop6ep6WlqKSkqaWl\r\n        qKWmqaamqqamp6SmXl2JCQlkAABhAABhAABiAABiAABiAABjAABjAABkAABkAABlAABlAABlAABmAABm\r\n        AABnAABnAABnAABoAABoAABoAABpAABpAABqAABqAABqAABrAABrAABsAABsn52p////wL6+ube3////\r\n        ////////////////////////////////////////////////////AABzAABzAABzAAB0AAB0AAB0AAB1\r\n        AAB1AAB1AAB2AAB2AAB2AAB3AAB3AAB3JSSGu7rAxMPExMPDxMLCxMLCxcHCxcPDKCiJAAB6AAB7AAB7\r\n        AAB7AAB7GBiFwsDEycfHycfHysjHy8nIysfHy8bHy8jJysnJycjHycbFysbGx8XIaWelCAiCAACAAACA\r\n        AACAAACAAACBAACBAACBAACBAACB////////////////////09HR1tPT1NHR1dPS1dPU1dPT1tXU1dPT\r\n        1dLS1tTT1dLS1tPUsK/HCQiFAACBAACBAACBAACBAACBAACAAACAAACA////////AAB/AAB/AAB/AAB/\r\n        AAB+AAB+AAB+AAB+////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////5+bl4+Hi39zc39zc4+Dh5OLi4+Dg4ODg4d/f4d/e4N7d39zc393d4N3d39zd\r\n        3dvb29ra3Nna29fY3dvb3t3e3dnb3dva3dvb2tjZ29jZ3Nna2dfX2dbW3drb4t/g4uHg4uHh4N/g4N/g\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////m5qam5mZ\r\n        m5qanJucnZycnJubnJqanJqanZybnZucnJubnJqanJqanZubm5makY+Qh4WEfHp5eXV2eXZ3e3h4fHp5\r\n        e3p6fHl5fXp6fnt6gn19g35+gX19gHx8gn59gH18f3t7g317hoB9hIB+g39+hYGAhoGBhYGAgn9+gH5+\r\n        gH19hICAg4B/g4B/iIOCioSEh4OCiIOCioSDi4WEi4aEiYaFiYeHiYaGioeHioeIi4iJjIiJjYmIjImJ\r\n        jIqKjoqKjYmJjYmJjYqKjoqKjYqJkY6OkY+Pj42NkI2Nk5CQk5CQlJKSkpCQko+PkpCQkY6Pko6Pk5CQ\r\n        lZKSl5STl5OTlZKSmJaWm5mZm5iXl5SUmZaVmJWVlZKSlpOUm5eYm5iYm5mYnJqZm5eYm5iXnZubmpiZ\r\n        mpeXnpqaoJycn52cn5ycopybopyboJycoZ6eoZ+eoqCfoJ6dn5yco6CfpqOjqaamqaanqKamqKamlJKd\r\n        NjV2AABgAABgAABhAABhAABhAABiAABiAABjAABjAABkAABkAABkAABlAABlAABmAABmAABmAABnAABn\r\n        AABoAABoAABoAABpAABpAABpAABqAABqAABrAABrAABrAABsAABs////////////////////////////\r\n        ////////////////////////////////////AABzAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2\r\n        AAB2AAB2AAB3AAB3AAB3Xl2awsDBw8PDw8HCwb+/wr+/wsDAmpiyBwd9AAB6AAB6AAB7AAB7AAB7Xl2f\r\n        xsTFxsTEx8TExsTExcPDyMXFysfHysjHycfGyMXFycbGtrTCNzaTAAB/AAB/AACAAACAAACAAACAAACA\r\n        AACBAACAAACA////////////0M7P0M7P09HR09HQ0c/O0s/P09DR09DR1NLS1dPT1tPT1tPT1tPU19XW\r\n        0M7UIyOQAACCAACCAACBAACBAACBAACBAACBAACB////////////AAB/AAB/AAB/AAB/AAB+AAB+AAB+\r\n        AAB+////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        5+bl5+bl4+Hh4d/g4d/f4+Hh4uHh4d7e393d4N7d4t/f4+Hg4uDg4N7e397e3tzb3Nra3Nra3NnZ2tfY\r\n        3Nrb397e393e3tvc3dra29nY29jZ29nZ2dfX2tjY393d4d/e4d7e4d/g397e397e////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////nJucnZycnJub\r\n        m5mZnJqbnJqam5mam5qbm5qbnJuanZybnZybnZucnZucmZeYj46OhIGBenh4enh4enh4end3end2fHl4\r\n        gHx7gn19f3t7f3t6f3x7f318fnt7gXx7gn17gX18gHx8gn19hIB/g4B/gn9/gX5+gX5+gn9/gX9/gX9/\r\n        hYKCiIOCi4SCi4WDiYSDiYKCh4KBhIKBg4KBh4SEiIWFioeHioeIi4eIi4eHiYeGiIaGi4iIjImJjImJ\r\n        j4uLkY2MkIyMkY+PkI+PjImKjIiIjouLkY2Nk5CQkY+Pk5CRkpCQkI2NkIyNkY6Ok5CPlJGRk4+PlJGR\r\n        lpSVmZiYmZaVmJOSl5KSmJWUl5WVmJaWmZaWmJWUmJaVmpmYm5iYmpaVnZqZmJWVl5SUnJqZoJycnpqa\r\n        npubnpycnZybnpuboJ2dnZubnZqaoJ2cnZqanpmaop+eoJ+foqCgp6Wlqaeol5WfREN8AwNgAABgAABg\r\n        AABgAABhAABhAABiAABiAABjAABjAABjAABkAABkAABlAABlAABlAABmAABmAABnAABnAABnAABoAABo\r\n        AABoAABpAABpAABqAABqAABqAABrAABrAABsAABrAABsAABs////////////////////////////////\r\n        ////////////////////////AABzAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2\r\n        AAB3Cgp7mpmxw8PEw8LCwb+/wcDAwcDAwb+/bGqgAgJ7AAB6AAB6AAB7AAB7AwN8oZ+1xcLCxsPDxcPC\r\n        xcPCx8TDycXFycXFyMTEx8TEx8XElZO0GBiIAAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACA////\r\n        ////////0M7P0M7Pz83O0dDQ0c/P0c7O0c/P09DR09DR09HQ09HQ1dLT19XW19XWysjQJyaRAACCAACC\r\n        AACCAACBAACBAACBAACBAACB////////////////AAB/AAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////5ePk5ePk4+Hh4+Li\r\n        5OPj5OPj4+Li4t/g4d7e4N3d4d7e4uDg4eDg4N7e393d3tzb3tzc4N7e3tzc3dvb3drb3drb3t3c3t3c\r\n        3drb3NnZ3dna3Nrb2tjY3NnZ3t3c3Nva3NnZ3tvc397e////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////m5mZnJqbnJqamZiY\r\n        mpmZnJubnZycnZubnp2cnp6dnZycnp2doJ6fnp2dmJeWjo2NhIGBeXd3eXZ2end2enh3e3h4e3h4fXt6\r\n        fnt7fXp6fnx7fnt6gXt6g3x7gHt7f3t7gX9+gH5+gH19gX19gX59gX5+gX5+g39/g4GAg4CAhoGAiISD\r\n        hYOChIGAhYGAg4CAgoCAhIKBh4SDiISDiIaFiIaFiYaGiYaGioeGioiHioeHioeGjImJkIyMj42NkI+P\r\n        j42OjYqLjImJjoyLkY6OkY6Pj4yNkI2OkY6OkI2MkY6NkI2NkI6OkI2NkI2NkI2MkY6Oko+PlpGQlpCP\r\n        lZCPk5GRl5SVl5SUl5SUmJWUmZaVmpeXmZeWmJSVmZaWl5WUlpOTm5iYnpubn5uboJycnZqbmZaXnJiX\r\n        nZqZnJqanZmZnpyaoJ2cnpqan5ubmJaWmZeXop+fqKSlpqSkoJ6ieXeRPDt3BQVhAABgAABgAABhAABh\r\n        AABhAABiAABiAABjAABjAABkAABkAABkAABlAABlAABmAABmAABmAABnAABnAABoAABoAABoAABpAABp\r\n        AABpAABqAABqAABrAABrAABrAABsAABsAABsAABs////////////////////////////////////////\r\n        ////////////AAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2AAB3Li6IuLe9\r\n        wcDAwsDAwsDAwb+/wL+/w8HBMDCLAAB6AAB6AAB6AAB6AAB7JiWJwsDBx8PCyMTDx8TDyMTEx8PDx8PD\r\n        xsPDxcPDvr3AY2OhBgaAAAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACA////////////////1NLS09HR\r\n        zczM0dDQ0s/P0c/P0dDP09DR09DR0c7P0M7O09HR1dTU1tPTxsPNOTmYAACCAACCAACCAACCAACCAACB\r\n        AACBAgKB////////////////////////AAB/AAB/AAB/AAB/AAB+AAB+AAB+AAB+////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////5+Xm5eLi5ePj5OPj5ePi5OLi4+Hi4+Li\r\n        5OPk5eLj4+Dh4uDh4d/g4d7e4N3e4N3d4N/f4uHh4uHg397c3dva3NnZ3tzb3t3c3dvb3Nra3drb3tvb\r\n        3dnZ3drZ3Nra29nZ3Nra39zb39zb////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////mZiYmpmZnJubnpydnJqc\r\n        nZybnpycnpycnp2dn52dnZucnJqanZucn52em5mZjoyMgX9/d3V1eXZ2e3h4e3p5e3h3enZ2e3h4fHl4\r\n        gnt4hoB8gHx6fXp6f318gHx7gXx6gH18gX5+gX5+gX5+gH19gH19f3x8gH19g4GAhIOCgn9/g39/hYKC\r\n        hYKChYKChYKBhYKBhoOCh4SEhoODh4SDiIaEiYeGiIWFiIWFioeHi4iIjImJjYuLjIqKjIqJj4yMj42N\r\n        kY+PkY+PkI6PkI2Nj4yMj4yLkIyMj4yLj4yMj42Mj4yLj4uLj4qKkI2Nk4+Pk5CPkI6NkY6OlJGQlpKS\r\n        lpOTl5SUl5SUmZaVmZeWl5WVl5WVmJaWmZeWmpiXnJmYnZqZnpubnZmam5iYmpeXm5iXnZmanZqanJmY\r\n        nZuZoJ2cn5ubnZqamZeWnpuapaGhpaOjoJ6foZ6eop+ekI6XSkh8ICBsAQFgAABgAABhAABhAABiAABi\r\n        AABjAABjAABjAABkAABkAABlAABlAABlAABmAABmAABnAABnAABnAABoAABoAABoAABpAABpAABqAABq\r\n        AABqAABrAABrAABsAABsAABsAABsAABs////////////////////////////////////////////GBdw\r\n        AAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2XFuYv729wb+/wL6+wb6+\r\n        wr/AwcDBlJOvAAB5AAB5AAB6AAB6AAB6AAB7X16dxcLCxsLCxsPDxsPDxsTDxsTDx8XFxcPDq6m6Ly6P\r\n        AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACA////////////1NLS1NLS0M7Oz83N0c/P09LR0dDP\r\n        z87N0M7O0M7O0M3N0M7O0c/P0tDP09HR09DQQUCbAACDAACCAACCAACCAACCAACCAACBAgKBAgKB////\r\n        ////////////////////AAB/AAB/AAB/AAB/AAB/AAB+AAB+AAB+////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////5+Xm5+Xm5uPj5ePj5OLi5OHh5OHi4+Hi4+Li5uTl5uXl5OLi4uDg\r\n        4+Dh4d/g4t/g4d7f4N/f4eDg4uDh4N/f397d393c39zc3t3d3tzc3dvb3dvb3tzc3tvc3dvb3tvb3dvb\r\n        397e39zb////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////npydnJqcnZybnZuanpycn52e\r\n        n52dnpycnZucn52doJ6eoJ6en56en56empiZj4yMg4CAe3h4e3d3end2end3eXR1gnt5hYB8f3p5eXV2\r\n        fHl5gn16hH57f3x7fXt7fnt7gH18f3x8fnt7gH18gHx9gX5+gn9+gn9+g4CAhIKBhICAhICAhYGChYGB\r\n        hoODhoKDhIGBhYGBh4SDh4ODhoODh4SEiYaGi4iIi4iIi4eHioaHioeHjIqKjoqLjoyLkI2OkY6PkI2N\r\n        j42Nj42NjYqJjImIjYqKjIiJj4uLkI2Mj4yMj4uLkI6OkY6OkY6OkY2OkpCPk5CQlZKTlpOTl5STl5WU\r\n        l5SUlZKSlpOTmJaWmZaWmpaWmpiXmZiXmJaWmpiYmpiYmpiYmpeWnJmZnJiZmJWVmJWVnpqaoJ2cnpyc\r\n        mZaWnZuapaOjoqChnZqampeXnpuan5ycoJ2dkI6XZWSHJiZvEBBmAABhAABhAABhAABiAABiAABjAABj\r\n        AABkAABkAABkAABlAABlAABmAABmAABmAABnAABnAABoAABoAABoAABpAABpAABpAABqAABqAABrAABr\r\n        AABrAABsAABsAABsAABsAABt////////////////////////////////////////DQx2AAByAAByAABy\r\n        AABzAABzAABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2AAB2AAB2nJmvvLq6vLm6v7y8wL6/v72+vbu7ZGOc\r\n        AAB5AAB5AAB6AAB6AAB6CAh9kZCvw8HBw8HBxMLCxMPDxcPDxcPDxsTEcG+lCwuBAAB9AAB+AAB+AAB+\r\n        AAB+AAB/AAB/AAB/AAB/AAB/////////////w8HAz8zMzcrKz8vL0M3N0M7Oz83Nz8zMz8zMz8zM0M7O\r\n        1NHR1NLS0s/Q0tDRzczOYF+mAACDAACDAACDAACCAACCAACCAACCAACCAACC////////////////////\r\n        ////////AAB/AAB/AAB/AAB/AAB/AAB+AAB+AAB+////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////6efn6efn5uXl5uTk5OHi4+Dg4+Hg5OLi5OHh5eLi4+Hi4d/f4uDf4+Hh4d/f4d/f4d/f\r\n        4d/e4uDf4d7f4uDh4eDf4N3d39zd4N7f4d/f4N3d4N/e397e39zd39zc3tzc3dna3tva3tva////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////nZuanpycn52eoKCfn5+en56en52d\r\n        oJ+foqChoaGhoaGgoaCfoqGioqGinJqaj42Ngn5+eXV1eHNzfnh2gXp4e3d2eHZ2e3Z1gHh1gHt5f3x7\r\n        f3t7fnp7fnt6fXp5fHh4fXp5fnx8fnt8gHx9g3+AhIKBg4GAhICBhYGChYKChIGBhIGBhoKChYKBhoOC\r\n        hoKChYGChIKBhoODh4SEh4WFiIWFiYaGiYaFioeHjImJjYqJjYuKjoyLjYuMjImKkI6Nj46Oi4mJi4iH\r\n        jImIioiHi4mJkI2NkY6NkY6OkI6NkY6MkI2MkY6OkY6Oko+PlJCQlZKRlpKSlpOTlZOSk4+Pk4+PmZaV\r\n        l5OTlZGQl5SUlpSUlJKSmJSUmZaWmZaWmZaWmpiXmJaVlJGRmZWVnJiYnpuanpubmZWVmpeXn52dn52d\r\n        nJmZmZaWm5iYnZqbnJqanpybm5ibhIOSammJODd2BgZjAgJiAABhAABiAABiAABjAABjAABjAABkAABk\r\n        AABlAABlAABlAABmAABmAABnAABnAABnAABoAABoAABoAABpAABpAABqAABqAABqAABrAABrAABsAABs\r\n        AABsAABtAABsAABt////////////////////////////////////AABxAABxAAByAAByAAByAABzAABz\r\n        AABzAAB0AAB0AAB0AAB1AAB1AAB1AAB2LSyGtrS3vLq5vLq6vLq7vru7vru6vru9ODeNAAB5AAB5AAB5\r\n        AAB6AAB6Hx6Ft7S7wb+/w8LBxcLDxcLCw8DBsKy6HR2HAAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/\r\n        AAB/AQF/////uba2wb6+w8HAzcrLzMrKzcrKzcnKzcrKzszMzsvMz8zN0M7O0M7O0tDR1NHT0tDR0c/Q\r\n        0M3NeHauAACDAACDAACDAACDAACCAACCAACCAACCEBCF////////////////////////////////AAB/\r\n        AACAAAB/AAB/AAB/AAB/AAB+AAB+////////////////////////////////////////////////////\r\n        ////////////////////////////////wcC+zs3N1tTV2NXVx8TEq6ip////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////5OLj\r\n        5+Xl4+Li5eLi5+Tl5uTk5OLi4uDg4+Dh4+Df4d7f4N7e4+Hh4+Hh4uDg4+Dg4uDg4uDf4uDg4d7f4d/g\r\n        4uDh4N3d3tzc393d4N3d4N3e4d7f4N7e3tzc3tvc3dra3dra3trb3trb////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////oKCfn5+en56en56doaCgoKCgoJ6doJ6c\r\n        oZ6dn56en52dn52dn56doJ6dmpiYjYqKgX18e3h3e3l4e3h3enZ1fHV0gHp5gHp5f3t7fXl6fHh4fXl5\r\n        fXp5enh3e3h4fHh5fXl6gH5+gH5+gH19gn9/g4KCgn+Agn+Ag4CAhoKBhoKAhIGAhYGBhoODhoSEhoOE\r\n        hoSEhYKChIKChoODh4WEhoSDhoSFhoSFhYSFhoaGhoSEh4SEiIWGiIeGiIaFi4iIjIqKjImIjIiIi4iJ\r\n        ioiIjIuLj4yMkIuJlo6LlY6Mko6NkY+OlJCQlZGRlZGSlJKSl5WUlJKSj4yMkYyNlZGRk5GQko+Qko+P\r\n        lZGQmZWVmJaVl5SUmJSUmZeWlpSUlpOTmJWVm5eXnZmZnJmYm5iYmpeXmpeXnJmZnJmZm5iYnpqbnpyc\r\n        m5iYnpuaoZ6enZucnpydlJKabm2LRUR7EhJoAABhAABhAABiAABiAABjAABjAABkAABkAABkAABlAABl\r\n        AABmAABmAABmAABnAABnAABoAABoAABoAABpAABpAABpAABqAABqAABrAABrAABrAABsAABsAABsAABt\r\n        AABtAABtAABt////////////////////////Hh18AABxAABxAAByAAByAAByAABzAABzAABzAAB0AAB0\r\n        AAB0AAB1AAB1AAB1AAB2WlmXu7m6vLq7urm5vbq6v7u8wb29qKW0DAx8AAB5AAB5AAB5AAB6AAB6Q0KR\r\n        wL6+wr+/xMHBxMHBw7/Aa2mhAAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AQF/sKyxuba2\r\n        wb6+x8XFzMrLzMrLzMrKzMnKzcnJzsvLzcvLz83N0M7OzszMzszN0M7O0M/P0c/P0M3NkI+4BweGAACD\r\n        AACDAACDAACDAACDAACCAACCEBCFEBCF////////////////////////////////AACAAACAAAB/AAB/\r\n        AAB/AAB/AAB+AAB/////////////////////////////////////////////////////////////////\r\n        ////////////zMnKwcC+zs3N1tTV2NXVx8TEq6ip09DQvLm5trOy////////////////////////////\r\n        ////////////////////////////////////////////////////////5OLj5OLj5OHi4+Dh4t/f5eLi\r\n        5+Xm5uTk5OLh4+Dg4t/f4+Li4uHh4+Dh5eTj5eTk5eLj4+Hh4uDg4d/g4d/f4N/f4uDh4uHh4eDf4N7e\r\n        393e393e4N7e4N3e393d3tzc3tvb3tzc3trb////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////n56doaCgoJ+eoZ+eop+eoZ+goJ6fn56eoJ6e\r\n        oJ+foJ+eop+goaCgoaCfmZiYkIuLhH99eHZ3end4fHd2e3d1e3h4fHl5d3R0d3NzeXZ2e3h3fXp5fHl5\r\n        fHh5fHh4fXp6fXp7gH1+gH5+f3x8f3x8gn9/hYCAhYB/hIB/hYKChoSEhoODh4ODhYKChIGChIGBhYOC\r\n        goB/g4B/hoSDg4GDgH+BhIOEiYeHh4SEgoCAhIKCiYaFh4aFiIeHiYeIi4iIiYaGhIKCg4GChoOEjYiI\r\n        loyKk4uJj4qKkY2Nko+Pk5GRko+OkIyMj4yNk5GQjIqJiISFj4uMk5CQkY+OlJCPlpGRl5STlpOTmJST\r\n        mZWVl5STkI6Pjo2NlZOSl5SUlpOTmZWVnpybm5mYmZaWnpubnpubnpubn5ycoJ2dnJqaop6cp6Kfo5+e\r\n        n5ycn52cnpyboJ6diYiVVVOBHh1tAABhAABiAABiAABjAABjAABjAABkAABkAABlAABlAABlAABmAABm\r\n        AABnAABnAABnAABoAABoAABoAABpAABpAABqAABqAABqAABrAABrAABsAABsAABsAABtAABtAABtAABt\r\n        AABuAABu////////////////FRV4AABxAABxAABxAAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1\r\n        AAB1AAB1iIanu7m6vLu7vLu7vru9wL29v728gn+mAAB4AAB5AAB5AAB5AAB5AwN7ZGOdwb6+wb6+wr+/\r\n        kpCuJSWIAAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB+AAB+AAB+AAB+FBOEsKyxw8DAyMTFy8fHysjIy8rK\r\n        y8nJzMrJzMrKy8jJzMrKzcvLzcvLzMnJzcrKz8zM0M7O0tDQ0tDRr67EDAyHAACDAACDAACDAACDAACD\r\n        AACDAACCBweEWVmX////////////////////////////////////AACAAACAAACAAAB/AAB/AAB/AAB/\r\n        AAB/////////////////////////////////////////////////////////////vbq6ysfI1tTUzMnK\r\n        1NLS2tna3Nra4Nzd4N7e3Nra09DQvLm5trOy////////////////////////////////////////////\r\n        ////////////////////////////////////////5OHh5OHh4uHh5OHi5OHh4+Dh5OLi5OPj5OLi5OLi\r\n        5eLj5+Xl5OPj5OHh5uPj5eTk4+Hh4+Dh4uDg4d/f4d/f4N7f4d/f5OHi4+Hi4uDh4d/g393d393d39zd\r\n        4d7e4d/f4N7e393d393d////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////oJ+eoZ+eop+eoaCgoJ+foJ+foZ+foZ+foKCfoZ+goaCg\r\n        oKCgn56foJ6foZ6fmZaWjImKfnt7dnNyeHV0eXZ1d3R0dXNyeHV1fHh4fnt6fHl5fHh4e3h3fHl5fnt7\r\n        fnt7f3x8fnt7fnt7fnt7gH59gn9/g4CAhIKBg4GAg4CAhYKChYKChIGBhoKChoODgoCBhIKBjoqGi4aF\r\n        hYGChoODiIaGh4WEhoODiYaGioeGh4aFh4WFh4aHh4WGh4SFh4WFhoSDhYKCiIWFjIeHjIiHjYqKkI2N\r\n        kI2NjYqKj4qJjYiGh4WFjouLjIqJioeHjImKj4yMko+MlZGPlJCRlZKSlpKSl5SUmJWVk5CQjImKjouM\r\n        lJKSlZOTkY+PlZKSmZeWmZeWmZeWnZubn52cn5ycnpuanJmZnZqaoJybo56coJ2bn5ubnZqanJqanZqa\r\n        npybnpuboJydeXePMjF0ExJoAABiAABiAABjAABjAABkAABkAABkAABlAABlAABmAABmAABmAABnAABn\r\n        AABoAABoAABoAABpAABpAABpAABqAABqAABrAABrAABrAABsAABsAABsAABtAABtAABuAABuAABuAABu\r\n        CQli////////AgJxAABwAABxAABxAAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AAB1AAB1JCSCu7m6\r\n        u7q6urm5u7m5vbu8vbq7vbu6YmKaBAR6AAB4AAB5AAB5AAB5BAR8goGovry8p6W1LCyLAgJ8AAB7AAB8\r\n        AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+NjWRx8TFxsPDyMTEy8fHy8jIysnJysfIysfHycjHycfH\r\n        zMnJzcvKy8jIy8fIzMrJzsvLz8zM0M7O0c/PubjICQmGAACDAACDAACDAACDAACDAACDAACDAACDWVmX\r\n        WVmX////////////////////////////////////AACAAACAAACAAAB/AAB/AAB/AAB/AAB/AAB/////\r\n        ////////////////////////////////////////////xcLCvbq6ysfI1tTU3tzc4N7f3dna2dbW3dra\r\n        4+Li5+bl4N7ezsvLtrOyvLq6vLq6////////////////////////////////////////////////////\r\n        ////////////////////////5eLi5OLh5OPi5OLj5OHi4d/f4N7e4+Hh5eLi5OHi5OHi5OHh4+Dg5OLi\r\n        5eLj5OHj5OHj4+Dg4+Dg4d/f4t/g4t/g4uDg4d/f4d7f4d/g4t/g4N7d393d4N3d4uDg4d/f393e4N3e\r\n        4N3e////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////oaCgoJ+foJ+foZ+goJ+foaCfoqCgoqGgoaCgoZ+goqCgoqGh\r\n        oaCgn56eoZ6fmJWVioeHfnt6e3h3fXt5fHl5e3h4enh4e3l4eXd2e3d3fnt7fnt6fHl4fnp6fnx7fXt6\r\n        fXt6fnx8f319fnt8gH19goB+gn9/g4GBhIKBhIGBhIGBhIGBg4GBh4SDi4aEjIiFiYWEh4SDhYKChYOD\r\n        iIWEiIWEhoSEiIWEiIWFh4SEhYOChIKCiIaFioiHiYaGhYODh4WFioeIjImJj4yLjYqKjYmKj4qJjomI\r\n        ioeHioaHh4SFj42MkI6NjouKko2Mk4+Oko6Pk5CQlZOSl5WVl5SUk5CPkY6OlJGRlpSUlZOTlJKSk5CQ\r\n        lZOTmZiXm5iYmpeXm5mZnJmZnJmZm5iYnJqZnZmZm5iZnJmZnJmZm5mZnJmZm5mYmpiYnJmZnZmZnZqa\r\n        lpOYgYCRVlSBJCNvCAdlAABjAABjAABjAABkAABkAABlAABlAABlAABmAABmAABnAABnAABnAABoAABo\r\n        AABoAABpAABpAABqAABqAABqAABrAABrAABsAABsAABsAABtAABtAABtAABuAABuAABvAABvAABvAQFw\r\n        AABwAABwAABxAABxAABxAAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AQF1V1aUuba3u7e3u7i4uri5\r\n        u7i4u7q5u7m5R0aRAAB4AAB4AAB5AAB5AAB5Cgp9fn2lTk2VAAB6AAB7AAB7AAB7AAB7AAB8AAB8AAB8\r\n        AAB9AAB9AAB9AAB9AgJ/RkWWube+xMLCxcPDycfHysjIyMfHyMbGycbGycfGysjHzMrJzMnJycbHycbH\r\n        ysfHy8fHzMrJzszLzcvLx8TLMzOVAACDAACDAACDAACDAACDAACDAACDAQGDPTyWo6Gj////////////\r\n        ////////////////////////////AACAAACAAACAAACAAAB/AAB/AAB/AAB/AAB/////////////////\r\n        ////////////////tbKzxcLCz83MxcLCzszM2dfX2tjY3tzc393c3dnZ3dnZ3t3c4uDg4+Dh3tvc29jY\r\n        09DQvLq6vLq6////////////////////////////////////////////////////////////////////\r\n        ////5eLi5eLi4+Hg4+Hh4+Hh4+Hh4+Hh4+Hh4+Hh4+Hg4t/g4uDg4t/f4+Dg5OPj4+Li4+Dh5eLi5OHh\r\n        4uDf4+Hh4+Hh4+Hh4uDg4uDg4eDf4N7e4N3e4d/f4N3d4d7e4+Hg4uDf393d4N3e////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////oZ+goJ+foaCfoqCfoqCfoZ+foqCgpKGho6KioqKhoZ+foqCgo6Gg\r\n        o6CgoqCgl5WVjImJf319eHZ3d3Z2eHZ2eHZ2d3R1end2enh3eXZ2end3fHl5fXp6fnt7f3t8fnt7fHl5\r\n        fHp6gH9+gX9/gX5/g4CAhIGBg4B/gX5+gX9+g4CAg4CAg4CBhoKChYKChoODhYKChIKChIGChICBhIGB\r\n        hoKChoOChYGBg4B/g4CAhYODhoSEhoODiIWEiYSEiYWEjYqJjoyMjouMjoqKjoqKj42MiIWFg3+Ah4WF\r\n        jo2MkY6Oko6OkY6OkI2Nj4yMkY+PlJKSlJCQlZKRlpSUlpOTlZKSlZKSlpOTlpOTl5WVmpiXmpeYmpeX\r\n        mZaXmpeXm5iYnJmZmpiXm5mYm5iZm5eYmpiXmZeWmpeXmZeXm5iZnJqanZuanpubnpybnpuam5eYh4WT\r\n        VVOBMTB0GhpsBQVlAABjAABkAABkAABkAABlAABlAABmAABmAABmAABnAABnAABoAABoAABoAABpAABp\r\n        AABpAABqAABqAABrAABrAABrAABsAABsAABtAABtAABtAABuAABuAABuAABvAABvAABvAABwAABwAABw\r\n        AABxAABxAAByAAByAAByAABzAABzAABzAAB0AAB0AAB0AQF1f3ygurW1ure3uLa2uba2u7i5u7i4rKqz\r\n        JCOEAAB4AAB4AAB4AAB5AAB5ExOACQl9AAB6AAB6AAB6AAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9\r\n        BQV/X16dvLi8xMHCw8HBxsPEyMXGx8XFx8TEyMXGycbGysfGysfHycbGyMXFycfGycbFyMXEzMnJz8zN\r\n        zcrLzMnLNzaWAACCAACCAACDAACDAACDAACDAACDAACDKSiRo6Gjo6Gj////////////////////////\r\n        ////////////////AACAAACAAACAAACAAAB/AAB/AAB/AAB/AAB/////////////////////w8DAzMrL\r\n        tbKzxcLCz83M1NHR29jZ2tjY2tjX2tfX29jY3Nra39zc3tvb3dra39zd4N3e3NnZ2NXWwr+/wr+/////\r\n        ////////////////////////////////////////////////////////////////////4+Dh4+Dh4N7e\r\n        4d7e4t/f4+Hh5eLi5uPj4+Li4+Hh4uDg4uDg4+Dg4+Dg5eLj4+Li4+Hh4+Dg4d7e397d4+Lh5uTj5OLi\r\n        4+Hh4+Hh4+Lh4uHg4t/f4uHg4N7e4d7e4t/f4d7f4N7e4N7e////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////oqCfoqCfoZ+foqCgoqCgoaCgoqChoqCgo6Ggo6GhpKGhpKKio6GhpKGh\r\n        o6GhlpaViYeHe3l5eHZ2dXRzcW9ud3R0e3h5eHV2eHZ2e3h4fXp6fXp5fnt7fHp6fXt7f319gH5+gH19\r\n        gH1+gH59gn9/g4CAgn9/gX9/gX9/gn5/gn5+goB/gX9+gX9/goCAhoKDhoODhIKBhIKBhIOCg4CBg3+A\r\n        hoOChYKCg4CAgoB/hYKCiYWEioiHjYqKjYuLioeHiYaGjouLjouKjIqJh4SEgH19hoOEjoyMjYqLjYqL\r\n        jIuLiYeHjYqLkIyNj4yLkI2NkpCQkpCPko+PlJGQlZOTlpOTl5SUmJWVmpeXmZeXmZeXmZeXmpaWmpeX\r\n        mpeXmZaWmZWWmZaWm5mYm5mZmpaWmZaWmJaVm5iYnZubnpycnpubnpuanpqan5ycnZucjIqVeniOR0Z8\r\n        DQ1oAQFjAQFjAABkAABkAABlAABlAABlAABmAABmAABnAABnAABnAABoAABoAABpAABpAABpAABqAABq\r\n        AABqAABrAABrAABsAABsAABsAABtAABtAABtAABuAABuAABvAABvAABvAABwAABwAABwAABxAABxAABx\r\n        AAByAAByAAByAABzAABzAABzAAB0AAB0ExN7qaawtrO0t7W1t7S1uba2ubW1ube3mJasISGDAAB4AAB4\r\n        AAB4AAB5AAB5AAB5AAB5AAB6AAB6AAB6AAB7AAB7AAB7AAB7AAB8AAB8AAB8AAB9AQF9c3CkxMLBxcTE\r\n        xcPExcLDx8XFxsTFxcLCxsLDx8PEyMTFpqS5yMXGyMXFycbFycXFycbGzMrKz8zNz8zNycfMWlmjAACC\r\n        AACCAACCAACDAACDAACDAACDAACDAACDoaCzpKKj////////////////////////////////////////\r\n        ////AACAAACAAACAAACAAACAAAB/AAB/AAB/AAB/////////trO0xMLBw8DAzMrL0c/P2NXW2tjY3Nra\r\n        29nZ2tnX29nZ2tfX2tfX29nZ2tfX2tbX29jY3tzb393e3tvc2NXWwL69pqSk////////////////////\r\n        ////////////////////////////////////////////////////5OHi4+Dh4N7f4N/e4+Hg4+Dh5ODg\r\n        5ODg4t/g4N7e4uDg4t/f4+Hh5OLi4+Dg4d/e4d/f4+Hh4uDh4N7e4t/f4+Hi4d/g4uDg5OHh5OHi5ePj\r\n        4+Hh4uDg4uDg4+Dg4+Dg4Nzd4Nzd4Nzd////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////oqCgoqCgoaCgoZ+foZ+goqCho6Gio6Kio6GioqGhpKGipKOipKOipKKio6Gh\r\n        lpSViIaGeHZ1eHR0fHh4eXd2end3eXd3enh3e3h3fHl6fHp6fXp6f3x8gHx9gH19fnx8f319gX19g39/\r\n        gH5+gH19gX5+gn5+g4B/goB/gX5+gH19gX5+gn9/hYODh4SEhoODhIKBg39/g4CAhYKChIGBgn9/hIGA\r\n        h4SDi4iHioeHi4eIi4eHiYWFiYaFjYuKjouLj4yMjoyMhIGBhoODioiIioeHi4iIi4iJhYKDjImIjYyK\r\n        iYeIh4OEjImIkI2NjouLj42Nj42Nko+QlZKSl5WUl5WVmJWVlpSTl5SUlpOTmJWVm5eYmZaXlpSTmJWU\r\n        mpeXmpeYmpiXm5mYm5mYm5iYnJiZnZqanpycnpuanZmZnJqanZubnpybn5ycnJmdfHmQVlWCLi50Dg1o\r\n        AABkAABkAABkAABlAABlAABmAABmAABmAABnAABnAABoAABoAABoAABpAABpAABpAABqAABqAABrAABr\r\n        AABrAABsAABsAABtAABtAABtAABuAABuAABuAABvAABvAABvAABwAABwAABwAABxAABxAAByAAByAABy\r\n        AABzAABzAABzAAB0AAB0UE+QtrOzt7W1uLW1t7S0trS0trS0t7W1nJqsFRV+AAB3AAB4AAB4AAB4AAB5\r\n        AAB5AAB5AAB6AAB6AAB6AAB6AAB7AAB7AAB7AAB8AAB8AAB8AQF8jIqtxcPDxcPDxcLDxsPExsTExsTE\r\n        xcLDxsPCjYqvVFKcISCKS0qal5S0urbBysbGysbHzMnKzMrKzcvL0M7OammpAACCAACCAACCAACCAACC\r\n        AACDAACDAACDBweFhYOwpKKjiISF////////////////////////////////////////////AACAAACA\r\n        AACAAACAAACAAAB/AAB/AAB/AAB/CwuDtrO0xMLB09DQ19XW29ra3Nzb3drc3dnb29nZ2tnY2tnZ2tfY\r\n        2tfY2tjY2tfX2tfX3Nra3drb3NnZ3Nra3NrZz83NpqSkpqSk////////////////////////////////\r\n        ////////////////////////////////5OHi5OHi4N3e4N/f4N/e4uDg4d7e4d7f5ODh4t/f4d/e4uDg\r\n        4N3e4N3e4+Dh4t/f4d7e4t/f4uDg4eDg4d/f4t/f4uDg4N7f4d7f5OHh5uPj5uXk5OPi4+Hh4d7e4uDg\r\n        5ePj5eLi4Nzd////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////oZ+foZ+goqChoqGio6Gio6GhpKOjpKOjpaOjpKKipKKipKOjpqSkpKOioqGglpSU\r\n        h4WEend3eHZ1eXZ2enZ3eXZ2dnR0eXZ2fXl5fHp5fnx8f3x8f3x8fnx8fnt7gH19gX5/f3x9f318gX9+\r\n        gn9/g4CBgn9/goB/gn9+gn9+g4CAhYGBhYOChoOChICAgoCAg4GAg4GAgoB/hIKBh4SEioaGioeHiYWG\r\n        iYaGioiHioiHiYaGjImJjYqLjIqKi4mJiIaFhYODh4SEjImIjouKioeHiYWGi4iHjoyMjIqLi4mIj42N\r\n        j4yNjIqJjYqKkI2MlJGRlJKSlJKSlJGRlpKSlZKSlZOTlpSUmJWVmJaWl5aVl5aVmpiYmZaXmZaWmJWV\r\n        mZaVm5iXnJmYnZqanZuanJmZnJiYnJmZnJqanZqanZqan52coZ+foZ+fmpebeniQSkl/BwdmAABkAABk\r\n        AABlAABlAABlAABmAABmAABnAABnAABnAABoAABoAABpAABpAABpAABqAABqAABqAABrAABrAABsAABs\r\n        AABsAABtAABtAABtAABuAABuAABvAABvAABvAABwAABwAABwAABxAABxAABxAAByAAByAAByAABzAABz\r\n        AABzBgZ2gH+gtbOytLKytbOztrS1t7W1t7S0t7SzgoCiCQl6AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB5\r\n        AAB6AAB6AAB6AAB7AAB7AAB7AAB7AAB8ExODubi+w8DAxMHBxMHBw8HCxMLDxsTEx8XExMHBWVidAAB/\r\n        AAB/AwOAHR2JTUybop63xcLFzMnJzMrLzs3N0M/OiYi0BQWDAACCAACCAACCAACCAACCAACDAACDAACD\r\n        YF+ktrW0iISFn5yc////////////////////////////////////////////AACAAACAAACAAACAAACA\r\n        AACAAAB/AAB/CwuDkY+z09HR2tfX2tfX2NXV2NbW2dbW2dbX2dfX2dbW2tfY2tjZ29na3drb2dfX19TU\r\n        2tjY3Nrb2dbX2dfX29nYx8XFpqSk////////////////////////////////////////////////////\r\n        ////////////////39zd4+Hh393d4N3e4d7e4N3d393d4t/f5OLi5eTk5+Xm5+Tl4+Dh4d/f4N7e4N3d\r\n        4N3d4uDh4uHh4uHh5OLi4+Hh4N3d4d/f5OLi5OLh5OLh5OLi4+Dg4t/f4+Dg6OXl7Orq5+Xl5+Xl////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////oqGio6Gio6GhpKKhpKOjpaOkpKOjoqGho6KipKKioqGgoqCgo6GhoqCfn52clJKRiIWF\r\n        e3h5dnR0dXJyeHR0end3end3e3l5fnt7fXp6fnt6fXp6fnx8gH19gH59gH5+gH5+gH5+gX5/gn9/gX5+\r\n        gn9+g4B+g4CAg4GAhIKCg4GAhICAg39/hIGBhYKChIGAhIKChoWEiIWFiYaGiIaFiYaGioeIiIWGiIWF\r\n        i4mIjIqJjIqJioiIhoWEhYODiIWFioeHjouKjYqKi4iJi4eHiYaGhoWEi4mIj4yMj4yNjYuKjouLkY2N\r\n        kY+OkY+Pko6PlJCQk5CPlJGQk5CRlJGRk5CQlpSUmJWVl5STlpOTl5SUmJWUmJaVmJaVmJaVmZaWmpeW\r\n        mpeWmpiXnJqZnJmYm5iYmpiYnJqanpuan5ycn52coJ6doJ6doJ6ek5KaY2KIMDB2AgJlAABkAABlAABl\r\n        AABmAABmAABmAABnAABnAABoAABoAABoAABpAABpAABpAABqAABqAABrAABrAABrAABsAABsAABtAABt\r\n        AABtAABuAABuAABuAABvAABvAABvAABwAABwAABxAABxAABxAAByAAByAAByAABzAABzAABzERF6mpmo\r\n        srCvtLKytrS0uLa1t7W1tbOytrSzeXefEhJ9AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB6AAB6AAB6\r\n        AAB6AAB7AAB7AAB7NTWPwb6/wb29wr+/w8HBxcTFxMLDwb+/w8HAvry/Hh6IAAB+AAB/AAB/AAB/AAB/\r\n        GRiIRkWYj42yysjJzMrKy8nJmpi3AACBAACBAACCAACCAACCAACCAACCAACCAACDKiqSwb7BtbKyn5yc\r\n        paOj////////////////////////////////////////////AACAAACBAACAAACAAACAAACAAAB/AAB/\r\n        ERGGi4m21tPT19PU2NTV2dbX2tnY2NbW1tPU2NTV2tfX29rZ3dvb29ra19XV1NHR19XV2tnZ2dbV2dbW\r\n        19TUtrS0trS0////////////////////////////////////////////////////////////////3Nra\r\n        39zd5ePj4eDg3tvc4Nvd4N7e4N7e4d7e4eDf4uDg5OLj5uTk5+bl5uTk5OHi5OHi5ePj4+Li4d/g4N3d\r\n        4+Lh4+Lh4+Dg5uPk5+bm5ePi4t7f4+Dh5OHi5OLh4uDg5ePj6OXm5eTk5eTk////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////pKKhpKOjpaOko6GhoZ+fo6GgoqChoJ+foZ6fo6Cgo6CgoZ+goqGgpKKioqGglJKShYGBe3d3\r\n        e3h4eXd3eXZ3e3h4fHl4fnp5fXp6end4fHh4fnt7gX9/gH5+fnx8fXp6f3t7f318gH5+gn9+gn9/goB/\r\n        gX5+gX9+g4GBhIGCgn9/goCAg4GBhYODhoSEhoSEhoOChYOCiYaGiYWGh4SEhYKDh4SEiYeHiIaFgn5+\r\n        hoODjIqJjYqJi4eHiYaGjImJjIqKhYODf319gH5+h4SEjYuKjouLjouLkI6Nko+PkI6OjoyMkI2OkY6O\r\n        kY+OkY+Ok5GRlJGRkpCQkpCPlZSSlJKRk5CQlZORmJWUmJWVmZaWl5WVlpOTlpOTmJWUmZaVmJaWmpiX\r\n        mZeWmZaXnJiYnJmYmZeXnJmZnpyboZ+foJ2en5ycoZ6dop6ekpCaYV+IJiVyAABlAABlAABlAABmAABm\r\n        AABnAABnAABnAABoAABoAABpAABpAABpAABqAABqAABqAABrAABrAABsAABsAABsAABtAABtAABtAABu\r\n        AABuAABvAABvAABvAABwAABwAABwAABxAABxAABxAAByAAByAAByAABzAABzNjaFs7GwtLKxtrOzt7W1\r\n        tbS0sq+vtLKwt7W0g4GjAAB3AAB3AAB3AAB4AAB4AAB4AAB5AAB5AAB5AAB5AAB6ERGAAAB6Hh6FLi6L\r\n        a2mfvbm6wLy9wb/AxMPDxsXFxcPDwb6+wr+/lJKxAAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACALCyP\r\n        Z2aiqaa3uri/GRiJAACBAACBAACBAACCAACCAACCAACCAACCDw+Iram/zMrKxsXEpaOjq6mp////////\r\n        ////////////////////////////////u7i4AgKCAACBAACAAACAAACAAACAAACAAAB/DAuDiIWz1dLT\r\n        2NXW29na3Nvc2NfX1NHQ1tLS2tfY3Nra2tnZ2NbW1tTT1dPS1tTU2dfX29nZ3tvb09DQtrS0////////\r\n        ////////////////////////////////////////////////////////3Nra3Nra3tvc5ePj4uDg3trb\r\n        3dra393d4N7e39zd3dzc3tzc3tvc4N7e5OLj5uTk6ebn6Obn5eTk5uPj5uPk4uDg4N3d4uDf5ePj5uPk\r\n        5uPk6Ofm6Obm5+Tl5uTl5OPj4d/f4d7e4uDg5eTk////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////o6GhoZ+fo6GgoqCgoaCfoqCgo6GhpKKio6KioaGgoqGhpaKipaKipaKiop+elJGSg4KCd3V1eXZ3\r\n        e3h4e3h4fHl4fHh4end3eXd3fXt6f359e3l5fHl4fnt6gH19gH5+gX5+f319f3x8gX19gX5+goCAg4GA\r\n        gX9+gH19gn9/g4CAgn+AgX9+g4B/hYOCh4WFh4WEhoOChoKDhYKChoSEhIOCgn9/iISEjYuKjoyKioiI\r\n        h4SEiISFiIeGgX9/g4GBiISEiYWGi4iIjImKjYqKjoyMj42NjouMjoyLj42MkI6OkI6NkI6OkZCPk5GR\r\n        kI6OkI2Nko+Ok5CPko+PlpSTlpSTlJGRlZKSlpSUlpOTl5OUmJWVl5SUl5SUmJWVmZaWmpaVnJiXmpeX\r\n        mZaWmpeXnZuboJ2eoJ2dn5yboJ2co56eo5+eoqCgoJ6eZWKIQD98HR1wAABlAABmAABmAABmAABnAABn\r\n        AABoAABoAABoAABpAABpAABpAABqAABqAABrAABrAABrAABsAABsAABtAABtAABtAABuAABuAABuAABv\r\n        AABvAABvAABwAABwAABxAABxAABxAAByAAByAAByAABzAgJ0Z2aVsa6usrCvtLOzsrCwsq2us7CwtbOz\r\n        tbOzeHefDw98AAB3AAB3AAB3Cwt7AAB4JyaGIiKFQ0KQYF+aeXejlpWtkI+qvbm4tbG3vru7wb6/wL7A\r\n        wL6+wL6+w8HAw8LCwsDBbm2jAAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAFRWHVlWdHh6K\r\n        AACBAACBAACBAACBAACCAACCAACCAACCBgWEhoSwy8nIy8jIwr6/q6mpxsTEvby7qKWl////////////\r\n        ////////raurwb+/u7i4Pj6WAACBAACBAACBAACAAACAAACAAACAAAB/AAB/g4Gy2NbW2tjY2djY1tTU\r\n        1NLR1NLS1tTU19TV1tTU1dPT1tPT1tTT19bV29nZ3t3d3dvbxMDBxMDB////////////////////////\r\n        ////////////////////////////////////////5ePi5ePi3tzc393d39zc3tvb29jY3Nra3dvb3tzc\r\n        3tzc3tzd3tzc3dvc3tvb39zc5OHh5ePk4+Hi5eLi5+bl5OPk4N3e4d7f4uDg4d/f5OLj5+Xm6Ofn5+Xm\r\n        5OLi4+Lh4+Hg4uDg4+Dg4+Dg////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        oqCgoaCfoqCgo6Kio6KhpKKipKOio6CgoqCgpKGhpKKipKKipaOjpqWkoZ6ek5GRhYODenh3fXp5fHt6\r\n        eXd4eHV1fHl5fHp5e3d3fHp5f3x7f3t7gH19gH5+fnx8fXp7fnt8fnt7fXp7gH18gX9+gn5/gn19gX5+\r\n        gH19fnt7gHx9hIGBhYSDhYODhoSEhoOChYOChYOBh4WEhoODhIGBhYOCh4SEiIWFioiIh4SEhYOChoOD\r\n        jImIjouKi4iIjImJioiIjImJjYuLjoyMjouLjoqJjImIjYuLkI2NkY6OkY+OkY+PkI2NkI2NkI2NjouL\r\n        kY6Oko+Pko+PkY2Nk5CQlJKSlpOSlZKSlZOTl5STlpOTlJGRl5SUm5eXmZeWl5WVmZaWnJmZnJqanpuc\r\n        oJ2coZ2doJ2coJycn5ycoJ+eoZ+eoZucoZ2gjo2aZmSLPTx8GhpvAABmAABmAABnAABnAABnAABoAABo\r\n        AABpAABpAABpAABqAABqAABqAABrAABrAABsAABsAABsAABtAABtAABtAABuAABuAABvAABvAABvAABw\r\n        AABwAABwAABxAABxAABxAAByAAByAAByNzaFrKepr6yssK6usK2stLCvtrO0sq+wsq+vs7CwdXOdHBx/\r\n        U1KTTk2SammbhoWll5equLW2qqezuri3uri4uri4u7i5u7i4vLm6vLq7vry8v72+vbu8vbq6vbu7v729\r\n        ube6RUOTAQF9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACABASBAACAAACAAACBAACBAACB\r\n        AACBAACBAACCAACCAACCVFSgzMnKzsrL0c3NzMnJxsTEvby7qKWlxcLBu7e4uLS1xsTExsTEraurwb+/\r\n        ysfHyMfLTUueAACBAACBAACBAACAAACAAACAAACAAACAERCFeHauz83R1dPT1dLS09DR0s/P0tDQ1NDR\r\n        1NHR09DQ1NLS1tPT2NXV2djY29ra19XVvLq6oZ+h////////////////////////////////////////\r\n        ////////////////////////3dvb4N3d3t3c29ra29jZ29na3dvb3NnZ29nZ3dvb3tzc3tvc4N7e4d7f\r\n        3tvb2tfX3NnZ4t/f5OLi4uHh4uHh4uHh4N7e4N7e3tzd4N7e4+Li4+Dh4d7f4+Hh4t/f4uDg5ePj5+bl\r\n        5eLi5eLi////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////o6Ki\r\n        o6KhpKKipqOjpKGhop+epKKipaSjpaOjpqSkqaalqaalp6Wlp6WloqCglJKSg4GCeHV1e3h4e3h5end3\r\n        fHh4fXp5fHp5fXp6fHl6fHt7fnx7fnp6e3h5e3h3fHh4fXp6gH1+gn+AgX9+f319gn9/gHx9gX5+gX5+\r\n        gn9/g4CAg4GBg4GAg4B/hoOCh4ODhYKBgoB/gn9/gn1+hYCAioeHiIaFh4WEiYaGioaGiIaFiIaFiYeH\r\n        ioeHioeGjImJjIqKjouLioaFiISFjYqKj4yMkIyMj4yMj42NkI6NkY6OjYqLjYmJj4yLj4yLj4uLko6O\r\n        ko+Pk5CRk5GRk5CQko+OlJCQko+OkY6Nl5STmZeXlpSTlZKSmJSVmpiXm5mZm5mZnZybnpuboJycn52c\r\n        n52dn56doJ6eop6do6Cgo6Giop+goZ6gjImYY2GJOzl7EhJtAABmAABnAABnAABoAABoAABoAABpAABp\r\n        AABpAABqAABqAABrAABrAABrAABsAABsAABtAABtAABtAABuAABuAABuAABvAABvAABvAABwAABwAABx\r\n        AABxAABxAAByEBB3iYefqqapsK2tsK6usK6ttLGwtbKzsq+wsK6tsa2tsrCwrKyysbCzt7S0trS1ube4\r\n        ubi3t7W2uLW2t7S0t7S0uLa2ube3ure4uri4vLu7u7m5vbq6wL6+vry8u7m5u7e4npquFxeEAQF9AAB9\r\n        AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACBAACC\r\n        HBuMUVCgxsTKz8zNz8zLzsvLz83Nz87NzMrKxcLBu7e4uLS1xsTExsTEwb+/zMrJ0s7P1NHRxMLNREOa\r\n        AACBAACBAACBAACBAACAAACAAACAAACAAAB/dXSt1NLR1dLS0c7Pz8zM0tDP1dPS1NLR1dLS1dPS1dLS\r\n        1dLT09LS1NLS1tTUysjIoZ+hoZ+h////////////////////////////////////////////////////\r\n        ////3dvb3dvb2dbX3dra3Nra2tfY2tjY3Nra3Nra3Nra3dvc3dvb3dra3tzb4uDg4N7e3drb3dva4d7e\r\n        4+Dg4d/f4N7e393d3tzc3tzb39zc393d4N/f397e393d4d/f4t/g4t/g4+Dh5+Xl5eLi////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////pqOjpKGh\r\n        op+epKKhpKSjpqSkpqSkqKalqaenqKenp6Wlp6SkqKWlqKWloJ2dkY+Pgn+AeXZ2fHp5e3h4e3l4e3l5\r\n        e3l5e3l5fXt6fHl4e3h4fnt7fnt7fHp6fnt7gX5+gX5+f3x8gH19g4KAg4GAgH5+gH1+gX9+gH18gX19\r\n        gX1+g39/g4GAhYGBh4GBg39+hICAh4SDhoODhYKBhYOChIGBgn9/hIGBhoOChYOCh4SEiIWEhoKCiYaF\r\n        ioiHhIKChoKDkI2NjYuLiIWFioiIjYqKjouKi4mJjoqJkoyLkY2NjoyLj42Mj42NkI2NkI2NkY+OkI6O\r\n        kIyNkY6Nko+Oko+PlZKSlJKRlZOSmJSUmJOUmJWVmJeWmpqYm5qZm5iYnJmZn52dn56doJ6eoJ2doJ+e\r\n        op+goqGhoqCfop6cpKGhoqCin52ed3WQOjh7HR1wDAtrAABnAABnAABoAABoAABpAABpAABpAABqAABq\r\n        AABqAABrAABrAABsAABsAABsAABtAABtAABtAABuAABuAABvAABvAABvAABwAABwAABwAABxGxp6Z2WS\r\n        rq2ssK6usrCws7GxsrCvsK6usa2usq+vsa+vsa6usrCvsrCwsrCws7Cwt7S0ube4uba3t7a2t7a1uLW1\r\n        t7Szt7S0t7W1uba2vLm4vbu7ubm5urm5wL29vbu7ube3vbq6i4mqExOCAAB8AAB9AAB9AAB9AAB9AAB+\r\n        AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACBFBSIYWCkyMfKzMnKy8jI\r\n        ysjIycjHy8nJzcrJzcvLz8zMzszLzcrK0c7OzcvLycbGzcnJ0s7O0s/Q0c/Qx8XLIB+NAACBAACBAACB\r\n        AACBAACAAACAAACAAACABASCb26q1NLS0dDPz83N0c/P09LR1NLS19TU1tPU09DR0tDQ0tDQ1dLS1tTS\r\n        xMHBoZ+h////////////////////////////////////////////////////////////3Nra3dvb2dfX\r\n        2tfY2tjY29nY3Nra3Nna29nZ3Nra3Nna3NnZ3NrZ3t3c397e393d4N7e3t7d3Nra3tvb4N7e4N7e3drb\r\n        3dra3trb3tvb3tvb3tzc3t3d3tzc39zc4d7e4t7f4t/g5OPj5OPj////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////pKKhpKSjpaOj\r\n        p6Wlp6Wlp6WlqKamqKamp6akp6Wkp6SkqKWmqKWmqaanoZ6ek5GQhYKCenh4e3l5fHp6fXt6fHp5e3l5\r\n        fHh4fXl6fHp6e3l4fHp5gH19gX5+f3t8fXp6gYB/gH19fnt8f319gH18gX19gX5+gX9+f3x7f319gX19\r\n        hn59h4B/hYOCh4SDhYKCgn9/gn9+g4GAgX5+gn5+g4B/hYOCh4SEhoOChYKBhoODiYaGhYGCh4SFjoyM\r\n        jImJhYODiIWGjYqKi4iJioeGlJCMmJOQkIuKjYuKjoyLj4yMj4uLj4yMjYuKjoqJj4yMkI+Ok5CQk5CQ\r\n        kY+Ok5CQlpOTl5SUlZGRlpOSmJSUmpeXm5iYmpmZm5qanJqanpybnZubnpucoJ2doZ6eoaCgoZ+eoJ6e\r\n        oqGhoqCgoZ2cpKCflJKcgoCWYmCJODd6HRxxCgprAABoAABoAABoAABpAABpAABpAABqAABqAABrAABr\r\n        AABrAABsAABsAABtAABtAABtAABuAABuAABuAABvAABvAABvAABwAwNxZ2WTp6SnrKqpr66usK6usK6u\r\n        r62tr62ssq6usa6vsK2usK2tsa+vsa+vsa6usrCwtLGytbKztrOzt7W1t7a3uLa3uLe3ube4uri4uri4\r\n        u7i3ure4uLa3vLq6vry8ube3t7S0t7a4a2mfCwuAAAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+\r\n        AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBCwuFQD+XaWilk5Gzrau7wr/CyMXFycbGyMXF\r\n        yMXFysfHzMjJzcrLy8nIysjHzcvLz87Nz83NzsvM0M7Oz87OtbLDLi2SAACBAACBAACBAACBAACBAACA\r\n        AACAAACAAgKBdHOt0M3O0M3M0MzN09DQ09LR1dPT09DQ0s/P09HR1NLS19XV09HRtbKytbKy////////\r\n        ////////////////////////////////////////////////3Nra3Nra2dfY2tnZ2tfX2dbW2dfX29nZ\r\n        29nZ29nY3Nna3dra3dva3Nra29na3Nra3dvb3tzc3Nra29jZ3tvc3t3d3tzc3tvb3tzc393d3tvb3dra\r\n        3dzc3t3d393d39zc397d4N7d4N/f4d/g4d/g////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////paOjp6Wlp6WlpaOjpaOj\r\n        qKamqKemqKamqqioqaioqaioqqioqaenq6inq6mooJ2ekY6PgoCAe3l4fHl5e3h4enh3eXd3enl4eXh3\r\n        enh3fHl5f319gH59fnp7f319fXp7fnt7fn19f3x8fnt7gH19f3x7fnt7fnt8gXx8iH99h4F+g4GAhIGB\r\n        hYGBhIGBhYKChoSEhYODgoB/g4GAhIKBhYKBhYKBhYOCh4WEh4SEhYKCh4SFi4mJiIaGh4SEh4ODi4eI\r\n        i4mJjYqIlI+Mk46NjIeIjIqKjouLjYqKjouLjoyMjouMjoyKjoyLjouLkI6OkI2NkY6OkY6Nko2NlI+P\r\n        lZKSlJGRlpOSlZGSl5SVmJaWmJWVnJiZnZqbnJqZm5mZnJmZm5mYnJqZn5ubn52dnpycnpuboJycoZ+f\r\n        oqCho6Cho6GhlZKbgn6TX12INTR5GhpwCgpsAABoAABpAABpAABpAABqAABqAABqAABrAABrAABsAABs\r\n        AABsAABtAABtAABtAABuAABuAABvAABvBQVxR0aIq6mqrKqqraqrr6ytr62trqysraqqr6yssrCwsrGx\r\n        sK6usK2trqysr6yssrCws7Gysa+vsK6utLKxtrW0tra2tbS1trS0uLe3uri4uri4uba3uLW1ube3vbu8\r\n        vLq7ubW2u7i4r662Pj2QAQF7AAB7AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/\r\n        AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBBweDGxuKODeUaGalmpe3paK5w7/EycbHycbFysbGycbG\r\n        ycjHysjIysnIzMrKzsvLzszMz8zNzczMzcrKq6m/Hx6NAACBAACBAACBAACBAACBAACAAACAAACAAACA\r\n        fnyw0tDQ09DR1dHS1NLR09DQ0c7O0c7O0tDQ0tHR1tPTy8nJtbKy////////////////////////////\r\n        ////////////////////////////////19TV19TV19TV2dfX2NbW2NXV19TV19TU2dbW29jY29na29jZ\r\n        3NnZ3Nra29nZ2tjY2tfX2dbX2tbX29jZ3dvb29ra29ra39zc4N/f3t3d3Nra3NnZ3dra3dvc3tzd3dvb\r\n        3Nra393d4N/f4d/g////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////paOjpaOjqKamqaeoq6mpq6qq\r\n        qqioqaeoqaeoqqinqqinqqenqqeoq6ipq6mqoZ+fko+PgH5+eXd3end4eXZ2eHZ2end3fHl5fHl5fHp5\r\n        fHp5fnx8gX9+gH5+fnt8e3h4fHl4fnt6fnt6fHh4fnp5gXx8gn99gn9+gX19gX59hIGBhYODhYKCh4WE\r\n        hoSDhYOChIKCg4CAg4CAhIGBhIGAhoOCh4SEh4SEiYeGiYaGh4SEiIWFiYWGiYWFioeHi4iHi4eHi4eH\r\n        i4eIjYuLjoqLjImJjImJjIqKjIuLjoyMjYuLj4yMkI2NkI6OkI+Oko2MlIuJk42Mk5GRlpOSmJWUlZKS\r\n        lZOSlZSUl5OTmpeXnpycnZmZnJmZm5iYm5iYm5eYnZianJmZm5mZnJqanpucoJ2doJ6eoJ2cop2cpJ+e\r\n        o5+eop6ej46YfXyUXFqIMjJ5GRlxCAhrAABpAABpAABpAABqAABqAABrAABrAABrAABsAABsAABtAABt\r\n        AABtAABuAABuAABuNzeCoZ6nq6mpqqmprKuqr66ur6ysrKipraqqsK+usbCwsbGxsK+urKqqq6morauq\r\n        sa6usa+wsK6vsq6vtLGxtLOztLOztLKzs7CxtrSzubi4ubi4uba3uLW1ura3uba3urm5vbu8vru8q6m1\r\n        MDCKAAB7AAB7AAB7AAB8AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/\r\n        AACAAACAAACAAACAAACAAACBAACBAACBCAiEHx6NISGNPj2XcW+pnpy4xcPFycbGx8TEx8TEx8TEycbH\r\n        zMnKzczLzczLzcrKzMjJzczLoJ+9Dw6HAACCAACBAACBAACBAACBAACBAACAAACADQ2FdXSt0M/Q0s/P\r\n        0s7O0s/P0c/P0M7O0c/O0c/P0c7Pwr/Al5WVl5WV////////////////////////////////////////\r\n        ////////////////29nZ1tTT1dPT1tPU1tLT1tTU19XV19XV2dbW2dfX2djY2tjZ2tfY3NnZ3NrZ29nZ\r\n        29rZ2tjY2dbX2tjY3NrZ3NnZ29jZ3dvb3tzc3dvb3NnZ3Nvb3dvb3Nra3Nna3dra3dra3tzb4d3e4d3e\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////qaeoq6mpq6qqq6qqqaeoqaenqaen\r\n        qaenq6mqrKqqrKqqraurrKusq6mrq6mqn5ycjYuKfnt8dnV1fHh3fnl4e3Z3eHV1eXd2e3h4f319gH59\r\n        fHl5e3d3fHh4fXp5fXp6fnl5fnh3f3t6f318gX5+gn19gX18g4CAgn9/gX18g39+g39/hIGBhYKCg4GA\r\n        hYKCg4GBgn9/g39/hYKCh4SEiIWEh4SEiYaGjIuLjYuKioaGiIWEioaGh4SEh4WFi4iIjImKjYmJjYuK\r\n        jImJi4eHjYuKjIqLioeIjYqKkY2Nko6OkI6Oko6Nk46MkY2Nk4+PlJGQk5CQlZKSk5GQlJKSl5SUmZiY\r\n        nJqanJmanJqbnJqbnJmZm5mZm5iZmpeYmZeXm5mYm5iYnpqbn52doJ6doZycoZ2cop+foZ2eoZ6foqCf\r\n        oZ6fkI6ZfXyUWViIMDB5GBdxBwdrAABpAABqAABqAABqAABrAABrAABsAABsAABsAABtAABtAABtIB95\r\n        jIqfr62trqurp6Skqaemraurrqusq6eoraursK+vsK+vsK+vrq2sq6ioraursa+vsa6vsK6usa+vtLCx\r\n        s7CwsrGxtLKytbOys7GxtLKyt7a2t7S1uLS2t7W2ure4ube2trW0uLW2t7S1kpCpERB/AAB6AAB7AAB7\r\n        AAB7AAB7AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACA\r\n        AACAAACAAACBAACBAACBAACBAACBAgKDAwODExOIQkGYdHOrk5K0xsPDycXGycXGycbHzMrLzcvLzMjI\r\n        ysbHy8nJzMvLkI+0CAiFAACCAACBAACBAACBAACBAACBAACAAACAAACAenmtzszMzszMzszMzs3M0M7O\r\n        0c/O0M3N0c7PycfIraurraur////////////////////////////////////////////////////zczM\r\n        29nZ1tTU1NLT1tPT2dbV19bV19XV2tfY2dbW2dfX29nY29nZ2tjY2tnZ2tnZ2tjY3Nva3Nra3Nra29ra\r\n        3Nva3Nna3Nnb3Nra2tjY2dbX2tfX2tjZ2tnZ2tjY29fY3NnZ3dvb3dra39vc39vc////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////q6qqqaeoqaenqqioq6ioq6mqrKqqrKur\r\n        rKqrrKqrrKqqrKmpraqqrKqprKqqnpyckIyMhYB+fnh2e3Z1eHZ1end3e3d4end3eXV1end2e3h3fHl5\r\n        f3t7gXt5fXd2fXp5gH59gH19gHx8gH19gn9+gX5+gHx8gHx8gX59g39/gn9/goCAg4GBgoB/gn9/g4B/\r\n        hIGBhYKCg4GAhIGBh4SEiIeHioiHioWDiYSDiIWEiIaGiIaGiYeHiYaFioaGi4iIjIqKjIiHjYmIioiH\r\n        hoKDi4iIj4yMkYyNkIyMkY+OkI+OkI2Nko+OkI6OjouLko+Ok5CQk4+Pl5SUmJaWl5WVl5WWmJaWmpeY\r\n        nZmZnZqam5qZmZeXmpiYm5mYnJmZnZqbnZubnpycnpubn52coqCgoqChoZ6foqGgo5+go6CgpKKiop+i\r\n        kY2ZeHaRVVSFLy55FhZxBgZsAABqAABqAABrAABrAABrAABsAABsAABtHh53c3KTqaanrausrqysqqWn\r\n        qKWlqqiorKmqrKmqrKmqraurrKqqraurr62traurrqysr62tr62tr62tsK2tsK6usa6vsrCwtLGxtLKx\r\n        tLKytbO0tbKztLGxtLKytLOzt7S0t7W0tbOztLGytLCylJKnQD+OFRSBAQF6AAB6AAB7AAB7AAB7AAB8\r\n        AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACA\r\n        AACBAACBAACBAACBAACCAACCAgKDAgKDAACCGBeKVVSgkZCzpaS6wr7GxsPGx8TFyMXFysfHy8jJy8nJ\r\n        dXOrBgaEAACCAACCAACBAACBAACBAACBAACBAACAAACAgH+w0M7OzcrKzcrJ0M3N0M7OzszM0c/Py8nJ\r\n        raur////////////////////////////////////////////////////zczMzczM1NHR1tPT09HR1tTT\r\n        2tjX19XV1dPT2NXV19TV2NXW29nY2tjY2dfX2NbX2NbW2NbW2NbW29jZ3tzc3dva29nY29jZ2tjY2tjZ\r\n        2dfX19XV2NXV19XV19XV2dfX2tjY2tnZ3Nra3NnZ39vc////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////qqioq6ioq6mqq6qqq6qrqqiprKmprampraqp\r\n        q6mpq6mprKqrrKqrrKqqrKmqnpqakIuLf3x8eXd3eXd3eXV2eXV1eXV1enZ1eXV1fHh3gHp4fXl4fnt6\r\n        fXp6fXl6fnt7gH59gH19gH19gH18gH5+g4GAhIGAgX9/gX5/gn9/gX19g39+gn5+goB/gn9/gX9+gX5+\r\n        gn5+gn9+hYGBiIKChoGAhIKBhoSEioaGiIWFiIaFiIWEioeHi4iIioeHioeIioeGiYeGi4iIjouLjouL\r\n        ko6NkY6OjIqLjImIkI2MkI6OkI2NkY6Nk5CPkpCPlZGRlpOTlJKSlpOTl5OTmpeXnJmZm5iYmJaWl5WV\r\n        mZaWnZqanZubnZubm5mZm5iZmpiYnZubn56eoJ6foZ+foaCgoJ6fnpydoJ2doZ2doJ6eoJ6en5yej42Z\r\n        eHWRUlGFKyt4FRVxBARrAABqAABrAABrAABsBARtaGaPpaKjp6WlqaeoqaeoqaanqKamqKamqqiorKqq\r\n        rKmqq6ipq6qqrKqrrausraurrauqrKqqrqurrqusraqrrq2tr6ytsa+vsa6vsq+wtLKys7Cwsq6us7Gx\r\n        tLOztbOztbOztLGxtLGxtrOztbO0tLS0paOuhYOkRUSQGhqCBAR7AgJ8AAB7AAB7AAB7AAB8AAB8AAB8\r\n        AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACB\r\n        AACBAACBAACCAACCAACCAACCAACCAACDFBSKPDuXaGelgH6tnZu3r6y+ysfIysjIy8jIbWuoAACCAACC\r\n        AACCAACBAACBAACBAACBAACBAACAERGGiIezzcrLzMjIzcvKzs3MzszMzMnKuri4uri4////////////\r\n        ////////////////////////////////////////1dPT1NPSz8vM08/Q09DQ09HR1dPT1dLS09HR1dPS\r\n        1dPT1dPT2NbW2NbW2NXW2NXV19TU2NbX2dfX2dbV3Nna29jY2NbW1tXU19XV2dfY2tfX2dfX2NbW1tXV\r\n        1tTU2NbV2NfW2dfX2tfY29na29na////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////q6qqq6qrqqipq6mprKmprKqpq6mprKmqraqqraqs\r\n        raurraqrraurraqqq6monJmZjIqJfn18eHZ2enZ2enV1dnJydXJyeXZ2fHp6fHl4e3Z2fHh4f3x7fnt7\r\n        fnt7fnt7f3x8f3x9gH5+gYB/g4CBg4CAgn9+gX5+gn59gH18f3x8gH19gH18gn59gn59gX19g4CAhIGB\r\n        goCAgX9/hIGBhoOCh4SFiIWGiYaGioeGioeGiIWFiIWGiYeGi4mJjYuKjYqKj42Mj42Mj4yMjYqLjImJ\r\n        jYqJkI2MkY6OkY6OkY+OkpGQlJGRlJCQkpCQlZKSmZWWmZaXmZeYl5SUlpOTlJKSlpSTmpeWnJmZmpiY\r\n        m5mZm5aXm5eYm5mZnJqanJqan5ucn52dm5qbnJqanpqan5ycn52eoZ6eoZ6doJ6eoJ+enpyfjoybdXOR\r\n        TkyDJyZ2GRlyBgZtAABrVVWImpefpqOjp6ampqWmp6Slp6WlpqSkqKWmqaenq6qprKqrrKqsrKurrKqr\r\n        rKmqrKqqq6mprKqqrKqqrqqrrqusrqysrqurr6ytr62tsK2usa+wsa6usq+vtLOztbSzt7S1tbO0tbKz\r\n        tLCws7Cws7CxtLGytLGxs7CvtLGxmJWpdXKfSEeRGRmCBAR8AgJ8AAB7AAB8AAB8AAB8AAB8AAB9AAB9\r\n        AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACBAACC\r\n        AACCAACCAACCAACCAACCAACDAACDDw+IIiGOMzKUR0abb2+pl5W2wsDFR0ebAACCAACCAACCAACCAACB\r\n        AACBAACBAACBAACBCQmDmJa4zMjJy8nJzczL0MzNycbHrqurrqur////////////////////////////\r\n        ////////////////////sK6u1dPT09DQ0M3N0s/P0tDQ0M7P0s/Q1NHR09DR09HR1NLS09HS1tPU1tPU\r\n        1dPT19XV2dbW2dfY2NbW19PT19TU2tjY2NbX1NLS1tXU2tjY2NbX2dfY2NfX2dbW2NbW2dfY29nZ29nZ\r\n        29jZ3Nrb3Nrb////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////q6mprKmprKqpq6mprKuqrKqrraqsrqysraurrquqraqq\r\n        rKqqrKqpraqqrKqqnJubioiHfHl4dnNzdnJydnNzeXZ2eHV0eXZ1fXl5fXp5fHl5fHh4fXp6fnp6f3t6\r\n        fnx7gH5+gn+Agn9/gX5+goGAgX9/fnt7fnt6fXp6f3t7gX9+gn9/gX59goB/hIKBhICAg3+AhICAhIGB\r\n        hoKDiISFh4WEiYaFiYaFiISEh4ODiIaFiYeGioaGi4eHjIqKiYiJioiIjoyLjouMjYqKjYqKj4yMjYqK\r\n        jYqLkI2NlJKSk5KSkI2Oko+Pl5SWlpOUlJKTl5WVlpSUlJGRlZKSmJWVmZWWmZWVm5mZm5mZm5eXnZqa\r\n        nJqam5iYnJmZnJqam5qanZuaoJ2dn52en52dn5ycoJ2doJ2eoJ+foZ+fop+goZ+fm5qdiYaWfnuSdHGQ\r\n        XlyJpKKipaKipqKjpaKjpqSkp6WlqaenpqSlp6WlqKWmqaanqqiprKmprKqpq6ioq6mpqqmpq6mprKur\r\n        rKurq6mpq6iorKiprqursK2usK2ur6ytsK6us7Gysa+wsq6vs7CxtLKztbO0trW0trSzsq+wsq6vs7Cw\r\n        sq+vsq+vsbCvtLGyubW3vry8nZ2xdHOhREORFhaCBAR8AgJ8AAB8AAB8AAB8AAB9AAB9AAB9AAB9AAB+\r\n        AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACBAACBAACBAACCAACCAACC\r\n        AACCAACCAACDAACDAACDAACDAgKEAACDAACDICCONzaWAACCAACCAACCAACCAACCAACBAACBAACBAACB\r\n        AACBDg6Fm5q5y8nJzcrK0M3NzcvLwb29wb29////////////////////////////////////////////\r\n        sK6usK6u0M7O0c7O0c/O0c/Q0dDQ0c/Q0tDQ0s/Q08/Q0tDQ09HR0tDR1dPT1dPT09HR1dPT2NbX2NXV\r\n        1tPT1NPT09HR2NXV19bW1NLT1tTU2dfX2NfX1tXW1tTU2NTV2dfY3Nvb4N/f4N7f3dzc3Nrb////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////q6mprKuqrKqrrausrqurrKqqq6mpq6mpq6mpq6iorKqprqys\r\n        rq2uraurp6WkmJaWiYeGe3d2e3d2eHV1eHV1end2end3end3end2e3d3fXl5fnp6fnt7fnx8fXx8fHl5\r\n        fnx7gH9+fnt7fXp6fnt6f317fXt7f319gn9+g4B/goB/gn9+g359hYB/hYGBhIGBhoKCh4ODhoKCh4OD\r\n        iYaGhYKCg4CAh4SEioeGhoOCh4KDhoSEhYODiYaFjImJjYqKjImJjouLjoyLiYeHjImJkY2Nk5GRk5KR\r\n        kY2NkY2NlJOTlJGRlJCQlpSUmJaVlJKSlZKSl5SVmJaWmJSVnJmZm5mZnJmZnZqam5mampeYnJqanJqa\r\n        nJqanZubnZucnpqbnpubn5ycn5ydn5ydn52doJ6en52doZ+foaCgoZ+foZ6eoZ+hop+ho6CgpKGho6Ch\r\n        pKGhpaOjpqSkpqOkpqSlpqWkpqSkp6SlqKWlp6Skqaamq6ipqaenqqenq6mpraysq6qqqKamp6Ojqaam\r\n        rKqqraurr6ytr62tsK+vr62uraqqrqmqsa6vsq+ws7GxtLOzt7W1t7S1tbKys7Cwsa+vs7Gxs7GxtLOy\r\n        tLOzt7a2uri4uba2uri4mJeucHChQUCRFBSCBAR9CgqAAAB8AAB8AAB9AAB9AAB9AAB9AAB+AAB+AAB+\r\n        AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACBAACCAACCAACCAACCAACCAACC\r\n        AACDAACDAACDAACDAACDAACDAACDAACDAACDAACCAACCAACCAACCAACCAACBAACBAACBAACBIB+MqKW8\r\n        zMnJzcvM0M7Owb6+nZqb////////////////////////////////////////////0tDQysfIzMrL0M7O\r\n        0tDR0tDR0tDQ09DQ0tDQ0c7O0s/P09HR0tDQ0tDQ1NHR1NPT1NPT1NLT1NLT1NHR1dLS1tTU1dTT1tTT\r\n        2NbW19XV19XV19TV2NbX2NbW1tTU1dPT19bW29va4N7e4N7e3dvc3dvc////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////rausrqurrKqqqqmpqainqqioqqioq6ioqqeoq6qqrayrrq2srq2r\r\n        rKqqqKWlmpeXiYeHe3d3end2enZ2eXd3eXd3eXZ1eXZ2eHV2dXR1d3Z3eHd3eXZ2eHZ2eHZ2eHh2e3l4\r\n        fHp6fnt7f3t7fnp6fXt6fHp7fnx9f3t7hn58iYB9hX9+goB/hoKCh4SEh4SEhoODh4SFiIaGgoB/f3x8\r\n        hICAh4WDhIGBhYKChoKCioaFi4iHioeHjIiIjIqJjYqKi4qJjYuKkI2NkI6PkI6Ok5CPkpCQk5CQlZOT\r\n        kpCPko6PlZKTl5WVlpSUmJSUl5SUlpOTl5OUmJaXmpiYmpeYmJaWmpeXm5eYnJmam5aYm5iYmpmYnJmZ\r\n        npqan5ybnpucnZqbn5ydoJ2eoJ2eoJ2doJ6eoJ6eoJ6eoJ6eoqCgo6Gho6ChpKOjpaSkpaOjo6Cho6Ch\r\n        paKjpaKio6Cgp6Slqaanp6Wlp6WmqKanp6Wlqaamqqipq6mqq6mpqaamqaamqaenqqioq6iprqytr62u\r\n        rausrKqrrKmqrqurr6ytsK2tsK6usrCwtbKzt7S1s7Gxsq6vtLCxtbOztrOztbS0tLOztLKytrO0trOz\r\n        t7W1uri5u7q7uri6lpaubm6haWifOjmPHByFCQl/AAB9AAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/\r\n        AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACBAACBAACBAACCAACCAACCAACCAACCAACDAACDAACD\r\n        AACDAACDAACDAACDAACDAACDAACCAACCAACCAACCAACCAACBAACBAACBAACBJCSOxMLFy8nJzczMxMLC\r\n        nZqbnZqb////////////////////////////////////0tDQ0tDQz83NzMrKz87O0c7Q0c7P0MzN0s7O\r\n        1NDQ0s/Q0tDQ0tDQ0c7P0s/Q09HR09HR1NHS1NLS09DQ0c7O0s/P1dHS1tPT1dTT1tTU19XU19XV19TV\r\n        2NbW2NbW1dTU1tPT2NbW2djY29ra3Nvb2dfX2dfX////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////qqmpqainqqiorKqqrKqpq6inq6iorKqqrqyrraysraurrqysr62trqys\r\n        qKammZaWh4SFenZ2end2dXNzeXZ1eXZ2c3FydHN0e3l5end3d3R0dnR0e3h3enh3eXh4enh5fHp6fHl5\r\n        eHV1dnR1dnN0fHh5hX59hn57gXt6gX5+g4CAhIKCg4CAg39+gH19g4GBgoB/e3h3fnp6hICBhYKBhoOB\r\n        iISEi4eGioeHioeHi4iHioeHh4WFhIODiYeGj4yMjYqLj4yNlJGRk5GRko+Qk5KSkpCPkY6OlJGSlZKT\r\n        lZKSlZKSlJCRk5CQlZKTlpOUmJSVmJWUmJWVmJSVmZaWmJaWmZWWmpeXm5iYnJmZnZqanZqanJmZnJqa\r\n        npybn5ydnpubnpubn52cop+foZ2en5ycn52co6CgoZ+foqGhpqSkpKKjoqGio6KhpKKho6ChpaKjpqOk\r\n        p6WlpqWlp6amp6Wlp6Slp6Wlp6Wmp6Wmqaemqaenqaanqqioq6enrKmqrKurrKqqq6ipraurrq2traus\r\n        r62tsK+vsa+vsq+wtLKztLKysq6vsa2utLGytrO0t7W1tLKzsq6vsq+utbOyuLa1trS0uLa2ube4t7W2\r\n        ube3u7i4ure4pqOxjoupY2KcNzeOGRmFCgqAAAB9AAB9AAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/\r\n        AACAAACAAACAAACAAACAAACBAACBAACBAACBAACCAACCAACCAACCAACCAACCAACDAACDAACDAACDAACD\r\n        AACDAACDAACDAACCAACCAACCAACCAACCAACCAACBAACBAACBWVifv73Czs3NzszMuri5oqCg////////\r\n        ////////////////////////////zs3Nzs3NzszMz83Nzs3N0M3Pz8zNz8vL0s/P09DQ0c3O0c7P09DQ\r\n        09HR0tDQ0s/Q1NHR09LS1NLS0s/PzszL0M3N09DQ1NLS1tTU19TV19TU19TU1NLR1NLR1tXU19bW2dfX\r\n        2dbW1tTU1dPU1tPT2dfX////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////rKqqrKqpq6inrayrrqurr62trq2trqysr62tsK6urayrrKiqq6mpq6qqpqOi\r\n        l5SUhYODfHh2gXt4e3d1eHV1eXZ2eHZ2eHV1e3h3e3h4e3l4enh3e3h4enh4end4enh4fHl5enZ2eHZ2\r\n        e3h4fnt6gX5+g3+Agn9/f3x8f3t7gXx6end2fXt7gH59f3x8gH19gH19g399h4OBh4KCh4SEiIWFi4iI\r\n        jIqKiYaGg4CAhIGCiYeIjIuLjouLjoyMkI6OkY6Oko6PkI6OkI6OkY2Nko6Oko+Pk5GQlJGRlZGSlpOU\r\n        lpOTlZKSlJKRlZSTlpOTl5SUl5WVl5WVlpWVmZeXmpeYmpiYmpiXm5mYnJqZnZubnJqbm5iZmpaWnJmY\r\n        n5ycoZ6eoZ6eoJ2doJ2cop+foJ2eoZ2fop+goZ+foqGho6GhoZ+fo6GhpqSlpaOkpKKipaSkpaSkp6Sl\r\n        pqWlp6Wmp6Wlp6WlqaenqKanqKWlqaamq6mpq6mqq6mpqqeorqusr62trq2trq2usK6vsa+vsK6usK6w\r\n        sa+vsK+ur62tsq+wtbOztrO1tLKzs7Cxsa+vsa+utbKyuLa2uba3t7W1trOztbKzt7W1urm4urm5u7m5\r\n        ure3trO3pqS0i4mrc3GiYmGeMDCNCgqAAAB9AAB+AAB+AAB+AAB+AAB/AAB/AAB/AAB/AAB/AACAAACA\r\n        AACAAACAAACBAACBAACBAACBAACBAACCAACCAACCAACCAACCAACDAACDAACDAACDAACDAACDAACDAACD\r\n        AACDAACCAACCAACCAACCAACCAACBCAiEXV2gvLm/yMbH0M/OxsTEoqCgpKGh////////////////////\r\n        ////////////ysjHz83NzsvLzsvMzszM0M/Pz83NzcvKz83N0c7P0MzNz83O0s/P09DQ0c7Oz83N0c7P\r\n        0tDQ0s/P0s/Q09DQ1NLR1NLS1tTU19TU1tPS1dPT19XV1dPT1NPT19bV2NbV1tTT1dLS09HS0tHR1NHR\r\n        1NHR////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////rayrrqurr62trqyssK2tsK2tsK2ur66trqysrKqqraqprauqr62tsK6uqKalmZWU\r\n        iISDenZ2eXZ2eHZ1eXZ2eXZ2eHV1eHV1end2eXZ2eHV1eHV1end3fXx7fHp6enZ3e3l5fXp6fXp6gH19\r\n        gX5+gH19gn59gXx7f3x7fHl6d3R1fXp6hYOCgn9+hYGAh4OBhoKBhYGCiIWFiYiHioiIiISEiIWFjImJ\r\n        jYuLjIqKjoyKjYuKi4mKjouMj42MjouLjouMkI2NkIyMkY6OkY+Pko+PlJGRlJKTlpOUlpOTlZOTkpCQ\r\n        ko+PlZKSl5WVlpOUlpSUl5SVmJaXmZeXmpeXmZeWm5mYnJiYnJiZnJqanJqZnpmZnpqbnZqbn5ycoJ6d\r\n        n5ycn5ydoZ2eop+goJ6foJ6eoZ+goZ6fn52doZ6epaKjo6KjpKOjpKGho6ChpaOjpqWlpqSlpaOkpqOk\r\n        qKanqKanqKamqaamqKamqaeoqqenq6mprKusraurrauqrausraqrrqurrqytrqytrq2sr66usK+wsK6v\r\n        s7Cxs7Gys7Gys7Gys7GxtLKytbO0trS1t7S1tbSztLGxtrKzuLa3urm5urm6uri5uba3t7a2ube3u7m5\r\n        t7a5vbu8sK63hYSoYWGdQECTDAyBAAB+AAB+AgJ/AAB+AAB/AAB/AAB/AAB/AACAAACAAACAAACAAACA\r\n        AACBAACBAACBAACBAACCAACCAACCAACCAACCAACCAACDAACDAACDAACDAACDAACDAACDAACDAACCAACC\r\n        AACCAACCAACCHh2MkI6yx8PEyMbGy8rLycfIvbq6pKGhxcLCuLW2oJ6e////////r62twLu9yMXFysjH\r\n        0c/Pz8zNzcnKzsvLz83NzszMzcrKzsvL0M3N0c/P0M7P0M3Nz8vM0MzNzszMz83N0c3O0M7O0c/Q1NDS\r\n        1NHR0tHQ1NPS1NHS0s7P0tDQ1dTV19XW19XV19TU09HQ0c7O0s/Q0dDQ0dDQ1NLT1NLT////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////rqyssK2tsK2tsa+vsa+vsK+vr62tsK2tr62sr6ysr62tr62tsK6usa+vp6SklpSThIKB\r\n        dnR0eHV2d3R0d3Nzd3R0eXZ1dnNydnJyeHR0e3l5e3l5e3h4fHl5fHh4fHh3fnx7gX5+f319gH19gHx8\r\n        g4B/gH18dnJzdXFyfXt7goB/g4CBhIGCg4GBgoCAhIGBhoSEh4SEiYaFi4qJjIqKioiIjIqKjoyMjYqK\r\n        jImKjYuLjYyLjIqJjouKjouMj4yNkY6OkY+OkI6Oj42NkY6Pk5KRk5GRk5CRko+PkY6OlpKSlpSUlZKT\r\n        lZKTlpSVlZOUl5SVmJWWmJWVmJWVmZWWmpaWnJqanJuanZqanpubnJqanJmanpqanZqbnJman52eoJ+f\r\n        oJ6eoJ2doZ6foJ+fnpycnpyco6ChpaOko6Giop+gop+fo6Gho6ChpKGjpqOjp6OkpaOkpqSmqaeoqaio\r\n        p6alpqSjqKamqaioqaioqaeoq6mpqqepqqanrqytr62uraurraursK6vsrCxsK6urqyssa6usrCwtLKz\r\n        tbO0tbS0tLOzsrGysa+wsa+vs7Gxt7S0uLe3uLa3uLW3t7S1t7O1t7S1trS0uLW1ure4vLq6vLq7ure5\r\n        vLm6vLu7sa62enijUlGYOTiRCAiBDAyCBQWBAAB/AAB/AAB/AAB/AACAAACAAACAAACAAACBAACBAACB\r\n        AACBAACBAACCAACCAACCAACCAACCAACDAACDAACDAACDAACDAACDAACDAACDAACDAACCAACCAACCPDuW\r\n        sK++ycbHysjIysjIzcvMzMnKyMXGxcLCuLW2oJ6ex8fGwcDAr62twLu9yMXFysnJzcvLzMrKy8nJzcrK\r\n        zcrLzsrLzsvMz83Oz83Nzs3Mz83Nz8zMzcvLzsvLzszMz87N0c/P0s/P0c/P0c7P0MzOzcvMz83N0M7O\r\n        z8zMzsvM0tDQ1NPS1dLT09DR0M3O0tDQ0tHR0c7O0M3O1NLT////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////sa+vsa+vsK6usbCws7GxsK6tr6ysr6ysr6usr6yrsK2tsq+wtLGxs7GxpqSjk5CQhIGBeHZ1\r\n        eXZ2eHZ1dnR0dnNze3d3end3eHV1eHZ1eXZ2fXl4f3x6f3x8gH1+fXp6end3f3x8gH59gn9+f3x8dnNz\r\n        dHFxgH19f319gHx9gH9/e3l6fnt7hIGBg4CAgn9+hIKBh4WFiIaGiYeIiomKioiJjYuKjouLjIqKjImJ\r\n        jYqKj4yNjouMj4yLj42NkI+QkI6OkY6OkI+NjoyMkIyNko+PkpCQlJGRlpOTlJKRlZKSlJKSlJKTlZKS\r\n        lZOTlZKSlpOTmJWVmJWVmpeXmZeXmZiYm5qanJmanJiYnJiYm5mZmpiYnZucn56enpycn5ucn5ydnp2d\r\n        nJqanp2coqGipKKjop+foZ+goqChoZ6eoZ+fo6Ghp6SkqKSjpqSlpKOko6KjpaOlp6WlpaOipaOkqKen\r\n        qKWmqaanq6mqrKqqq6iprKusrKurrqurrqysr62usK2trqysrKqrrqusr6ytsa+us7GxsrCwsrGxs7Gy\r\n        sa+vsK2usq+wtLOztLOytbOztrS1trOztbGyt7S1trO0trS0ura3u7q6vLy8u7m6ure4vLm5vbu7vr28\r\n        vry7srG3iYiqc3KkXFucLS2NKCiMBweBAAB/AAB/AACAAACAAACAAACAAACAAACBAACBAACBAACBAACC\r\n        AACCAACCAACCAACCAACCAACDAACDAACDAACDAACDAACDAACDAACDAACCCAiFbWyoxcTGycbHyMfHy8jH\r\n        y8fIzMrLzszN0c7OzsvMzMrKx8fGwcDAxMHCzcnKz83NzMrLycbGy8nIysnJy8rKzMnJzMrJzczLz83N\r\n        zsvMzMnKzcvKz8zMzszLzcvKzMrKzcvLz83N0c/P0c7OzszMzcvLzcvLz8zMz83M0M7N0M3N0M3N0M7O\r\n        0c/P0c/P0M/P0dDQ0c/Pz8zM0c3O0c3O////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        sK6usbCws7Gxsa+vrqyrrauqrqyrrqusraqrr6yss7CwtbOztLGysK2urqurpKGglJGRgn+AeHV1eXZ2\r\n        eXd3eHZ2eHZ1eXZ2eXZ2fXp5fXp6fXl6fnt7fXp5fHl4fnx7gH19gX5+goGAfHp6eHV1fHl5fHl5fnp6\r\n        gH59end4e3d4gX59f319fXp7fXl5h4SDiYaGh4SFhoSFioiIi4mJjIiIjYqKjIqKjouMjo2NjYuKjImJ\r\n        j4yNj46PkI6Oj42MjoyLj4yMkIyNkIyNkY6OkZGQk5GRk5CQko+OkpCPlJKSlpOTlZKSlJKRlZKRl5SU\r\n        lpOTl5WVmZaWl5WVmJaWm5iZmpiYmpeXm5iYnJmanZycnZqanJmZnJmanJqampeYmpaWnpuboqGhoqCg\r\n        op+fop+goZ6goZ6foaCfo6Gio6GipqKjqKWmpaOjoJ6eoqChpaOkpaOkpaOjpqSkqKamqaaoq6mprKqp\r\n        q6mpqKanq6epraqrrKurqqipq6iorKmpraurrausq6mqrKinrquqr6ytsa6vtLKys7Gys7Cxs7Gxs7Cx\r\n        srCwtLOzt7W2trO0tLKytbOzt7S1t7W2uLW3urm5u7q6urm4uLa2uba3ure4vbq7vbu6ure3uLa3u7m5\r\n        t7S5oJ6zqKW1hIOpZGOfPDySCgqCBgaBAQGABASBAACAAACAAACBAACBAACBAACBAACBAACCAACCAACC\r\n        AACCAACCAACDAACDAACDAACDAACDAACDAACDAACDHx+Ol5e3y8nJysfIycfIycbGy8jHysfIy8nKzMnJ\r\n        zMvL0M7O0tDQz83Nz83Nzs3MzMvKzMnKzsrKzcrJysfIysfHy8nJy8nJzMrJy8jIzMnJzszMzszLzcrK\r\n        zcvKzszMy8rKy8jJzsrKz8zLzsvLzcrKzczLz83Nz83Mz8zM0tDP0tDP0M3NzszN0M7O0M7Oz83N0M3N\r\n        0M7O0M3N0c/O0c/O////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////sa+v\r\n        rqyrrauqraurrqysrqysrqysr66utLGxtLKysrGxsa+vsK6usKytr62top+fjoyLgH59eXZ2enh3eXd2\r\n        eXZ2e3l4fXp6e3h4fHh4fHp5fnx8fXp6fnt7gH19gH19f319fHt6eXd2eXZ2fXt6hIF/gn9+fXp6fXl6\r\n        gX59goCAfXx8goB/h4WFh4SDiISEioiIioeIiYaHjYqKjYqKi4iJjIqKi4qJjImJjImKjYqLjYuKjoyL\r\n        jouLj4yNjYuLj4yMkpCPkpGQkI6Pj42Nko+Pko+Pk5CQk5CQlJGRlZGRl5WUl5SVlZOTmJSVmZaXl5ST\r\n        lZKSmZaXmpiYmpiYm5eYnJmam5mampeXmpaWmpiZmpiYm5iYnJman52en56enZubnpuboZ2eop6fop+g\r\n        op+goZ+goJ+goqCipKKjo6Ggo6GhpKKjpaOkpqWmpKKio6CgpKKip6amp6amqaamqqenqaenqaanqqeo\r\n        qaanqaamqKWlqqeorausrq2trKurqqSkraensK6usa+wsK6vs7Gxs7KytLOztbOztLGxs7GxtLKztbOz\r\n        s7Kxsq+utLGxt7W2trO0t7S1uLa2uLa2uLa2t7S0uLW1ura3u7m5ubi4ubi4u7m6vLm5u7i5u7m6ubi5\r\n        u7m6vLq6rau3iIWqXFubU1KZLy+PJSSMBQWCAACAAACBAQGBAACBAACBAACCAACCAACCAACCAACCAACC\r\n        AACDAACDAACDAACDAACDAACDQUCZsrC/ycfIysjJycjJycjIysrJysjIycfHy8nJy8rKy8nKysjIzMrK\r\n        z83OzczMy8jJy8jJzMnJysjHysjHy8fHysjIysfIysfHysfGzMnJzszLzMrKzcvKz8zMz8zMzcrKzMnK\r\n        zsrKzsrKzcvKzsvLzcvLzMvKzcrLzcrLzszMzszMzsvLzcvLzsvMzcvLzcnK0c7O09HR0M/P0c/O////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////raurrqys\r\n        rqyssa+vr62trauqrqyssa+vs7KytLKysq6vr62traqqqqinq6iooJ2dkI2Nf319eHd3fHp6fHl5e3h4\r\n        e3l4fXp6e3h5end4fHp6f318gX5+fXt6eXd3e3l4fXp6fXl5gHx8gX5+goCAgn5/fHl6dnV1eHd2gH59\r\n        hYKChoODhoODiIWFiIWFiYaHioiIi4iIiIeHiYiIi4eIi4iJi4mIioiGjImIjImJjoyMjYqLjImJjYqK\r\n        kY6OkI2NjoqLj4yMkY+PkI+Pj4yMj4yLkI6NlJGSlpOUl5WWlpSVlZOTlZKSlZKSlZOTl5SVl5SVl5WV\r\n        mJaWmZeXmZeWmZaWmJaXmZiXm5iYnJmZnpydnZucnJmZnJmanpydnpycn52eoJ6fop+hoZ+goZ+gn52e\r\n        n52doaCgo6Gho6Gio6GipaSloqCgoqCgpKGhpKOipKOjpqOkqKWlqKamp6WlpqOjqqenqqioqaenq6ip\r\n        raysrayrrKqqrKmpraqqsa+vsa+vr62usK6usK6vsa+vs7Kxr62tr6uss7GytbS1s7Gysq+vsq6vtbOz\r\n        trO0trO0trO0trOzuLW2t7S1trS0ube3uri4ube3uba3u7i5trW0sa+vtrS1u7m6uri5uba2ure4ure4\r\n        ure3srC2oZ6yop+yhYSqdnWmOjmTKSmOExOHFxaIBQSCAACBAACCAACCAACCAACCAACCAACDAACDAACD\r\n        AACDCAiGcXCpxMLEx8XGx8XGx8XFyMfHysnJyMbHx8XGysjJycjJyMbHycbHycbHzMrKysjIycbFyMfG\r\n        x8XFx8XFysjHy8nIyMbFyMXEysbGycfHysjIy8nJysfIzcrKzsvMzMnJysjIy8jIzMjGzMnIzcvMzcvL\r\n        y8nIycfGy8jJysjJy8nJzMrKzMnKy8nJzMrKy8nJzMjJ0M7O0M/OzMvLzMvL////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////sa+vr62trauq\r\n        qqenraursK2tsrCwtLGytLGyr62sq6iorKqpsK2tsq+vsq+wop+fkY+Pfnx8eHZ0e3l4fXp6end3eHV1\r\n        eXR1e3h5e3l5d3NzeHR0gX9/gX9+gHx8fXl5f3t7gX5+enl5b25ubm1sdXJygH58hIGBhoSEh4WEhYKC\r\n        hYODh4WFh4WFhoODiYaGi4iIi4mJiYiIiYaGioaGioeIioiJioiJi4iIjYqKjoyMjoyMjouLjYmJj4uM\r\n        kI6Oj42MjouKjoyLkY+Oko+Pk4+Qk5GRlZOTk5GQko+Pk5GQl5SUmJSVlZOTlpSVmJWWmJWVlpSTl5SU\r\n        lpSVl5WWmZaWm5iYm5qanZqbnJmanZubnp2dn5ydnZubnJucnZucnpydnpycnpucn5ydoZ+foqCgoZ+f\r\n        oZ+foJ+goqChoqCho6GhpKKipKKjpKKjpKKipqSjpqSlpqOkp6Slqqioqqioq6ipq6mqrKqrq6qqq6mp\r\n        qqenq6iorKqqrq2tsK6urqusrKuqrKysrqysramqr62ts7Gys7Cys7GxsrCws7GxtLKztrS0tbOztrO0\r\n        trOztbKztrOzure3uri4uLa2uLW2uLa2trS0s7Gxt7a2ubi4uLW1t7W1ube2vLm5vLm6vLq7vbq7vbq6\r\n        u7m6vru8vru8rqu1kI6thoOrcG+lWFeeOTiTBASDBweEDQ2GBASDAACCAACCAACDAACDHByMmJe0xcLD\r\n        xsTFxcPEwsHBx8XFyMXGyMXGyMbHyMXGyMXGyMbGycbGycbHysjJysfIycfGycjIyMbHx8XGycfGycbG\r\n        xsPExcLCycbGysjJysjIy8nKzMrKzcvLz83NysjJyMXGysfGysbFycbGysjJysjIysjHzcnJzMnKysnK\r\n        zszMz8zMzcvLzMrJzcvLzMnJy8jIzMnKzMnJzMvL////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////qqenraursK2trqyr\r\n        sbCvtLOysrKysbCwsrCvs7Cxsa+wsa+vs7CxtLKysrCxop+gkY+PgH9+enh3fHd4eXZ2eHZ1eHZ2eHV1\r\n        eHR1fXp6gH59gH59fnx8fXl5e3h4c3FycW5veXZ1fXl5gHx8g4CAhoODhoOChYKChYKDhoODhIGAhYGC\r\n        hoOEh4WEh4WEiIWFiYWGiIWFiIWFiYiHioeHiYaHjIqLjoyMj4yMjYuLjYqKjoqLj4yOj4uLj42LkI6O\r\n        kY+QkpCQkY6PkY6OkY2Ok5GRkpCQkpCPlZKSmJaWl5SVlpWVlpOTlZKTlZKSlpOTlZSVlpSVmJWWmJaW\r\n        mpiYmJaWmJaWm5iZoJ6enpycm5mZm5manZucnZqbnZqbnZubnpucn52doJ6foaCgoZ+foJ+foZ+goZ+g\r\n        o6GhpaOko6GipKGipaKjp6Wlp6ampaOkpqWlqaioqqipqKeoqqqqq6mqq6ipqaenqKSjp6GhqaWmrKur\r\n        rq2trqysrKqpraursK6ur6yurqussrCwsrCxsa+wsa6vsq+vs7GxtLOztrS0tbOztLKys7Gyt7S0uLW1\r\n        uLe3ube3uLe2trS0t7O0ura3uri4t7a2t7S1uLS0uLa1uri5vbq8vLq6u7m6u7i5vLu6vLy7vru8vbu7\r\n        vby8vby8uba5v7y8wL6+sK27ioitcnGlXVyfWVieNzaTBQWECAiFR0aasK28xMHCxMHCxcLDxMHCxcLC\r\n        xcPDxsXFyMfIx8XGyMbGysjIyMbGyMbHysjJycbIysfIysnJycfGxsLCxsPDxsPDx8TEy8fIzcvMzc3M\r\n        y8rJzMnJzMjJysjIzMrJycbGxsPEysbFzsrGzMjHysfIy8jJzMnJzMrKzMrJysnJzcvM0M7O0M/OzMrK\r\n        y8fHzMnJzcrJzMrKzMrKzMrK////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////rqyrsbCvtLOysrGxtLOz\r\n        tLOys7Gxsa+vsa6vtLKytLKzsrGxsa+us7Kxs7GxoZ+fjouMfHt6end1fHl4end3d3R0d3R0end3eXV1\r\n        fHl5fnt7eXd2d3R0fHh5hIB/g4CAgX5/gn+Ag4CAg39+g4GAhYODhYKCg4B/g39/hIGBhICAhYKChoSE\r\n        h4WFiIaGioaHiYaGiIaFioiHiYiIioiIjYqLjoyMjYuLjouMjYqKjImKjYyNj42Oj4yNkI6PkI+PkI2N\r\n        kY6Pk5CRk5CRkY6Ok5KRlJOTko+QkpGRlZOTlJKSlZGRlpOUlpWWlpWVl5WVmpiYmZeXlZOTlI+Qm5eY\r\n        nJqbmZeXmpeXnpucnZucnJubnJqbnZubnZubnZucnJucnZucnpydoZ+go6ChoZ+goaCgo6GhoqChoZ6f\r\n        pKGipaOjpqSkp6Wmqaioqqipp6anpaWkqKamqaenqKSlqKWkp6KhqKOhqqemrKqrrKqrraurrKqqrKqq\r\n        rq2trqytr6ytsK+ur62trqqrsK2usK6usa+vs7CxtbO0tbS0tbO0tLOztLKztbOztLGytbOztbS0tbOz\r\n        trO0t7W2uLa2t7W2uLW2t7S1tbKytrOzuba3ube3ube3uba2ure3u7q7vLu7vLq7vry8vby7vbq7v7y8\r\n        vry8vbq7v7y9vry8t7W6wsC/wb6+rqu5jIqvmZezw8HCxMLCxMLCw8DBxMLDxMLCxMHBw8HCxcTFx8XF\r\n        yMXGycjIyMfHyMbGyMbHyMfIycfIy8jJycfGxMLCw8DBxcPDx8TEycfIzMvKzMvKy8rJysfHyMXGx8XF\r\n        ysjIyMXFxcLEy8fH0s7HzcrFxsTGy8jJy8jJysjIysfHyMbFysfHy8nJzMvLysfHx8TEycfGzMrKzcrL\r\n        zszMzszM////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////srGxtLOztLOysq+wsrCws7Gx\r\n        tbS0tLKzsq+wsq+vs7GxtLOztLK0tbK0srGxoJ6ekIyMfXp5eXZ1d3V0d3JzeHJye3d2fXt6fXx7fnx7\r\n        gX19gX19g4CAgn9/goCBgoCAg4CAgn9/gn9/hIKBhIGAhICBhICAhoOCh4SFhoOEhYKCh4aGiIWHh4OE\r\n        iIaFioeHiIWFhoSFiIaGi4iIjImJi4mJjImJjIqKjYuMjImKjImJjYuLjYyMjImKjouMkY6OkZCPkY+Q\r\n        kY6PkI6Oj4yNkY2OkpCQlJKTlJGRlZKSlZOTlZOTl5WVl5aVlpWUlpKSmJOUmpeXmZeYl5SVmpiXm5qa\r\n        m5mbmZiZm5manJmanJubnZycnJmam5iZnZuboJ6fop+goJ6fn56eo6Kho6GhoZ+eoqCgo6GhpKGipKGi\r\n        paKjqKSmp6anp6Wlp6SlpqSkp6Wkp6Sjp6Oip6Sjqqenq6mqrKqqq6mpqqioqqeprKurra2srausraur\r\n        rKmprqqrrqysr62tsK2usrCxsrGxsrKytLGys7Gxs7Kys7Gxs7Cws7GwtLKytLGys7GxsrCxs7GxtrS1\r\n        trS1trS0tbKytrOytrS0t7W1t7W1trS0trO0t7W2urm5u7i4u7e4u7i4vbq7wL2+vbu7u7i4vbu8v72+\r\n        vru8wL6+wsHAwr/Awr/Awr/AwcDBwsLCw8LCwsDBwsHBw8HCw7/BxMHDw8HCxMLCx8TFyMbHx8bGxsTE\r\n        x8XFyMfHx8XGx8TGxcPEw8HBxcLCx8TFx8bFxcTDxsPDx8XFyMfGycfHyMbHysfHysjIxsPDxMLDycfH\r\n        z8rFzcfCyMXEycbHycjHysjIycbHx8XEycbGycfHx8XGx8XFycfGyMbGy8jIy8jIzszM////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////sq+wsrCws7GxtbSztLKys7CxtbKz\r\n        tLGxs7GwtbKytrOztrS0tLKytbKysa6un5ycjYiIenZ2fHl4fXp5end3e3h3fnt6f3x7fHp6fXt6gH18\r\n        gX59hICAhIGCg4CBg39+g4GAg39/hICAhIGBhoWEiIaGhYKDhYKChoOEhYKDhIGBhYODhYKCh4ODiYWF\r\n        iIaGiIWFiISEiIWFi4iJjYyNjIqKi4mIi4iIjYmJjYqKjIiJjIiJj4yMkpCQkY+PjouMjouMk5CQkY2N\r\n        kIyNkpCRk5KSkY6PkY6Ok5CQlZKSlJOSlJKRlpOUmZeYmZiYmJWVmJWWl5WWl5eXmZiYmZeXmJWWmpeY\r\n        m5manZubnJqanZqan5ydnpydnpucn5ydoJ+foqCgpKGho6Ggop+foZ6fo6Gho6Chop+go6ChpaSkpqSl\r\n        p6WlqKWlqKamp6WlpKKipaOjp6Slqaanqaenqqeoqqioq6iprKqqrKurrKmqrKmprKurraurraqqraqq\r\n        rqytrq2tsK6usK6usK2tsa6vsrCws7Cwsq+ws7KxtLKytLKysrCwsrCwsq+wtbKztrS1tbO0tbOztbOy\r\n        trS0t7a2uLa2trS1tbO0trS0ube3ure4t7S1uLa3vLm6v729vr29vry8vry9vLq7vLm6vry+wL/AwL6+\r\n        wL6/wL6/v7y+wL6/wsDBwsHBwsDBwsDBw8DBxcPExMLCwb/AxMLDxcPExcPExsTFx8TFx8XFxsPExMHC\r\n        w8DBxMHBx8TEx8XGxcPExcLCxcLDx8XFx8XFx8XFx8bGyMbGx8TDxMHBx8XEyMjIycXGzMbEz8rGysfH\r\n        ysfIy8rJysjIyMbGysnJy8jJyMXFycbGysjIycbHysfGycfGycfG////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////tbSztLKys7CxtbOzs7CxsrCvs7GwtLGy\r\n        trOzt7S0trS0trSztrO0trO1rqqrnZqajImJend2d3R0enZ2fXp6fHl5enh3fXp6gHx6gn16gn5+gn9/\r\n        hIGAhYKCg3+AgX9+goCAg4GBhIODhYODhoKDh4KDg4CBg4GBg4GAhIGAhYKBiYWFiIaFh4SFiIWGiYaG\r\n        iYeHiYiIi4mJi4mIioiIioaHjoqKkI2Nj4yNkI2OkY6PkI6OjoyMkIyNk5CQk5CPkI2OkI6OkY+Pko6Q\r\n        kY+PkpCQkY+QkpCRlJKSlJGTl5WWmJWWl5OUlpOTlpSVl5WVmZeXmJaWl5WUmJeXnJmbm5iam5mZm5mZ\r\n        nJqbm5iZnpucoZ6foJ2en5ucoZ+eoqGhoJ2eoJ6eoqGgpqSko6GioJ+eoqCgpKKio6GhpqKjqKanp6an\r\n        pqWkpqSjqKamqaWmqaanqKanqaenqaamqaanq6iprKmqrKqqrKqqq6mpq6moraqrraqpraqqr6yssK6u\r\n        sK2tsa+wsa6usa6usK2usa+vsrGxsrGxs7GytLKztLKztLOytrS1s7KzsrCwsrCwtrO0ube3ube4t7S2\r\n        trS1ube3uba3t7S2trW1uLa2ure3u7m6vry8vru9vLq7u7i4u7m5vry8vbq8vbu8vby9vru8u7i5vLm7\r\n        wL6+wb+/wb/AwsDBwsDBxMLCw8LCwsDBw8DCxMLDxMLDxcPExcLDxcPExcTDxMLCxsPDx8XFxsXFxcTE\r\n        xMDBxMHBxsTDyMbFyMTFxsLDxMPCw8LBxMHBxsLCyMfGysnJycfIy8jIy8nHysfHycbHycjIysjIycfH\r\n        ycfHycbGycXFysfHyMfHyMXFysfHysjIysjI////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////tbOzs7CxsrCvtbGytLKytrKyuLa2t7a3trS0\r\n        t7S0trOztbGytbOzt7W1sq+vn5yci4iIe3h3f3t7fnt6fXt7fXl5fnp5f3t7f3t8gH19g4CBgn+Agn9/\r\n        goCAg4GCg4CBg4GAhIGBhICBg4GAg4CAhoKChoOChoSEhoSEhYSEhoSEiIaGhoSEhoODhoSDiIeHiomJ\r\n        iIeHiYaHjIiJjoyMj46OkI+Qj46OkI2NkI2OjoyMj42NkpCQkpCQj42MkY6Pko+RkY+Pj46NkY+Qko+Q\r\n        kpCQkpCQlJGRlZKTlZKTlpSUlpSUmJSUmJWWl5WWlpSUmJeXmpeYmZeXl5eWmZiYmZaWmpeXnZucoJ2e\r\n        oJydnpycn52en56en52doZ+foaCgoJ6eoJ6eoJ6eo6ChoqGhoZ+fo6Cgp6Wmp6Wmp6amqaenqKamp6Wl\r\n        qKamqKanp6Wlp6WmqKWmqaenqaeoq6mpqqmoqqioraqqraurraqprqqqr6ysr62tsK2usK2usK2tsK6u\r\n        sK6ur6ytsK6vsK6vsK+vtLKysrGxsrGxs7Gxs7GxsrCxtLGytLKzt7W2t7W2trS1t7S1uba3t7W2trS1\r\n        ube4ube4t7S0uLW0u7m5u7q6uLa3uri4vbu7vLm6u7i4u7m5vbq6vLq6ure4ube3vLm5vru8wL2+wb+/\r\n        wL6/w8DBw8PDwsHCwr/Bw8HCwsHBwsDAxMLBwsDAwsHBw8HBx8TFycfHxcPExMLCxMLDxMLCxcLBxcPC\r\n        xsTFxsPDxMDBxcPDx8XGxsTExsTEycXGy8fGxsXFxcTGx8TFx8XFxsTEx8XEyMbGx8TFxsPDyMXEysjH\r\n        yMfGyMbFy8jJysjI////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////tbGytLKytrKyt7O0trO0tLKztrSztrWzt7W1t7a2\r\n        uba2uLa3uba1t7S0rqysnpubjYmJfXp7fHl5fXp6f319f319f319gH19gHx9fnt8gX5+hYKChIGBgX19\r\n        gH19gX5+goB/g4CAhICBhYODhoSEhoOEhIKChYSEhIKCgn9/hICAhIKAhoOCiYaHi4mJiYeIiIaGioiI\r\n        jo2Njo2OjIqKi4iIjImKjYuLjoyMj42Nj42Nj42Mj4yMj4yOj4yMj4yMkI6Ok5CQkpCRk5GRk5CQk5CQ\r\n        k5CRlZKTlpOUl5SUl5WWlpSVlZOUlpOTl5SVlpWVl5WWl5SUmZaWmZaWmpmYm5iZnZqbnpycnp2enpyd\r\n        npucnZycnZubnJiZnpuboqGhpKOkpKOjo6Gio6GipKOkpaSkpaSkpqOlpKCio6CgpaOkp6SlpqSlp6Wm\r\n        p6WmpaKhpaOjqKanqaeoqaeorKmqraqqrKmpq6mpqqmprKmqramqrqurr6yssK6vr62ur6utr6ytrayr\r\n        raqrsK2tsK6ur62tsa+vsrCxtLKztbKztbKztLKztbSztLOztbKzt7S1t7W2ube3ube4t7W2tbKztbKy\r\n        uri3ubi3t7S0uLW2vLq6u7m5u7i4u7m5u7i4uri5u7q6vby7vbu7v7u8v7y9v729v76+v729wL6+wb6/\r\n        w8DAwsDAwb+/wb/AwsDBwr7Awb+/wcDAwsDBxcLDxMHCxcPExsTExcLDwr+/w8C/xsXEx8bFxcPDxcPD\r\n        xsTExcPCx8TEx8TFxMHBwr++xcLCx8PExMHCxMHCxMHBx8PEx8XFx8XFysjIy8nJycfHy8nJzcvMzcvM\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////t7O0trO0tLKzt7W0t7W1t7W1trO0t7S0t7W1uLa1uLW0\r\n        trS0t7S1uLW1rqysm5mZioiIf31+f359fnx7f3x8fXp6e3h4fHl3gH17gX5+gH5+gH59gX5+gn9/goCA\r\n        gX9/goCAhIGCg39/g3+AhIGChIGBg39/g39/gn9/hIGBh4SEiYaHiYaGiIWFiomJjYuLjYuLi4mIiYaG\r\n        iIaGi4mJjIqKjYuLjouLjYyMjYqKjoqLkI2NkI6OkpCQk5CRk5GSk5GSk5CQkpCPk5GRlJKSlJKTlJKS\r\n        lJGRlZKTlZKSlpSUlZSTlZOTlZKTl5SUmJWVl5WVmJaVmZaXmpaYnJqanZyanZucnZqbnZmZnZqan52e\r\n        oZ+foZ+foZ+go6Cho6KioaCgoqCho6Gio6KhpKKio6ChoZ6epKGhpaOjo6GhpqOjpqSkpaOjpaOipqOj\r\n        p6WlqKenqaioq6mpqaenqKamqqenq6moq6qpq6mqraurraqrraqqrq2sr62traqrraurr6ysr6ysr6ys\r\n        r62tsK2usrCwtLOzs7KzsrGxs7Gxs7GytLGytbOztrS1uLa2uLe2trS1uLa2uLe4uLa2uLa1uLW1trS1\r\n        t7a2u7m5u7i5ure4uLa3uri5vru7vry9vry9vru8v729vry8vry8vry7vry7wL6+wcDAwcC/wL+/wb+/\r\n        wb2+wsDBw8DBwb+/wb+/wb+/w8DAw8HBxcPDxsTEw8HBw8DAxcLCxcLDwr/Awb6+wr++wsC/xMLBxsTE\r\n        w8DBwLy8w76/xsPDxMLCxMHCxMLDxcPDyMbGyMbHysjJycfHx8TFycbHy8nKy8nK////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////tLKzt7W0t7W1t7S0tbOztrS0t7W0t7W1t7O0tbKytbOztrW0t7W1\r\n        t7S0ubW2r6ysnJmaiYeHfnt7fXt6fXt6fXp6fXp5f3t7gHx9gH5+f3x9gX1+g4CAg4GAgoCAgn9/gH19\r\n        gHx9gn9/g4GAhIGChYKCh4SEhoSDhYKChYKChoKChoKCiIWFioeHi4mJjIqKjImJjImJioiIioeIi4iI\r\n        i4mJi4eJi4iIjoyLkpCQkY6PkI2Ok5CRko+Qk4+Rk5CRlJKTlJOTlZKSlJGRko+Qko6Ok5GRlZKSlpSU\r\n        lpSVlJKSlZOSl5WVmZaXl5SVmJWWmZaXmJeXmJWVmpaWnJuanp2dnZucnpucn52eoJ+foZ6foZ2fn5yd\r\n        nJqaoJ2eoZ6foZ6foZ6eoqCgo6GhpKGhpKKipKKjpKGipqKjpqWkpqalqKWlp6OjpqSkpqWlp6Wmqaan\r\n        qaenqKamqainrKqqq6qpq6mqq6mrqqmpqqinrKqpq6mprKmpraysrqytsKytsK2sr6yssKytsa+vsrGx\r\n        srGxsbCwsq+ws6+xtbOytbSztbS0tLKys7GxtLKytrW1t7e2trW1uLa2uLe3trO0tLKyuLa2uLa3uLa2\r\n        ube3uba3u7m5vbq7vbq7vbu7vby7vbm6vLm6vry8vLm6vbq7vr29vry7v7y8wL6+wL6/v76+wL+/wL6+\r\n        v729wL6+v72+wL6+wcDAwsDAwcC/wsDAw8DBw7/AwsC/wb6+wb6+xMHBxcLCxMLCwb6+wLy8w8DBxsTE\r\n        xsbFxMPDw8HCxMLCx8XFx8TFxcPDxsTEx8TFycfHy8nK////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////t7S0tbOztrS0t7S0uLS0trS0trO0tbO0t7W2t7W2t7S1uLa2uba2uLW2\r\n        tbS0rKqqm5eXioiHfHl6fHl5fXl5fnp7f3t8fnt8fXx8gH59gH5+gX5/goCAg4GBgn9/f3x8f3x8goCA\r\n        hoOChoOEh4SEhYODhYODhIGBgn9/hIGBiIWFi4iIiYiIioiIjYqKjouLi4mKiomJiYeIioaHiYaHi4mI\r\n        j4yMj42NkI6OkY6Qj42Nj42OkpGSk5GSk5GRko+Pko+PlJGRk5GRkpGRkpCQk4+QlZKTlZKTk5GRlZSU\r\n        l5WVmZaWmZaXmpeXmZiXmJaWmJSUm5iYnZucnJqbmpaXmpeYm5mZnZubn5ydnZucmZaWm5iYoJ2dn52e\r\n        oJ2eoJ2eoZ+foZ+foqCgpKKipaSkpaKjpKGhpaSkp6amqKWlpqSkpaOjpaGiqKWmqqenqainqKenq6ip\r\n        qqioq6mqrKmqqaipqaenq6ioq6mpq6ipraqrraurrausq6qprqursa6vsK2vrqusr62ssrCwsK6vsq6v\r\n        srCwsrCwsa+vsq+vsa+vs7KytLKztLOztrW1trO0trS0tbOztrO0trS0tbOzt7W1uLe3uLW2uLW2uri5\r\n        u7m5u7q6vLq6vLq7vbu7vLq7u7e4vLi6vbq8u7i4vbq6vr29v76+vry8vru8v7u9wL29wb+/v72+v7y9\r\n        wb+/wL6/wL2+wb+/w8HBwsDAwb++wb6+v729wr+/xcPDxMPDwsDAw8HBw8HBwsDAw8HBxMPCw8HBxMHC\r\n        xsPDxsTDxcLCw7/AxMLCxMHCxMHC////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////t7S0uLS0trS0ube3uba3ube3uLe3trW1t7W1uba2uLa2t7W2ube3uLe3t7W1\r\n        rKiom5eYiISFend3fHh4fnl6fnx7fnt7f3x8fnt7gH19goGAgoGBgH19gHx8gX5+gn9/gn+Agn9/hIKB\r\n        hYODg4GCg4CAhYOCh4SEiIaGh4SEhIKChoSEjImJjYyMiYiIiYeHiYaGiYeGiYWFioaGi4mIjYyLjouM\r\n        jYuMkI6OkI6PkI6PkI2NjouLjouLk5CQkY+PkI6Ok5CQk5CRk5GSk5GSkpCQk5GRlJOSlZKSl5SVmJaX\r\n        mZeYmJeXmJaWmJWWmZaXmZaWmJWVmJWVm5iYnpucnZycm5mamZWWm5iYn52eoqGhoJ+fnpucn5ydoZ+f\r\n        oJ2eop+fo6Kho6ChpKChpaOipqWkpaOkpaKjpaOjpqSkp6WmqaanqKWlqKWlqKWlqKamqaenqaanqKWm\r\n        qKamqKamqqenq6mpq6mprKqqq6mpqqioq6mqrqytraqsraqrr62ssK6usK6usa+vsq+wrqurr6yssa6u\r\n        srCwtLOztLKzs7GytLKysrCxsrCwtbKztrO0tbS0tbKztrS1t7a2uLa2ube4ube3ube4ubi5uri5ubi4\r\n        vLu7u7q6u7m5vbu7vLq7vLi5vbq6vbu8vLu7vbq7vrq7vru7wL6+wL6/v72+v729wL29v729wL2+wr/A\r\n        wr/AwcDAwL6/wLy9v729vru7wL6+wsDAw8HBw8HBwcC/wL29wb2+wsDAwsDAwr/AxcHBxsTExsXFxMHB\r\n        w8DAxMHBxMHB////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////ube3uba3ube3t7W1t7W1uLa2ure4ube4uba3uba3ube3ube3ube3ure5vru6rKmp\r\n        mJSUhoODfXp6f3t7fnt7fXt6fHp5fnt7f3x8gX5+gX5+gX1+gH5+gH5+gHx9gX19g4CAgX9/g4B/hYOD\r\n        hoSEhYKDhYKChICBhIGBh4WFiYeGhoSEh4WFiYeHi4iHjIqKioiJiYeGiYaGioeIi4mIjouLjoyMjouL\r\n        jouLjImJjoqLj42NjouLj4qKkpCQkpKRkpCQk5CRk5CRk5CRlJKRk5GSlJGSl5WWlpSVl5SVmJaWmZeY\r\n        mZaXmJaVl5SUl5SUmZeXnJqbnZycm5mZm5manZubnZubnp2dn56enpycn5yeoZ6foZ6foJ+eoZ6eoJ2d\r\n        oZ6fop+gpKGhpaKipaKjo6KipaOjpqSkpqSlp6SkpqSjpaSjpqSjqKWmp6SlqKWlp6WkpqOjp6Okqaem\r\n        qqmpq6qqq6mqq6ioqqioqqmqraqrraqrraurr62sr66usbCwr66uraqqrqyssa+wsa+vsrCwsq+vsq+w\r\n        srCxs7Cxsq+wsq+ws7Gxs7KztrO0t7S0t7W1t7a2uba3t7S1t7W1ubi4t7W1trS0ube4u7m5ubi4urm5\r\n        vLq7vLm6u7m5ure4ure4vLm7vbq7vLq6vLq7vry+vbq7vLm4vbm5vry7wL++wL+/v7y9v7y9wL+/wL6+\r\n        wL6+v7y8vrq6v7y9wb6+wb++wb++w8HAwr+/wb+/wcDAwr+/xMDAxcLCxsTExcPDxMLCxMHB////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////t7W1t7W1uLa2uLa3uLa2uLa2uLW1uba3ube3uLa2ube3uri5ure4uri3uLa2p6Wml5OT\r\n        hoOCfnx7fHl6e3d4fnp6gH19gH59f3t8fnx8gH19gH1+gX1+gH19f318gH19g4GAg4GBgX5/gn9/hoOD\r\n        iYaGiIWGhYKChIGBh4SEi4iJjYuLjIuMjIuLioeIiYeHioiIi4iJi4iIjIqJjYuKjYuLjouLj4yNj42O\r\n        joqKj4yMkI2OkI6PkI6OkY6OkY6OlJGRlZOUk5KSk5GRlZKSlpOUlZKTmJWVmJaXmZiXmZeXmJWVlpOU\r\n        lZKSl5SVmpmZm5mam5qanJqampiYmpaXnJqanZycnZqcoJyeoZ+eoqCgn52en5ycn52doZ+go6CgpKKi\r\n        o6Kio6GhpKGipqKjpaSkpKOipKKio6GhpaKipqKjpqOkp6Wlp6Wlp6SlpqOlp6Wmqqioq6ipqqmpq6mp\r\n        qqanq6mprKurrKmqqqioraurrKurrKurrKyrrKqqr6ytsK+vsK6ur6ytsa6usa+vsa+wsq6wsq+wsrCw\r\n        srCws7GytbKytbKztbO0trS0trO0trO0trW1uLa2tbOztbOzuLe2ube3uba3uLW2uLa3uLa2uLa2ube3\r\n        ube4vLm6vLm6ube3uba3vbu7vbq7ure3u7i4vbq6vbu7vLq7vru8v7u8vry8v7++wL6+wb6+wL29wL6+\r\n        wL6+wL29wL6+wb/Aw8HAwsDAwb+/wb2+w7+/w8DAw8C/xMHBxcLCxcLC////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////uLa3uLa2uLa2t7W2uLa3uba2ubW1ure2uLe2uba2uri3ube3uLW1uba2uba3qaWnlZKTg3+A\r\n        fXp7fXt7fXl5fXp5fXp6f3t7f3t7gHx9f319fnx8gH5+gHx8gX1+gX19g3+AhIGChoODhYODhoSEh4SD\r\n        h4SEioeHioiJioiIi4iJi4mJi4mJjIqKjImKi4iKi4iIjImJjYqLjYuMjYuLjYuMj4yNj4yMj4uMjYqL\r\n        j4yNkI2OkI6NkI+PkpCRk5CRkY6Ok5CPlJGQlJOSlZSUlZOUlZOTl5WWl5WVmJaWmJWVlpOTl5OUmZaW\r\n        mJaWmZeXm5mYm5eYm5iZm5manJmanZqan5ycoJ6eoJ6en56eoZ+foqGgo6KhoqGhoqCgo6Cho6Gio6Kh\r\n        o6Kho6Gho5+ho5+gpKCgpaKipaKipKKjpKKkp6SlqKWmqKWnqKanqKWmqKanqaioqqenqqioq6qqqqmp\r\n        q6mpq6mqqaeoqaanrKqqraqrrqusr6ytrqysr62tsK6vsbCwsa6usa6usK6usa+vsq+vs7Kxs7OytLKz\r\n        tLKztLKzt7S1trS0trS0trO0tbO0tbO0uLa2uLW2uba2uba3t7S1trO0uLa2ubm4ube3uba2ure3uba2\r\n        uba2u7m5vLu7vLm6vLm6u7i6uba3u7e4vbq6vru7vbq6vry8vry8vbq7v729wL+/wL6/vru8vbq7v7y9\r\n        wL6+wb+/wL29wLy9wb6+wr+/wr6+wr+/w7/Aw7/A////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////t7W2uLa3uba2u7e2ure2uLa3uLa1ube2ure3ure3ure4ube4uba3ure4uLW1p6Okko+PgX19e3h4\r\n        fnt6fnt6fXp6fnt7f3x9fXp7f3x8f3t7f3x8gX5+g4CAhICBgn9/g4GBhoODhoSEhYOChoSDh4SEiYaG\r\n        ioiIiIaHiYeHioeHiYaHiIWGh4SEiYaGi4mJi4iKi4eIi4iJjIqLjImKi4iIjImJjouMkI2OjoyMjYuL\r\n        kI2OkY+Qj4yMkIyMk5CPlJGRlJKTlJKSlJGSlJGSlZWVl5aVmZaWl5OUl5WVmZeYmZeXmZaWmpeYmpiZ\r\n        mpiZmpiYmpeYnJiZnZqanZucnpybn5ycn52coJ6eoZ+foZ+fnpycn52eoJ+fop+foqCfo6GhpKKipKKh\r\n        paOjpqKjpaOjo6Kio6GipKChpKGhpKKipqSlqaamp6WmpqOkp6WlqKanqKenq6mpq6mpqqepqaaoq6mq\r\n        rKqqrKqrrKqqq6ipqqeoraussK2usK2usa6usK6ur6ytr6ussK6usK+wsbCwsrGxsrGxsrGxtbKztbOz\r\n        s7GxtbKztbO0tbS0trOztrO0uLW2uLa3uLe3uLa3uLa3uLW2t7S0tbOzuLW2ure4uba3uri4u7q6u7q6\r\n        vLq5u7m5ure4vLm6u7i4ubi3vbq6vLm6u7m5u7i4vLm5vby8vby8vru7vry8wL6+v7y8vry8vbu7v729\r\n        wsDAwsHAwsHAwb6+w7/A////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        u7e2ure2uLa3uLa2uba2ura2ube3uba3uLa2uLa1uLa2ura3ure4uba2t7S0pqOjkY6Of318e3l4fXp7\r\n        f3x8fnp6e3h4e3h4fXp7f319gX59gX1+goGBg4GBhIGBhYKChoSEg4GAg4CBhYOEhYSDhYKChoOFh4WF\r\n        hYSDiIaFiIaGiIeHioiIjIiJjImJiYeIiYaHioeHi4qJjIuLjoqKjoqKjYqKjImJj4yMkY+PkI6Oj4yN\r\n        kY6OkIyOkI2Ok5CRlJGRlJGRlZOTlZSUlJGSlpOUmJaWmJaXlpSVlpSUmJaWmpiYmpiYmZeXmZWXmZaX\r\n        mpeYmpaXnZqanZqanZqanZmanpqbnpucnp2dnZydoJ6fop+foqCgoqGgoqGhoqCgo6Ggo5+goJ6eoqGg\r\n        oqCgoqGgoZ6eoJ2eo6GipqSkpaOjpqSkqKWmqKanqKemqKamqaamqaanqqeoqaanqqeoq6mprKmqq6eo\r\n        q6iprausrqytrqusr6ytr66ur6ytsK2tsK6ur62ur6utsKyur66ur6+vsrCxs7KytLKys7CxtLGxtLGy\r\n        tLKytbKzt7S1trS1uLe2uri5uLe4t7W1trO0t7S0t7a1uLa3uLa3uLe3ube3t7W2uLW2ure3u7m5uri4\r\n        uLW0ubW0u7m4u7m5u7m5vLq6vLm5vbq7vbq6vbu7vbu8vry8vry8vru7vru7vr29wL6+wb+/wb+/wb6+\r\n        wb6+////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////uLa2\r\n        uba2ura2uLW2uLW1uba2uri4uri4vLi5vbm6u7e4u7e3ura3u7e3trS0pKGhko+Pf319fXt6e3h4enh4\r\n        fHl5fnp6fXt6fnt7gH19gX5+f3x8gn9/hIGBg4GAgoCBhIGChIGAg4CAhoODiIWGh4aFiIaGiYeHiYeH\r\n        iIWFiIWFi4mJiomIioiIi4iJjImKi4mIiYeGioeIjYmKjYqKjYuLj46OkI6PkY+PkI6Oj4yOkIyNko+P\r\n        kI+OkpCQlJGSkpCRkpCRk5CRlJOTlJOTlZKTlZOTmJaWmJWVmJaWmJaXmJaXmZeYmpiYm5mZmpmYm5mY\r\n        nJqanZubnJqZnZubnZubnZqanZubn52en52enpudnpubn52coJ2cm5iZlZKTnpubo6GhoZ+foJ6eoZ6f\r\n        op+hoqChpKKipKKipKOjpaOkp6Slp6Wlp6Slp6Slp6Smqaanqqeoqqmpqqepq6ipq6mpq6qqrKqrq6ip\r\n        q6mqrKusrq2srqysrqytrautr6utr62ur66tr62usK6vsK6vsa+xs7Cws7CwtLKzsrGytLKys7Gys7Gy\r\n        tLKyt7W2uLe3uLe3uLW1t7S0trS1trW1uLa2t7W1trO0tLKztbKzuba3ube3ubi4ubi3ura2ura2u7e4\r\n        vbu7u7m6u7i6vLq7vby8u7q6vLq7vru7vrq7vru8vr28vby7vru7wLy9wL6+wL69wL69////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////uLW2uLW1\r\n        uba2ure3u7m5vrq7wLy8vbm7uba2ure4vLq7vLq6vLq6vrq7u7e4p6WlkY+PgH1+gYB/gHx8fXt7e3l5\r\n        fHh4fnp6fnt8fnp7gn9/g4CAhYGChIGBg4CAg3+AhYGChoKDhoSEhoSEhYODh4WFiIWGiIaHiYiIiomI\r\n        i4mIi4mJioeIioaHioeHi4iIjYqKjYmLjYuLjYuLjYuMjYqLj4yMkI2NkY6Oj4yMjYqJkI2Nko+QkpCR\r\n        kpGQk5GRk5CRlJKTlZKSlJKTlZOUl5SUlpOUl5OUl5aXmZiZm5mZm5qZmpiYmZaWm5mZnJqanJqanZub\r\n        np2cnJmZm5mZnZubnp2enZqbnJqbnpycoZ6enZycm5iZn5ydoZ+goJ6eoJ2doZ+eoZ6fo6Gio6GioqCg\r\n        oZ+fo6ChpaGjpqOjpKKipaKjpqSlqKamqainqainqqenqaeoqqmoqqioq6mprKqqq6mpq6mpq6mqrKmq\r\n        rKqqraqrraqrr66urqysr6ytsK6tr62tr6yusa+wsa+vsrCxsrGysrGxsrCxsrCysq+xsq+wtbO0tbS0\r\n        trS0tLKztbKztrOztrOztbOztbO0t7a3uLW2t7W1t7W2ube3uri4uLa3uba3uba2u7i5ura4ube4vLq6\r\n        vbq7u7m5u7m5vLq5vLm5vLq6vbu7vLq5vbq6v7y8v729wL69////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////ure3u7m5vrq7\r\n        vLq6vbu7u7i4u7m5vLu7vLq6vru7v7y8v7y9vLq6vLq6ube2pqSkko+Pfnt7e3p5fHp6fnx8fn19fnp7\r\n        f35+gX6Agn5/gn9/gn+AhIGBg4CAg4CAhH+AhYGBhIGBhYKCiIWGiYaIiIaHiIeHioiIiomJiomJiYaG\r\n        ioaGiYaHi4mJjYqKjImJi4iIiYaHiYaHjImKj42NjoyMjo2Mj4yLj4yMkI2OkpCQkZCQkpCRlJGTlJOT\r\n        lJOSk5KSlZOTlpOTlpOTlZSTlpWUlpSUmJWWmZeYmpmYmpeYmpaXmpeXmpeXm5mZnJqanJqbm5iZnJqb\r\n        nZucnpycnZqanpycnp2doJ6eoqCgoZ6fn5yen52eoJ2en5ydoJ2do6Cgo6Kio6Gio6Chop+gpKGho6Ki\r\n        oqGho6GhpaGjpqOjpqWkqKenqKWlp6WmqKanqqeoqqipq6qqqaamqqeorKmqrKmqrKqqraurraysrqyt\r\n        r6ysr6ytrqytraurr6ytr62urqytsK6usrCwr62usKytsrCxsrGysrCxsrCxsrCxsrCws7GxtLGytbKz\r\n        tLGytbKytbSzt7a2uLW2trS0uLW2uLW2trS1uLa3uba3trS0tbKzuLS1ube2u7m4vLi5u7i5u7i5vLm5\r\n        vLq6u7m5vLm5u7i4vLm5v728v769v769////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////vLq6vbu7u7i4u7m5\r\n        uri3u7m4vry8wb/AwL2+u7i4vLi5vru7vru7vbu7uLW1pKGhkI2NgH19gH59gH19f319fn1+f3x9gX5/\r\n        hIKChIGBgn9/gX5/hH+AhICBhYGCg4CBhIGChYODhYOEh4SGhoSFiIaHiYiIiYeGiISFiIWHiIWGiYeG\r\n        i4iIiYeHioiJi4mJjImKjIqLjoyMjo2Nj4yNjouMj4uMko+PkY2PkI2PkpCRk5GRk5GRk5KSk5GRlZKS\r\n        lZKSlpSTlZSSlJGRlZKTmJWWl5WVl5WVmJWVmZaWmpiYmpeXmpeXmpiZm5mZm5iYnJmZnZqanpqbnJmZ\r\n        nJubnZucn52dn5ucnpucn52eoJ2fnpudnZqan5uboJ6foqChpKKkpaWloqGhop+goqGio6GipKCipKKi\r\n        pKOipaOkpaKjpaKiqKWmqaanqaeoqKanp6Smqaanqqmpqqioq6mqraurrausrKqrraurrqusq6mrraus\r\n        rqysraurrKqqsK2tsK2urqysrqussK2usrCwsrCwsbCwsK+wsrCws7GxtLGytLGytrO0tbO0s7GxtbS0\r\n        t7W2t7W2uLa3uLW2tbKzt7S1uLa3trSztrOzt7S0uLa2ubW1ure3uri4ure3u7i5vLq6vLm5u7m4uLa3\r\n        uba3vbq6vr28vr28////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////u7m5uri3u7m4vLq6v7y9\r\n        v7y9vbq6vbu7vru8vLq7u7m5vrq5wLy8wL6+ure4pKGijouMf3t7f318f319goCAg4KCgX9/gHx9gn+A\r\n        goCBgX5/g3+Ag4CAgH19gHx9goGAhIGChIGChICBhoOEhoSEh4SFiISFh4SEhoOEiIWGh4WFiYiIjIqK\r\n        i4mJjIqLjYuMjYqLjIqLjoyNjYqLjImKjYmKj4yNkY+Pko+Qko+QkY+Pko+Pk5GRlJKSlJGRlJGRlJGR\r\n        lpOUl5aVlpOTlZKSlpOTmJeXmpiYm5eXmpiYmpmZmpmYmpeXmZaXnJmanZqbnJmZm5mZnJqbm5qanpub\r\n        nZubnZucnJqbnZubnZubnpqbnpucoJ2eoJ6enZycnZqboJyeo6GioqGho6GipaSkpaOipKGipKOjpKKi\r\n        pqOjp6Slp6Skp6OjqKWlqaenqaanqaioqqinqaenqqanq6iorKqqrKmpq6iprKqrrausrKmqrausrqus\r\n        r6ytsa+wsK+wsK6usK2usK6usK6usa6vsa+ws7GxsrCxtLGytLOzsrGysa+xtbKztbO0tbOztrS0t7W1\r\n        t7S0trS0trS0trOzuLS1t7a2trW1uLW1ubW1ube2uLa2uba4u7m5u7m5urm4uLa1uba2u7i4vr28////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////vLq6v7y9vbq7vru7v727vbu7\r\n        vru7vbq7vbq6v7y9v76+wb6+wsDAwb6/tbGxop6ejImKf3x8fnx8fXp7fnt7gH5/gH9/f3x8gX5+gX9/\r\n        f3x8gHt8gn9+goB/g4B/gn+AgoCAhIKChYOCh4SEh4SEiISGh4WFhoSEhoSEiYeHioeIi4mJjYuLjImK\r\n        jIqKjoyNjIqKioeHjImJjoyLkI2NkIyNkY6PkY6Pko+Qk5GRk5GRk5GRkY+Qko+QlZKSlpWUlpWVlpSU\r\n        lpOTlpWVlpSUmJWUmpiXmZeYmpiYmZaWmZaXmpiZm5qZm5uanJqampiYmpiYnZqbnZqbmpeZmpiYm5mY\r\n        nZubnpycoJ2eoqChmpiXko2MmZSVoZ6foJ6eoJ6foZ+fpKKhpaCgpqKipqWlpaSko6GipaGipqKipqKi\r\n        qKWlqKWlqKWmqKenqainqKWmqqemqqalq6enqqipq6qprauqrKmqrausrq2tr66ur62usa+wsLCvr66v\r\n        sa6vsa6vsK2ur62ur62usK6vsa6vsrCysa+vrqursq+ws7CxsK2usa6vsbCws7GwtrOztbOzsrCwtLCw\r\n        tbGytrO0t7a1uba2uba3uLe3uLa2t7S0uba3ubi4u7m5u7i4uri3u7i4u7i4////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////vbq7vru7v727vLm5vbu5vbu7vru8v7y8\r\n        wL6+vry8wL2+xcHBwr+/vbu7vbq6s66vnpqaioaGfnp6f3x7f3x8f319gX9+gn9/f319gH5+gX5+gn5+\r\n        g39/gX9/gX9/goCAhIKChYODhoSEh4WFh4WGhIKDh4WFioiJioiJiYiIi4mJi4iJioiIjIqKjIqKjYqL\r\n        jYuLjIuLjYqKj4uMjoyMj42Nj42OkY+QkpCQkpCPj46Nj4yMk5CQlJGRlJKSlJGRlpOSlpSUlZOUlpSU\r\n        lpSTlpSUmJaXmZeYl5WVmJWWmpiYm5uamZiYmJaXmJaXmpiYmZeYmJaXmJeWmpiXm5mZnZycn56en52d\r\n        mJaVmJWUn5ycoZ+gn52dn52doZ+goqCgo6Cho5+gpaKjpqWlpKGho56epKGhpaOjpaOipqOkpaOkpaOk\r\n        pqSkqKamqKamqaalqaamqKanqKinqqmorKqqraysrq2trausrqysrq2trqysraqrrautraytrq2tr62u\r\n        r66ur66ur6yusK6vr62uraqqr6ussrCxsbCws7Gysa+vsa+vsrCxsa6usa+usrGxs6+xtLCxuLW1t7S1\r\n        trW1t7a2uLa2uLW1t7Ozt7S1uLa2uLa3uba3u7i4u7i4////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////vLm5vbu5vbu7wLy8wb69wsHBvb29v76+xcLB\r\n        wb+/vbu7wL28w8C+xMDAwr6+s6+wn5ubioeGfnt7gH59gX5+gH1+fnx8f3x8gXx9gn9/gX5+gn+Ag4CC\r\n        g4GBhIGBhIKDhYSEhIODhYODhYKDhIKChYKDh4SFiIaFioeHiYaHiIWGh4WFiYWGjImJjIuLjoyMj4uM\r\n        jo2NjoyMjouMj4yNkZCPkpGQkY+PkY+OkY+PkpCRk5CRk5CQk5GQlZOTlZSTlZKTlJGSlpOTmJaWmJaX\r\n        lpSUlpOUmJaWmJaWmJWWl5aXmZaWl5WUlpSUlJKTlZOTl5WVmZeWmpiYm5mamZeXm5iYnZycn52enZuc\r\n        npucoJ2en52eoJ6foJ+foZ+goZ+foqCgpKCdpZ+cpKCfpKCho6Cho6Gho6GhpKKipaOkpqSkp6Slp6Sk\r\n        qKWlqKampqSlp6Slqaanqaenqqipq6iprKmqraysrKmpq6enrKqqrKusrausrqytrausr66usK+wsK6u\r\n        r6ysraussK2usrGxs7SzsrGxsa+wsq+ws7GysrCwsrCvtLKxsq+wtLCxtbKztrS0tbOztrO0uLW1uLe3\r\n        uLe2t7S0t7W1t7W2t7S1u7i4////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////wLy8wb69wsHBv7y9w8HBxcPDvru7u7m4wb++xMHB\r\n        w8C/wb29v7u7vrq5vrq5sq6uoJycioeHfXp7fXt8fnt7fnp7f3x9goGAgoCAgX6AgX9/goCBhIGDhIOC\r\n        hIOChYODg4GBgX5/hIGChIKChYKDiYWGhoSFg4GAg4GAhYKCiYWHjYqKjYqKjYqLjo2NjoyNjouLjYqK\r\n        jYqLj42Nj42Nj46OkpCQkpCQk5CRkI6OkI2Nko+QlJKSk5GRlJCSlZKSlpOTl5SUlZOUlZOUlpOUlpOU\r\n        l5SVl5SVl5WVmJWVlpSUl5SUlZOTlZOTl5SUmJWWmJWWmZaXnJqanJqanJqbmpmZmpeYnJmanJqanpyd\r\n        oJ6foJ6fnpycn5mYo5yZpKCbpaGeo56do6Cho6KipKKhpaOjpKKjo6CipKKjpKKjpKKipaSkpKKipaKi\r\n        paKkpqSmqaeoqaioqaanq6qrrKqrq6qqrqytrq2urKusq6mqo6Cir66usK+wsK6ur6ysrqytr62urqys\r\n        rqyssa+vsK+vsa6wsq+ws7KytLKysq+wsK2usa+vsq+ws7CxtbKytLKytbKytbOztrO0tLGxtrS0trS0\r\n        tbKztbKz////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////v7y9w8HBxcPDwLy9wb2+w8HBw8DBwsC/wL29vru6vrq6\r\n        wL29xcHBxsPDwb6+sa2tnJeYiISEfHl5enh5fnx8goGAgX5/gH5/gH+AgoCBgn+Ag4GChYKDhIGChYOC\r\n        hoSFh4SFhYKDhoSFhYSEhIKCh4aEh4SEh4OEiYaHioeIiYeIiomJjImKjo2MjYyLjYuLjouMjoyNjYuM\r\n        jouLj42NkI6PkI2Nj4yMkY6OkpCQk5KSk5GRk5GRk5CQlZKSlZOTlZSUlpWVlpSUlZOSlZOTl5SVl5WV\r\n        lpSVlpOUl5WVlpSVmJWWl5WVlpOTmJWVmpiYmpmZmZeXmZaXmZaWmpeYnJqanJucnpydnp2dnZubnZqa\r\n        oJuaopyboZ2bop2coZ6eoZ+goZ6fo6ChpKOjo6OjoqCgoZ+foqGhoZ+fop+foqCfpKGipaOkp6WmqKam\r\n        qKWlpaOjqKamq6ipq6mqraurrKusq6mqo6Ci////////////////rqytr62urqysrKiprqytrq2urqyt\r\n        sa2tsa+usrGxsa6vsa+wsrGxs7Gxs7CxtbKytLKys7GwtLKztbKztLGxtbOytrOztbKz////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////wLy9wb2+w8HBwsDBwsDAwb6+wr6+wsDAwsDAwr69w72+wb2+\r\n        wby8v7q5v7q6sK6umpmYh4SFgH9/g4CAgX9/gH9/gX9/g4CBgoCBg4CAg4CBg4KChoSEiIWGh4WGhYOD\r\n        hYOEhoOEiYWGhoODhoODiIWGiIWGiIWFiYaHioeHi4mJjIqKiYeHi4mJjYuLjImKjImLjoyNjoyMkI2N\r\n        j4yOjYuMj42OkY6PkpCPkY+QkY6Pk5CQlJKRkY6OkpCQk5KSk5GRlJKTlZOUlZOUlJKTlJKSlZKTl5SV\r\n        lpOVlZOUmJWWmJaWmZaXmpiZmZiXmJWWmJWWmZaXnZubnZubnpucnZubnJqbnZydn52eoJycnpqbn5ub\r\n        npycnpycoJ2eoZ2eoaCgoaCgoZ2dn5ydn52dn52doJ6eoJ+foZ+eo6KhoqGhpKKip6SkpqSlpqWlp6Sl\r\n        qKOkraur////////////////////////////////////////rKiprqytrq2uraqrsKyssK2usK+usa+v\r\n        sa+vsrGxsrGxs7KxtLKys7Cxsq+wsrCws6+wtLCxtLKytrOz////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////wsDBwsDAwb6+xMDBxMPCwsC/v7u7v7y9wsDAwr6+wr6+xMDBx8TE\r\n        yMfGycfHtbKynZubiIaGf319gX5/goB/gX5/gH19gH5+gH9/goGBhIODhYOEhIKCgn+AhIGBhoKDhYKD\r\n        hIKDhoSEhoOEiIWGi4iJiYeHiYeIioeJh4SFhoSEioeHiIWGiYaHi4mJjoyLkJCQkI6Oi4mKjIqKj4uM\r\n        j4yMkY6PkI2Pk5CRkpCQj4yNj4uMko+Qk5CRlJGRlJOUlJKTlJGSko+QkY6Pko+Qk5GSk5CRlZOUlpOV\r\n        l5WVmpiYmZeXlpSVl5SVmJWWmZaXm5qam5qam5mam5manZucnJubnZucnJmanZqbnZucnpucn5ycoJ2d\r\n        n52doJ2en5ycnpucnpubn5ycop6goJ2fnpyboJ2doqCgoqCgpaKipaKkpaSlp6amqKOk////////////\r\n        ////////////////////////////////////////////raqrsKyssK2uraqrsK2tr6ysr6ytsa6vsa+w\r\n        sK+vr62usa+wsbCwsa6vsrCwtLKytrOz////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////xMDBxMPCwsC/wby9wb+/w8LCwb6+xsLDycbIy8fIysbGysfHysfJy8nL\r\n        y8nKtrS1nJqZhYODf3x9f319gX9/goCAgH9/gH9/goCAhIGBg4CAg4CBhoSEhYODhIKChIODhYSEhoSE\r\n        iYaHiIWFh4aGiIaHiIaGiIWFh4WFh4WFhIKCiISEi4mIiIeHiIaFi4eHjImKjIqKjoqLkI2NkI6OkZCQ\r\n        kpGRkY+PkI2OkY2OkpCRkpCQkpGRk5GRk4+RkI2OjoyMkY6Oko+Pko+Qko+QlJKTlZOTlpSUlZKTlZKT\r\n        l5SUl5SUl5SUmJeXl5WWlpSVmJaWmZiYmpiYmpeXm5mZnZqanpubnZubnZubnpuboJ6en52enZycnZyb\r\n        nZybnZubn5uboJydnpucoJydo6Cgo6Gio6Cgo6ChpKGjoKCgoKCg////////////////////////////\r\n        ////////////////////////////////////////raqrsK2tr6ysrqqrr6usraurraurr6yusK2usK6u\r\n        sa6vsrCw////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////wby9wb+/w8LCxcLCyMbFysfHysbHycXHyMXFyMTFx8TFysfJzczMzcvMyMbG\r\n        sq+wmpeYhYODgX5/gX5/gX5/goGBg4OChYSDhISEhIKDhIGBhIGBhYSDhYODhIKChoSEh4SFg3+Af359\r\n        g4GBh4SFiYaHiIaGhYODhoSDiIaFenh5enl4h4WEjIqLjIqLjouMjouMj4yMj46OkI6OkY6OkI6Oj46O\r\n        j42OkI6PkY6OkY+PkY6Pj42NjoyMkY+PkpCQk5CRlJGSk5KSlZOUlZKTlJKTk5GRk5GRlJGRl5SUl5WV\r\n        lZGSk5GRlZSUmZeYmpiYmpiZmpiYnJqbnJqanZucnJubnJqanJmbn5ydnZucnJqam5qZnZubnZqanZub\r\n        npydoJ6eoaCgo6Gio6GhpKGipKKjoKCg////////////////////////////////////////////////\r\n        ////////////////////////////////////rqqrr6usraurraurr6yusK2usK6u////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////xcLCyMbFysfHx8TFyMXHyMXFx8PDxcLByMXFy8fIzMfIycfHxsTEyMTGycTGs7Cw\r\n        mZiYhIKCgX+AgYCAgoGBgoGBgX9/gX5/g4CAhIKChIODg4KDhoODhoKDgHx9fHp6fHp7fnx+hIKDiIWG\r\n        h4SEh4aFh4WFgX9/gX9+iIaGioiIiYiIioiJi4mKjYuLjoyMjYqLjYuLjY2MjY2MjYyMjYuMj42Nj42O\r\n        kY+OkI2NkI2OkI6PkY+PkpCRk5KSlJOTlpSUl5WWlJOTkZCQkY+Qk5CQlZOSlJKSk5CQlZKSmJaXmpiZ\r\n        m5mZmpmZmpmZmpiZm5mam5qanJubmpmZmpeYnJiZnpucnZqbnZmanZqbn52dnpydnpydn5+eoJ+foJ+g\r\n        oJ+foqChnZucnZuc////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////x8TFyMXHyMXFx8TFx8XFycfHzMjIysbGyMTFxsLCycTFzsvMz87Oz87Nx8XGr62ulpOU\r\n        gn+AgX+AgoCAgoGBg4GBgoGBgoCCg4GChIKChYSEgX9/gH1+g4GCf3+AfHx+g4KDhoSEhoSEh4WFiYeH\r\n        iYeHh4OEhoOEh4WFiYaHioeHiomIioiJjImKjoyMjYuMi4mKjIqKjoyMjYyMjo2NjoyMjouLjoqMj42N\r\n        jo2MjouMkI2OkpGRk5KSlJKSlJKSkZCQkY+Qko+Qk5CQko+QlZKRlZOTlpSWmJaXmJeWmJaWmJWWmJaW\r\n        mZeYmZeYmZaXmpeYmZiYmpiZmpiZm5iZmpiYmpmZm5manZucnpycnZybnZucn52dnp2dn52enZuc////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////x8TFx8XFycfHzMrKysjIysbIysbHzMnJzcvLzc3Mzs7NzszMzs3M0M/OxcHDrKiqlpSUg4KC\r\n        g4ODgH9/f3x9gn+Ag4KChIOCgYCBfHp8g4CChoaGg4KDf39/goCBhYKDhYODhoSEh4SEhoKDhYSEiYiI\r\n        ioeHiYeHiYaIioeJi4iIjYqJi4mJi4mJjYuKjYuLjYuLjIqLjYuLjYmKjYqLjYuLjo2NkI2OkY6PkY6P\r\n        kI+PkI6OkI6OkI6OkI2OkY6Pko6Pk5GRlZOUlJKTko+QlJKSlZSUlZKTlpOUmJaWmZeXmZaXmJWWl5aV\r\n        l5aXl5WWmJeXmZeXmZeYmJaXmJaXmpeYm5mam5mZnZmbn5ycn52en5ydn5yd////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////zMrKysjIysbIzszMzsvLzcnKzcrLzcvLzcnLzszN0M7Oy8jIysbHzsrLx8PEr6ytlJGSf3x8gn+A\r\n        g4GBg4CBgoCBfHt8e3l7g4GBhIKBf319gX5/g4GBhIGBhYKChIOChIKChYOEhoWFh4WFiISFioiJi4qK\r\n        iomJi4mKjIqLi4iJioiJjImKjYuLjYuMjImKi4iJi4iJjYuMjoyNj42OjoyNj42OkY+PkY6PjouMjYuM\r\n        j42NjoyMj4yMkY2PkpCRkY+Qk5CQlJKSlJOTlJOTlZOTl5WVmJSWl5SVlpSUlpSVlZOUlJKSkpGRk5KS\r\n        lJKTlpOUlZOTl5WVmZiYnJubm5manZqanJqampmZmpmZ////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        zszMzsvLzcvNzcnLzcnKzs3N0M7O0MzMzsrKzszL0M3O0M3NzsvMz8vMwb6/qqankpCQgX5/hIGBgH9/\r\n        eXl7enl6gH59gH59gH1+f319gX9/gn+Ag4GBhIKChYKDhYODhoSDhIKChYKDiIaHh4aGiYiJi4mKioeI\r\n        iYeHioiIiYeHiYeIioeIiYeIiomKjImKjYqLjIqKjIqKjYyMj42NkI6Oj4yMjImLjYqLkI2LkI2Lj4yM\r\n        kI2Oko+PkpCQk5GRlJKTlZWVlJOTk5GSlJGTlJKSlpOTlZKTlZOTlZOTlJKSk5GSk5GRlZKSlpSVl5WW\r\n        mpiYm5mZm5mZmZeXmZaXl5WVmJeX////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////zcvNzcnL\r\n        zcnKzs3NzszMzcjJzcjJzcrKzsvLzcnKzcnJzcnLzcvM0M7Pz8zNw8DBq6ipkpGRgH+Aenp8enl6f319\r\n        fnx8fn18f35+gHx9gX1/g4GBhYKChYKDhYKDg4GAgn+Ag4KChYODh4SFiIaGiIaFiYeIiIeHiIWFh4WF\r\n        h4WGiIaHioiIi4mKjImKjIqKjYqLjYuMjIqKjYuLjYuKiYeJioeJk4+LlJGLjIqKjouNkI2OkI2OkI6O\r\n        kpCQkpCQkZCRkY6PkY+QkY+Qk5CRk5CQk5GRlJOTlZOTlpOUlZOSl5SUl5WWl5WWl5WUmJWVmJWWmJaX\r\n        mJWWmJaWmJeXmJeX////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////zs3NzszMzcjJ\r\n        ysfJzMjJzcnJzcnKzcvKzsrLzsvMzszMzcrL0M3Oz83Ny8jIvry7p6WljImLfnt7f3x9fnx8f319gX1/\r\n        gn5/gX9/gX9/gH1+g4CBhoOEhYKCgoCAg4GChIKDhIKChoSEiIaGh4SFh4WFiIaGh4WGh4WGiIaGiYeI\r\n        i4mKi4qKjIqKi4iJi4iJi4mJiYeHh4SGioiJkIyKko2HjIiHjImKjoyMj4yNj4yNjoyLjouMj42Nj46O\r\n        jouLkI2Nko+QkY6PkY2OkI6OkZCQlJKSlZKSlJKTlJKTkY+QkZCPlJGRlZKSl5SUl5SUlpSVmJaWl5WU\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////ysfJzMjJzcnJz83O\r\n        z87P0M3NzcnKy8bIzsrM0M7OzcvLy8jIzsvLzsrLzsnKvLm5o6GhjIqKfnt7f35+gH9/f35+fXx8fn19\r\n        gH5/g4CBgoCAgX5/g4CCg4KCgYCAg4KChoSFhICChoSEhYOEhoSEhoWFh4WGh4SFiYaGioiIiIaHiYaH\r\n        ioeHi4iIhoOFh4SFiomJioiJjoeHkYyIjYqIjYqLj42Nj42NjouMjoyMjo2NjYyMjYuLjoyLj4yNjouM\r\n        j42OkY+QkpCQk5CQko+QkpCRkpCQj42MjYuLkY+Pk5CQlZOTlpOTlJKSlZOSl5WUl5WU////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////z83Oz87P0M3NzcrLzMnL\r\n        z8zN0M3OzcvLy8jJzsnJzcvKzcrKzsvLzMnJzcnKvLm5o6GhiomJfXt8fnt8fnx8fXx8fnt8fnx8f31+\r\n        gX9/gH5+gX9/goGBg4GBg4CBhIGChIODhIKChoSEhoWFhoOEh4SFiYaHiYeHiYaHiIeHh4aGhYKDh4SE\r\n        iomIioeIi4iJjouJjYqJjImJjIqLjYqKjYuLjYyLjIqKjoqKjouLjIyMjImKjouLjo2NkI6PkY+PkY+O\r\n        lJGQk5CRk5CRkZCPkI6OkY6Pk5GQk5CQlZGSlZOTlpSUlZSUlJOU////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////zcrLzMnLz8zN0c7P0M3OzcrL\r\n        zcnIzsvLz8zN0c7O0M3N0MzM0MvM0MzN0M7Pvbm6o5+gh4WGe3l6fXt7fXx8fnx8fXt8fXt7fnt8gH5+\r\n        gYCAgoCAhIGCg4GChIKCg4GChYODhYOEhYODhIKChoSFh4aGh4eGhYSEg4CAhIGBiYeGjIiHioeGhoaH\r\n        iIaHioeIiYeHiYeHioiIioeIiIWGioeHjIqKjIqKjIuKjYuLjouMjYuMjoyMjYuLj42NkI2OkY+PkZCQ\r\n        kY+Qko+PkY+Pko+Qk5GRlZSUlZSVlZSUlJOUlJOU////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////0c7P0M3OzcrLy8rIzcvK0MzO0s/R\r\n        0c/Q0M3Oz8vM0s7O09DQ0tDP08/P0c7Nura2nZucg4GCenh5e3l5enh5fHp6f319gH9/gH5+gn9/goCA\r\n        f319f319gX5/g4GCg4KDgoCAg4CAhYKChYKChIKCg4GBg4KChoSEh4SEh4SDhoODh4SFhoSFhoODhoKC\r\n        iISFh4SFh4SFiYaGi4qKjIuKi4qJjYuMjoyNjoyNjYyLjIqKi4mJjYuLjoqMjoyMj42NkI6Oko6QkpCR\r\n        k5GSk5GSk5GSkpGQkpCQkpCQ////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////y8rIzcvK0MzOz8zL0c/Q0M/P0M3M0s7N\r\n        0s7P0s/Q0tDR09HQ0s/N08/P0czOubW0n5ybhYOEfnx8gX5+gX5+gH1+fn19fnx8fXp7fnt8f319goB/\r\n        hYKCg3+Agn9/g3+Ag39/gX5+gH5+f359goGBhYOEh4KCh4KChoODhoSEhIODhoOEhoSEiIaGiYiIi4mK\r\n        ioiJiIeHiIaHi4mKjYuMi4qLjIuLi4iJjImJjYuLjYqLjoqLjYuLjIqKj42OkpCSkY+QkY+QkI+OkI2N\r\n        j4yMj4yM////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////z8zL0c/Q0M/PzszL0M3N0MzO0s7P0s/Q0c/O\r\n        08/O1NDP0s/O0M7P0tDS0c7OuLW1nJqahYKCfXt8fXx8fXp7fnt8fnx8f318gX59gn59gX5+gX5+gn9/\r\n        gn5/gH5+fXx8fnx8gH9+goCAgn9/hYGBhoOEhYOChIOChYSFh4aGiIaGiYeHh4WGhoOEh4WFiYeHioiI\r\n        iYeIiIeIjIqKjYuLi4qJi4qJi4mJjYqKioeIiYeGi4qJjoyMjouLjYuLjo2Mjo2Mj42Nj42N////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////zszL0M3N0MzO0c3O0s7O08/R1tHT08/Pzs3M0M7O\r\n        1NDS0s7O0s/P09DR0c3Ot7O0mpeYgX9/fHp6fXt7fnx8fnx8fXp7fnx8f319fn19f319f35+gH5+gH19\r\n        gX5+gH5+gX5+goB/goCBg4CBhIGBhoOEhYODhIGChIKChIKDgoCAhIGBhYKChoSEiIWGiYaGi4iJi4mJ\r\n        iIeHiYaGiYaGiIaFioiIjImJjYuKjImJjIqKjIqJjoyLj4yNj42N////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////0c3O0s7O08/R0MvN0c3P0c7P0c7P1NLQ087O087Q1dHS\r\n        1dLT1tPT1tTUz8zMtbCymJaWfnx8enl6fHl7fHp6fXx7fXx8fnx8fnx8fnx8gH19gH1+gX5+gn5/gH5+\r\n        gH5+gX+AgoCBg4CAgn9/gX5+hIGChYODg4GBgn9/g3+Ag4CAhoKCh4ODh4SFh4WFh4aFiIWFh4SFh4WF\r\n        ioiIjYuMjouNjImKiomJi4mIjIqJjouLjouL////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////0MvN0c3P0c7P0s7Q1NLS1dPT1tPT1dDR1dHS1NPT1dXV1dPT\r\n        1dLS1dPTzMnLsa2ulZKSfHt7fXt6fnt8fnt8fHh5e3d5fXp6fnx7f3x9gX1+f3x9gH5+gX5/gX5/gH5+\r\n        gH5+f319gn9/hIGAg4GBhIGBhIGBhIKChIGChIKDhIGChYKBhoSEhoSEiIaGiYeHiIaGiIWHioiKioiJ\r\n        iYeIiIWFiYeHjIqKjIqK////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////0s7Q1NLS1dPT1tTU1dLT1NDS0s/Q0s/R1tPU1tTU1dPU1NHS1dLT\r\n        2NbXzMrLr6ytlZGSfHl5e3h5end4fHp6fXt6fnt7f3t8f3x8fX19fnt8f3t8gH5+f3x9fXt7f3x7f3x7\r\n        gX5+g4CAg4GBg4GBhIKDhIKChIGBg4GAhIKChIKChoSEhoSEhYKChoODh4WFiIeHiYaHiYeIiomJjIqK\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////1tTU1dLT09DRz8vM0MvN1NHS1dPT1dLT1dPU1tPU2NXV19XV1dPU1tPV\r\n        ysfJr62tkpCPe3l5fXt6fHp6fHp6fXp5fXp6e3l6fXt7fHp7e3l5fHl5f3x8f3t8fXp6f3t7gX19gX9/\r\n        gYCAgoCAgX9+goCAgX9/g4CAg4GBg4CBgn9/hIKBh4SEh4WFiYeIioiJjIqKjIqK////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////09DRz8vM0MvN0c7O08/Q1tLT1tPT1dHS2NTV2djY19XW19PV19TV1dTU1dLSycfG\r\n        rKmpjYuMenh4fHl5e3l5e3l4enl4enh3end3fXp6fXp6fHp6fHp5fnt7gH19gH5+f31+f319f318f319\r\n        gX5+g4B/hIGBgX5+gH19gn9+g4CAg4GAhYODh4WFioeIioeI////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////0c7O08/Q1tLT1tPT1dLS1dPT1dPT1tPU2NPU19TU1dLS1dLS1tPU1tHT1dLTxcPDqqeo\r\n        j4yNeXd2eHZ1eHZ2end3eXZ2eHV1eXV1eXd3eXd3fXt7gH1+fnx7fXt7fnt8f3x8gH59gX9+gH19f3x9\r\n        f3x8gH18gH18gX9/g4GBgoCAioeI////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////1tPT1dLS1dPT1dLS1tTU2NfW19bU1tPU1tPT1tHT2NXW19TU1dPS1dPT1dPTxcHBp6Oki4iH\r\n        eXZ2eXZ2eHV0eXZ2enh4enl5e3h5fXt7e3p5e3h4fXp7fnp7fnt7fXp6fXp6fnt7fnt6fXp6fnx7goB/\r\n        hYOEg4GCg4GC////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////1dLS1tTU2NfW1dPR1dHR2NTV1tPU1dLT1dLU1NHS1dLR1NHR08/R1dHS1tTUwb+/paGhiYaGe3l5\r\n        e3p6fHl6e3h5fHl5fHl6eXZ3e3h4fHd4fXl5fXt6fXp6fnl6fnp6f3p7f3x8gX9/goCAg4CBg4CB////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        1dPR1dHR2NTV19bW1NLS1NDS1dHT19PT2NXV1NHT09DS1dLT1dHT1tLS19TUwsDApaKiiIWFeXZ3e3l5\r\n        fHp6e3l5enZ2e3Z2fHh4fHp5e3l4fXl6f3t7fnt7f3x8gH19gX9/g4CB////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////19bW\r\n        1NLS1NDS19LT2NXV2NXX1dPT1dHR1tHR1tLS1tPU2NTV2NTV19XU1dLTvbm6oJ2dhIKCenh2eHZ2eXZ2\r\n        eXh3eHZ1eXd2enh3e3h4e3l4fHp5f318gH5/gH5/////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////19LT2NXV\r\n        2NXX1dHT087N1M/P1tLR19XU19TW1NHS1NHR19TV1dTT19PT1dDQuLOznZmag4CAeXZ2eHV1d3V0d3V0\r\n        dnNydXNyd3V0enh3gH5/////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////1dHT087N1M/P\r\n        1tLR1dHS1NLS1tLS1s/R1dHS1tXV19XV2NPT1tHS1tPT1dPTubW1nJmZgX5+d3RzdHJxcW9uc3FwdnR0\r\n        dnR0////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////1tLR1dHS1NLS1tLS\r\n        1tHR1tHS1tPU1NLS08/Q1tPT2NXV19PV1NDQ0s7P0c7PuLS0mZaVeXd2b21scnBvcnBv////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////1tLS1tHR1tHS1tLS09DR\r\n        0s/P08/P1NHR1dLS1NDS1dLT19PU1NLS1NHSzsvLs6+wcnBv////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////1tLS09DR0s/P1tLS1tLU1tLT\r\n        1dLS1NHS1tLS1tLS1tDR1dDR1dPT19XW19XW////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////1tLS1tLU1tLT1tXU1dLT1tLS19LS\r\n        19PT19XT1dPS19XW////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////AAAA////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////1tXU1dLT1tLS19LSzsrK19XT1dPS////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////AAAA////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////19LSzsrK////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////AAAA////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////AAAA////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////////////////////////////////////////////////////////////////\r\n        ////////////////////AAAA\r\n</value>\r\n  </data>\r\n</root>"
  },
  {
    "path": "Razor/UI/WelcomeForm.cs",
    "content": "#region license\r\n// Razor: An Ultima Online Assistant\r\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\r\n// \r\n// This program is free software: you can redistribute it and/or modify\r\n// it under the terms of the GNU General Public License as published by\r\n// the Free Software Foundation, either version 3 of the License, or\r\n// (at your option) any later version.\r\n// \r\n// This program is distributed in the hope that it will be useful,\r\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n// GNU General Public License for more details.\r\n// \r\n// You should have received a copy of the GNU General Public License\r\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\r\n#endregion\r\n\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Collections.Specialized;\r\nusing System.Configuration;\r\nusing System.IO;\r\nusing System.Windows.Forms;\r\n\r\nnamespace Assistant\r\n{\r\n    public class WelcomeForm : System.Windows.Forms.Form\r\n    {\r\n        private System.Windows.Forms.Label label1;\r\n        private System.Windows.Forms.CheckBox patchEncy;\r\n        private System.Windows.Forms.Button okay;\r\n        private System.Windows.Forms.Button quit;\r\n        private System.Windows.Forms.Label selectServerLbl;\r\n        private System.Windows.Forms.ComboBox serverList;\r\n        private System.Windows.Forms.GroupBox groupBox1;\r\n        private System.Windows.Forms.GroupBox groupBox2;\r\n        private System.Windows.Forms.OpenFileDialog openFile;\r\n\r\n        /// <summary>\r\n        /// Required designer variable.\r\n        /// </summary>\r\n        private System.ComponentModel.Container components = null;\r\n\r\n        private System.Windows.Forms.Button browse;\r\n\r\n        private bool m_PatchEncy = false;\r\n        private string m_ClientPath = \"\";\r\n        private TextBox uoClient;\r\n        private TextBox dataDir;\r\n        private Button dataBrowse;\r\n        private Label label2;\r\n        private TextBox serverPort;\r\n        private TextBox serverHost;\r\n        private Label portLabel;\r\n        private Label serverHostLbl;\r\n        private Button removeServer;\r\n        private Button saveServer;\r\n        private TextBox serverName;\r\n        private Label serverNameLbl;\r\n        private Button newServer;\r\n        private ComboBox langSel;\r\n        private Label label5;\r\n        private CheckBox showAtStart;\r\n        private string m_DataDir = \"\";\r\n\r\n        public WelcomeForm()\r\n        {\r\n            InitializeComponent();\r\n        }\r\n\r\n        /// <summary>\r\n        /// Clean up any resources being used.\r\n        /// </summary>\r\n        protected override void Dispose(bool disposing)\r\n        {\r\n            if (disposing)\r\n            {\r\n                if (components != null)\r\n                {\r\n                    components.Dispose();\r\n                }\r\n            }\r\n\r\n            base.Dispose(disposing);\r\n        }\r\n\r\n        #region Windows Form Designer generated code\r\n\r\n        /// <summary>\r\n        /// Required method for Designer support - do not modify\r\n        /// the contents of this method with the code editor.\r\n        /// </summary>\r\n        private void InitializeComponent()\r\n        {\r\n            System.ComponentModel.ComponentResourceManager resources =\r\n                new System.ComponentModel.ComponentResourceManager(typeof(WelcomeForm));\r\n            this.label1 = new System.Windows.Forms.Label();\r\n            this.browse = new System.Windows.Forms.Button();\r\n            this.patchEncy = new System.Windows.Forms.CheckBox();\r\n            this.okay = new System.Windows.Forms.Button();\r\n            this.quit = new System.Windows.Forms.Button();\r\n            this.selectServerLbl = new System.Windows.Forms.Label();\r\n            this.serverList = new System.Windows.Forms.ComboBox();\r\n            this.groupBox1 = new System.Windows.Forms.GroupBox();\r\n            this.langSel = new System.Windows.Forms.ComboBox();\r\n            this.label5 = new System.Windows.Forms.Label();\r\n            this.showAtStart = new System.Windows.Forms.CheckBox();\r\n            this.dataDir = new System.Windows.Forms.TextBox();\r\n            this.dataBrowse = new System.Windows.Forms.Button();\r\n            this.uoClient = new System.Windows.Forms.TextBox();\r\n            this.label2 = new System.Windows.Forms.Label();\r\n            this.groupBox2 = new System.Windows.Forms.GroupBox();\r\n            this.newServer = new System.Windows.Forms.Button();\r\n            this.serverName = new System.Windows.Forms.TextBox();\r\n            this.serverNameLbl = new System.Windows.Forms.Label();\r\n            this.serverPort = new System.Windows.Forms.TextBox();\r\n            this.serverHost = new System.Windows.Forms.TextBox();\r\n            this.portLabel = new System.Windows.Forms.Label();\r\n            this.serverHostLbl = new System.Windows.Forms.Label();\r\n            this.removeServer = new System.Windows.Forms.Button();\r\n            this.saveServer = new System.Windows.Forms.Button();\r\n            this.openFile = new System.Windows.Forms.OpenFileDialog();\r\n            this.groupBox1.SuspendLayout();\r\n            this.groupBox2.SuspendLayout();\r\n            this.SuspendLayout();\r\n            // \r\n            // label1\r\n            // \r\n            this.label1.Location = new System.Drawing.Point(8, 19);\r\n            this.label1.Name = \"label1\";\r\n            this.label1.Size = new System.Drawing.Size(101, 19);\r\n            this.label1.TabIndex = 0;\r\n            this.label1.Text = \"Load UO Client:\";\r\n            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\r\n            // \r\n            // browse\r\n            // \r\n            this.browse.Location = new System.Drawing.Point(308, 17);\r\n            this.browse.Name = \"browse\";\r\n            this.browse.Size = new System.Drawing.Size(64, 24);\r\n            this.browse.TabIndex = 1;\r\n            this.browse.Text = \"Browse...\";\r\n            this.browse.Click += new System.EventHandler(this.browse_Click);\r\n            // \r\n            // patchEncy\r\n            // \r\n            this.patchEncy.Location = new System.Drawing.Point(219, 76);\r\n            this.patchEncy.Name = \"patchEncy\";\r\n            this.patchEncy.Size = new System.Drawing.Size(152, 20);\r\n            this.patchEncy.TabIndex = 4;\r\n            this.patchEncy.Text = \"Patch client encryption\";\r\n            this.patchEncy.CheckedChanged += new System.EventHandler(this.patchEncy_CheckedChanged);\r\n            // \r\n            // okay\r\n            // \r\n            this.okay.DialogResult = System.Windows.Forms.DialogResult.OK;\r\n            this.okay.Location = new System.Drawing.Point(269, 306);\r\n            this.okay.Name = \"okay\";\r\n            this.okay.Size = new System.Drawing.Size(122, 43);\r\n            this.okay.TabIndex = 14;\r\n            this.okay.Text = \"&Launch\";\r\n            this.okay.Click += new System.EventHandler(this.okay_Click);\r\n            // \r\n            // quit\r\n            // \r\n            this.quit.DialogResult = System.Windows.Forms.DialogResult.Cancel;\r\n            this.quit.Location = new System.Drawing.Point(12, 323);\r\n            this.quit.Name = \"quit\";\r\n            this.quit.Size = new System.Drawing.Size(62, 26);\r\n            this.quit.TabIndex = 18;\r\n            this.quit.Text = \"&Quit\";\r\n            this.quit.Click += new System.EventHandler(this.quit_Click);\r\n            // \r\n            // selectServerLbl\r\n            // \r\n            this.selectServerLbl.Location = new System.Drawing.Point(9, 22);\r\n            this.selectServerLbl.Name = \"selectServerLbl\";\r\n            this.selectServerLbl.Size = new System.Drawing.Size(79, 19);\r\n            this.selectServerLbl.TabIndex = 9;\r\n            this.selectServerLbl.Text = \"Select Server:\";\r\n            this.selectServerLbl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\r\n            // \r\n            // serverList\r\n            // \r\n            this.serverList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\r\n            this.serverList.Font = new System.Drawing.Font(\"Segoe UI\", 9.75F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.serverList.Location = new System.Drawing.Point(101, 19);\r\n            this.serverList.Name = \"serverList\";\r\n            this.serverList.Size = new System.Drawing.Size(269, 25);\r\n            this.serverList.TabIndex = 5;\r\n            this.serverList.SelectedIndexChanged += new System.EventHandler(this.serverList_SelectedIndexChanged);\r\n            // \r\n            // groupBox1\r\n            // \r\n            this.groupBox1.Controls.Add(this.langSel);\r\n            this.groupBox1.Controls.Add(this.label5);\r\n            this.groupBox1.Controls.Add(this.showAtStart);\r\n            this.groupBox1.Controls.Add(this.dataDir);\r\n            this.groupBox1.Controls.Add(this.dataBrowse);\r\n            this.groupBox1.Controls.Add(this.uoClient);\r\n            this.groupBox1.Controls.Add(this.browse);\r\n            this.groupBox1.Controls.Add(this.label1);\r\n            this.groupBox1.Controls.Add(this.patchEncy);\r\n            this.groupBox1.Controls.Add(this.label2);\r\n            this.groupBox1.Location = new System.Drawing.Point(12, 12);\r\n            this.groupBox1.Name = \"groupBox1\";\r\n            this.groupBox1.Size = new System.Drawing.Size(379, 135);\r\n            this.groupBox1.TabIndex = 14;\r\n            this.groupBox1.TabStop = false;\r\n            this.groupBox1.Text = \"Client Options\";\r\n            // \r\n            // langSel\r\n            // \r\n            this.langSel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\r\n            this.langSel.Location = new System.Drawing.Point(77, 101);\r\n            this.langSel.Name = \"langSel\";\r\n            this.langSel.Size = new System.Drawing.Size(110, 23);\r\n            this.langSel.TabIndex = 27;\r\n            // \r\n            // label5\r\n            // \r\n            this.label5.Location = new System.Drawing.Point(9, 104);\r\n            this.label5.Name = \"label5\";\r\n            this.label5.Size = new System.Drawing.Size(90, 20);\r\n            this.label5.TabIndex = 28;\r\n            this.label5.Text = \"Language:\";\r\n            // \r\n            // showAtStart\r\n            // \r\n            this.showAtStart.Location = new System.Drawing.Point(11, 76);\r\n            this.showAtStart.Name = \"showAtStart\";\r\n            this.showAtStart.Size = new System.Drawing.Size(176, 20);\r\n            this.showAtStart.TabIndex = 26;\r\n            this.showAtStart.Text = \"Show this when Razor starts\";\r\n            this.showAtStart.CheckedChanged += new System.EventHandler(this.showAtStart_CheckedChanged);\r\n            // \r\n            // dataDir\r\n            // \r\n            this.dataDir.Location = new System.Drawing.Point(100, 47);\r\n            this.dataDir.Name = \"dataDir\";\r\n            this.dataDir.ReadOnly = true;\r\n            this.dataDir.Size = new System.Drawing.Size(202, 23);\r\n            this.dataDir.TabIndex = 2;\r\n            // \r\n            // dataBrowse\r\n            // \r\n            this.dataBrowse.Location = new System.Drawing.Point(308, 47);\r\n            this.dataBrowse.Name = \"dataBrowse\";\r\n            this.dataBrowse.Size = new System.Drawing.Size(63, 23);\r\n            this.dataBrowse.TabIndex = 3;\r\n            this.dataBrowse.Text = \"Browse...\";\r\n            this.dataBrowse.Click += new System.EventHandler(this.dataBrowse_Click);\r\n            // \r\n            // uoClient\r\n            // \r\n            this.uoClient.Location = new System.Drawing.Point(100, 18);\r\n            this.uoClient.Name = \"uoClient\";\r\n            this.uoClient.ReadOnly = true;\r\n            this.uoClient.Size = new System.Drawing.Size(202, 23);\r\n            this.uoClient.TabIndex = 0;\r\n            // \r\n            // label2\r\n            // \r\n            this.label2.Location = new System.Drawing.Point(8, 48);\r\n            this.label2.Name = \"label2\";\r\n            this.label2.Size = new System.Drawing.Size(101, 19);\r\n            this.label2.TabIndex = 25;\r\n            this.label2.Text = \"UO Data Folder:\";\r\n            this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;\r\n            // \r\n            // groupBox2\r\n            // \r\n            this.groupBox2.Controls.Add(this.newServer);\r\n            this.groupBox2.Controls.Add(this.serverName);\r\n            this.groupBox2.Controls.Add(this.serverNameLbl);\r\n            this.groupBox2.Controls.Add(this.serverPort);\r\n            this.groupBox2.Controls.Add(this.serverHost);\r\n            this.groupBox2.Controls.Add(this.portLabel);\r\n            this.groupBox2.Controls.Add(this.serverHostLbl);\r\n            this.groupBox2.Controls.Add(this.removeServer);\r\n            this.groupBox2.Controls.Add(this.saveServer);\r\n            this.groupBox2.Controls.Add(this.selectServerLbl);\r\n            this.groupBox2.Controls.Add(this.serverList);\r\n            this.groupBox2.Location = new System.Drawing.Point(12, 153);\r\n            this.groupBox2.Name = \"groupBox2\";\r\n            this.groupBox2.Size = new System.Drawing.Size(379, 147);\r\n            this.groupBox2.TabIndex = 15;\r\n            this.groupBox2.TabStop = false;\r\n            this.groupBox2.Text = \"Server\";\r\n            // \r\n            // newServer\r\n            // \r\n            this.newServer.Location = new System.Drawing.Point(135, 50);\r\n            this.newServer.Name = \"newServer\";\r\n            this.newServer.Size = new System.Drawing.Size(62, 27);\r\n            this.newServer.TabIndex = 20;\r\n            this.newServer.Text = \"New\";\r\n            this.newServer.UseVisualStyleBackColor = true;\r\n            this.newServer.Click += new System.EventHandler(this.newServer_Click);\r\n            // \r\n            // serverName\r\n            // \r\n            this.serverName.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.serverName.Location = new System.Drawing.Point(100, 86);\r\n            this.serverName.Name = \"serverName\";\r\n            this.serverName.Size = new System.Drawing.Size(270, 23);\r\n            this.serverName.TabIndex = 6;\r\n            this.serverName.TextChanged += new System.EventHandler(this.serverName_TextChanged);\r\n            // \r\n            // serverNameLbl\r\n            // \r\n            this.serverNameLbl.AutoSize = true;\r\n            this.serverNameLbl.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.serverNameLbl.Location = new System.Drawing.Point(7, 89);\r\n            this.serverNameLbl.Name = \"serverNameLbl\";\r\n            this.serverNameLbl.Size = new System.Drawing.Size(77, 15);\r\n            this.serverNameLbl.TabIndex = 19;\r\n            this.serverNameLbl.Text = \"Server Name:\";\r\n            // \r\n            // serverPort\r\n            // \r\n            this.serverPort.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.serverPort.Location = new System.Drawing.Point(307, 116);\r\n            this.serverPort.Name = \"serverPort\";\r\n            this.serverPort.Size = new System.Drawing.Size(63, 23);\r\n            this.serverPort.TabIndex = 8;\r\n            this.serverPort.Text = \"2593\";\r\n            this.serverPort.TextChanged += new System.EventHandler(this.serverPort_TextChanged);\r\n            // \r\n            // serverHost\r\n            // \r\n            this.serverHost.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.serverHost.Location = new System.Drawing.Point(100, 115);\r\n            this.serverHost.Name = \"serverHost\";\r\n            this.serverHost.Size = new System.Drawing.Size(163, 23);\r\n            this.serverHost.TabIndex = 7;\r\n            this.serverHost.TextChanged += new System.EventHandler(this.serverHost_TextChanged);\r\n            // \r\n            // portLabel\r\n            // \r\n            this.portLabel.AutoSize = true;\r\n            this.portLabel.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.portLabel.Location = new System.Drawing.Point(269, 118);\r\n            this.portLabel.Name = \"portLabel\";\r\n            this.portLabel.Size = new System.Drawing.Size(32, 15);\r\n            this.portLabel.TabIndex = 16;\r\n            this.portLabel.Text = \"Port:\";\r\n            // \r\n            // serverHostLbl\r\n            // \r\n            this.serverHostLbl.AutoSize = true;\r\n            this.serverHostLbl.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.serverHostLbl.Location = new System.Drawing.Point(7, 118);\r\n            this.serverHostLbl.Name = \"serverHostLbl\";\r\n            this.serverHostLbl.Size = new System.Drawing.Size(85, 15);\r\n            this.serverHostLbl.TabIndex = 15;\r\n            this.serverHostLbl.Text = \"Server Host/IP:\";\r\n            // \r\n            // removeServer\r\n            // \r\n            this.removeServer.Location = new System.Drawing.Point(203, 50);\r\n            this.removeServer.Name = \"removeServer\";\r\n            this.removeServer.Size = new System.Drawing.Size(63, 27);\r\n            this.removeServer.TabIndex = 10;\r\n            this.removeServer.Text = \"Remove\";\r\n            this.removeServer.UseVisualStyleBackColor = true;\r\n            this.removeServer.Click += new System.EventHandler(this.removeServer_Click);\r\n            // \r\n            // saveServer\r\n            // \r\n            this.saveServer.Enabled = false;\r\n            this.saveServer.Location = new System.Drawing.Point(272, 50);\r\n            this.saveServer.Name = \"saveServer\";\r\n            this.saveServer.Size = new System.Drawing.Size(63, 27);\r\n            this.saveServer.TabIndex = 9;\r\n            this.saveServer.Text = \"Save\";\r\n            this.saveServer.UseVisualStyleBackColor = true;\r\n            this.saveServer.Click += new System.EventHandler(this.saveServer_Click);\r\n            // \r\n            // openFile\r\n            // \r\n            this.openFile.DefaultExt = \"exe\";\r\n            this.openFile.FileName = \"client.exe\";\r\n            this.openFile.Filter = \"UO Client|client.exe\";\r\n            this.openFile.Title = \"Select UO Client\";\r\n            // \r\n            // WelcomeForm\r\n            // \r\n            this.AcceptButton = this.okay;\r\n            this.AutoScaleBaseSize = new System.Drawing.Size(6, 16);\r\n            this.CancelButton = this.quit;\r\n            this.ClientSize = new System.Drawing.Size(401, 358);\r\n            this.Controls.Add(this.groupBox2);\r\n            this.Controls.Add(this.groupBox1);\r\n            this.Controls.Add(this.quit);\r\n            this.Controls.Add(this.okay);\r\n            this.Font = new System.Drawing.Font(\"Segoe UI\", 9F, System.Drawing.FontStyle.Regular,\r\n                System.Drawing.GraphicsUnit.Point, ((byte) (0)));\r\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;\r\n            this.Icon = ((System.Drawing.Icon) (resources.GetObject(\"$this.Icon\")));\r\n            this.MaximizeBox = false;\r\n            this.MinimizeBox = false;\r\n            this.Name = \"WelcomeForm\";\r\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\r\n            this.Text = \"Welcome to Razor: UOR Community Edition!\";\r\n            this.Closing += new System.ComponentModel.CancelEventHandler(this.WelcomeForm_Closing);\r\n            this.Load += new System.EventHandler(this.WelcomeForm_Load);\r\n            this.groupBox1.ResumeLayout(false);\r\n            this.groupBox1.PerformLayout();\r\n            this.groupBox2.ResumeLayout(false);\r\n            this.groupBox2.PerformLayout();\r\n            this.ResumeLayout(false);\r\n        }\r\n\r\n        #endregion\r\n\r\n        private class ServerEntry\r\n        {\r\n            public ServerEntry(string addr, int p)\r\n            {\r\n                Address = addr;\r\n                Port = p;\r\n            }\r\n\r\n            public string Address;\r\n            public int Port;\r\n\r\n            public override string ToString()\r\n            {\r\n                return Address;\r\n            }\r\n        }\r\n\r\n        private class LoginCFG_SE : ServerEntry\r\n        {\r\n            public string RealAddress;\r\n\r\n            public LoginCFG_SE() : base(\"Use Last\", 0)\r\n            {\r\n                RealAddress = Config.GetAppSetting<string>(\"LastServer\");\r\n                Port = Config.GetAppSetting<int>(\"LastPort\");\r\n\r\n                if (string.IsNullOrEmpty(RealAddress) || Port == 0)\r\n                {\r\n                    RealAddress = \"\";\r\n                    Port = 0;\r\n\r\n                    try\r\n                    {\r\n                        string fileName = Ultima.Files.GetFilePath(\"Login.cfg\");\r\n                        if (string.IsNullOrEmpty(fileName))\r\n                            return;\r\n                        string server = null, port = null;\r\n\r\n                        if (File.Exists(fileName))\r\n                        {\r\n                            using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read,\r\n                                FileShare.ReadWrite))\r\n                            using (StreamReader cfg = new StreamReader(file))\r\n                            {\r\n                                string line;\r\n                                while ((line = cfg.ReadLine()) != null)\r\n                                {\r\n                                    line = line.Trim();\r\n                                    if (line != \"\" && Char.ToUpper(line[0]) == 'L' && line.Length > 12)\r\n                                    {\r\n                                        int comma = line.IndexOf(',');\r\n                                        if (comma > 12)\r\n                                        {\r\n                                            server = line.Substring(12, comma - 12);\r\n                                            port = line.Substring(comma + 1);\r\n\r\n                                            break;\r\n                                        }\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n\r\n                        if (server != null)\r\n                        {\r\n                            Address = \"(Use Last: \" + server + \")\";\r\n                            RealAddress = server;\r\n                        }\r\n\r\n                        if (port != null)\r\n                            Port = Utility.ToInt32(port, 0);\r\n                    }\r\n                    catch\r\n                    {\r\n                        RealAddress = Address = \"Use Last\";\r\n                        Port = 0;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        private class ShardEntry\r\n        {\r\n            public string name { get; set; }\r\n            public string type { get; set; }\r\n            public string host { get; set; }\r\n            public int port { get; set; }\r\n        }\r\n\r\n        private class Custom_SE : ServerEntry\r\n        {\r\n            public string RealAddress { get; set; }\r\n            public string Name { get; set; }\r\n\r\n            public Custom_SE(string name, string addr) : base(name, 0)\r\n            {\r\n                Name = name;\r\n                RealAddress = addr;\r\n            }\r\n\r\n            public Custom_SE(string name, string addr, int port)\r\n                : base(name, port)\r\n            {\r\n                Name = name;\r\n                RealAddress = addr;\r\n            }\r\n        }\r\n\r\n        private class PathElipsis\r\n        {\r\n            private string m_Path;\r\n            private string m_Show;\r\n\r\n            public PathElipsis(string path)\r\n            {\r\n                m_Path = path;\r\n                m_Show = GetPathElipsis(path, 23);\r\n            }\r\n\r\n            public string GetPath()\r\n            {\r\n                return m_Path;\r\n            }\r\n\r\n            public void SetPath(string value)\r\n            {\r\n                m_Path = value;\r\n                m_Show = GetPathElipsis(m_Path, 23);\r\n            }\r\n\r\n            public override string ToString()\r\n            {\r\n                return m_Show;\r\n            }\r\n\r\n            private static char[] pathChars = new char[]\r\n            {\r\n                Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar, Path.PathSeparator,\r\n                Path.VolumeSeparatorChar\r\n            };\r\n\r\n            public static string GetPathElipsis(string path, int PathMaxLength)\r\n            {\r\n                if (path.Length <= PathMaxLength)\r\n                    return path;\r\n\r\n                System.Text.StringBuilder sb = new System.Text.StringBuilder(path);\r\n                int remlen = path.Length - PathMaxLength - 3;\r\n\r\n                int ls = path.LastIndexOfAny(pathChars);\r\n                if (ls == -1)\r\n                    ls = 15 + remlen;\r\n\r\n                if (ls - remlen < 4)\r\n                    ls = remlen + 4;\r\n\r\n                if (ls > remlen && remlen > 0)\r\n                {\r\n                    try\r\n                    {\r\n                        sb.Remove(ls - remlen, remlen);\r\n                        sb.Insert(ls - remlen, \"...\");\r\n                    }\r\n                    catch\r\n                    {\r\n                    }\r\n                }\r\n\r\n                return sb.ToString();\r\n            }\r\n        }\r\n\r\n        private void WelcomeForm_Load(object sender, System.EventArgs e)\r\n        {\r\n            Language.LoadControlNames(this);\r\n\r\n            this.BringToFront();\r\n\r\n            langSel.Items.AddRange(Language.GetPackNames());\r\n            langSel.SelectedItem = Language.Current;\r\n\r\n            showAtStart.Checked = Config.GetAppSetting<int>(\"ShowWelcome\") == 1;\r\n\r\n            uoClient.Text = Config.GetAppSetting<string>(\"UOClient\");\r\n            dataDir.Text = Config.GetAppSetting<string>(\"UODataDir\");\r\n\r\n            IsValidClientAndDataDir();\r\n\r\n            patchEncy.Checked = Config.GetAppSetting<int>(\"ClientEncrypted\") != 0;\r\n\r\n            LoginCFG_SE lse = new LoginCFG_SE();\r\n\r\n            serverList.BeginUpdate();\r\n            \r\n            // Load any custom servers they might have added\r\n            NameValueCollection servers =\r\n                (NameValueCollection) ConfigurationManager.GetSection(\"Servers\");\r\n\r\n            foreach (string server in servers.AllKeys)\r\n            {\r\n                string[] serverHostAndPort = servers[server].Split(',');\r\n                string serverHost = serverHostAndPort[0];\r\n                string serverPort = serverHostAndPort[1];\r\n\r\n                serverList.Items.Add(new Custom_SE(server, serverHost, Convert.ToInt32(serverPort)));\r\n            }\r\n\r\n            serverList.EndUpdate();\r\n            serverList.Refresh();\r\n\r\n            // Set it to the last used one, or just set it to default UOR Prod\r\n            try\r\n            {\r\n                serverList.SelectedIndex = Config.GetAppSetting<int>(\"LastServerId\");\r\n            }\r\n            catch\r\n            {\r\n                serverList.SelectedIndex = 0;\r\n            }\r\n\r\n            WindowState = FormWindowState.Normal;\r\n            this.BringToFront();\r\n            this.TopMost = true;\r\n\r\n            _ShowTimer = new System.Windows.Forms.Timer();\r\n            _ShowTimer.Interval = 250;\r\n            _ShowTimer.Enabled = true;\r\n            _ShowTimer.Tick += new EventHandler(timer_Tick);\r\n\r\n\r\n            if (Config.GetAppSetting<bool>(\"ImportProfilesAndMacros\"))\r\n            {\r\n                string appDataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),\r\n                    \"Razor\");\r\n\r\n                if (Directory.Exists(appDataDir))\r\n                {\r\n                    if (MessageBox.Show(Language.GetString(LocString.ImportFromPrevious),\r\n                            \"Import Razor Profiles and Macros\",\r\n                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)\r\n                    {\r\n                        Config.ImportProfilesMacros(appDataDir);\r\n\r\n                        MessageBox.Show(\"Import complete\", \"Import Razor Profiles and Macros\", MessageBoxButtons.OK);\r\n                    }\r\n                }\r\n\r\n                Config.SetAppSetting(\"ImportProfilesAndMacros\", \"false\");\r\n            }\r\n        }\r\n        \r\n        private System.Windows.Forms.Timer _ShowTimer;\r\n\r\n        private void timer_Tick(object sender, EventArgs e)\r\n        {\r\n            this.TopMost = false;\r\n            this.BringToFront();\r\n\r\n            if (_ShowTimer != null)\r\n                _ShowTimer.Stop();\r\n        }\r\n\r\n        private void browse_Click(object sender, System.EventArgs e)\r\n        {\r\n            if (openFile.ShowDialog(this) == DialogResult.OK)\r\n            {\r\n                PathElipsis pe = new PathElipsis(openFile.FileName);\r\n\r\n                uoClient.Text = pe.GetPath();\r\n\r\n                dataDir.Text = m_DataDir = Path.GetDirectoryName(uoClient.Text);\r\n\r\n                Config.SetAppSetting(\"UODataDir\", dataDir.Text);\r\n                Config.SetAppSetting(\"UOClient\", uoClient.Text);\r\n\r\n                IsValidClientAndDataDir();\r\n            }\r\n        }\r\n\r\n        private void serverList_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (serverList.SelectedIndex < 0)\r\n            {\r\n                serverName.Enabled = true;\r\n                serverHost.Enabled = true;\r\n                serverPort.Enabled = true;\r\n\r\n                return;\r\n            }\r\n\r\n            Custom_SE server = (Custom_SE) serverList.SelectedItem;\r\n\r\n            serverName.Enabled = !(serverList.SelectedIndex >= 0 && serverList.SelectedIndex <= 2);\r\n            serverHost.Enabled = !(serverList.SelectedIndex >= 0 && serverList.SelectedIndex <= 2);\r\n            serverPort.Enabled = !(serverList.SelectedIndex >= 0 && serverList.SelectedIndex <= 2);\r\n            removeServer.Enabled = !(serverList.SelectedIndex >= 0 && serverList.SelectedIndex <= 2);\r\n\r\n            serverName.Text = server.Name;\r\n            serverHost.Text = server.RealAddress;\r\n            serverPort.Text = server.Port.ToString();\r\n            saveServer.Enabled = false;\r\n        }\r\n\r\n        private void okay_Click(object sender, System.EventArgs e)\r\n        {\r\n            m_ClientPath = uoClient.Text;\r\n\r\n            ServerEntry se = null;\r\n\r\n            if (serverList.SelectedItem != null)\r\n            {\r\n                if (serverList.SelectedItem is Custom_SE)\r\n                {\r\n                    int port = ((Custom_SE) serverList.SelectedItem).Port;\r\n\r\n                    string addr = ((Custom_SE) serverList.SelectedItem).RealAddress;\r\n\r\n                    if (addr == \"login.ultimaonline.com\")\r\n                    {\r\n                        Config.SetAppSetting(\"ServerEncrypted\", \"1\");\r\n                    }\r\n\r\n                    if (port == 0)\r\n                        port = 2593; // runuo default\r\n\r\n                    se = new ServerEntry(addr, port);\r\n                }\r\n            }\r\n\r\n            if (se != null && se.Address != null)\r\n            {\r\n                Config.SetAppSetting(\"LastServer\", se.Address);\r\n                Config.SetAppSetting(\"LastPort\", se.Port.ToString());\r\n\r\n                Config.SetAppSetting(\"LastServerId\", serverList.SelectedIndex.ToString());\r\n            }\r\n\r\n            SaveData();\r\n            this.Close();\r\n        }\r\n\r\n        private void quit_Click(object sender, System.EventArgs e)\r\n        {\r\n            SaveData();\r\n            this.Close();\r\n        }\r\n\r\n        private void SaveData()\r\n        {\r\n            for (int i = 0; i < serverList.Items.Count; i++)\r\n            {\r\n                for (int j = i + 1; j < serverList.Items.Count; j++)\r\n                {\r\n                    ServerEntry si = (ServerEntry) serverList.Items[i];\r\n                    ServerEntry sj = (ServerEntry) serverList.Items[j];\r\n                    if (si.Address == sj.Address && si.Port == sj.Port)\r\n                        serverList.Items.RemoveAt(j);\r\n                }\r\n            }\r\n\r\n            int num = 1;\r\n            for (int i = 0; i < serverList.Items.Count; i++)\r\n            {\r\n                ServerEntry se = (ServerEntry) serverList.Items[i];\r\n                if (se is Custom_SE || se is LoginCFG_SE)\r\n                    continue;\r\n\r\n                if (se.Address != \"\")\r\n                {\r\n                    Config.SetAppSetting($\"Server{num}\", se.Address);\r\n                    Config.SetAppSetting($\"Port{num}\", se.Port.ToString());\r\n                    num++;\r\n                }\r\n            }\r\n\r\n            Config.SetAppSetting(\"UOClient\", uoClient.Text);\r\n            Config.SetAppSetting(\"UODataDir\", dataDir.Text);\r\n            m_DataDir = dataDir.Text;\r\n        }\r\n\r\n        private void showAtStart_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            Config.SetAppSetting(\"ShowWelcome\", (showAtStart.Checked ? 1 : 0).ToString());\r\n        }\r\n\r\n        private void langSel_SelectedIndexChanged(object sender, System.EventArgs e)\r\n        {\r\n            string lang = langSel.SelectedItem as string;\r\n\r\n            if (lang != null && lang != Language.Current)\r\n            {\r\n                if (!Language.Load(lang))\r\n                {\r\n                    MessageBox.Show(\"There was an error loading that language.\", \"Language Load Error\",\r\n                        MessageBoxButtons.OK, MessageBoxIcon.Warning);\r\n                    langSel.SelectedItem = Language.Current;\r\n                }\r\n                else\r\n                {\r\n                    Config.SetAppSetting(\"DefaultLanguage\", Language.Current);\r\n                    Language.LoadControlNames(this);\r\n                }\r\n            }\r\n        }\r\n\r\n        private void patchEncy_CheckedChanged(object sender, System.EventArgs e)\r\n        {\r\n            if (!patchEncy.Checked)\r\n            {\r\n                if (MessageBox.Show(this, Language.GetString(LocString.NoPatchWarning),\r\n                        Language.GetString(LocString.Confirm), MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==\r\n                    DialogResult.No)\r\n                    patchEncy.Checked = true;\r\n            }\r\n\r\n            Config.SetAppSetting(\"ClientEncrypted\", patchEncy.Checked ? \"1\" : \"0\");\r\n        }\r\n\r\n        private void dataBrowse_Click(object sender, System.EventArgs e)\r\n        {\r\n            FolderBrowserDialog folder = new FolderBrowserDialog();\r\n\r\n            folder.Description = \"Select a UO Data Directory...\";\r\n\r\n            if (m_DataDir != null)\r\n                folder.SelectedPath = m_DataDir;\r\n\r\n            folder.ShowNewFolderButton = false;\r\n            if (folder.ShowDialog() == DialogResult.OK)\r\n            {\r\n                dataDir.Text = m_DataDir = folder.SelectedPath;\r\n                Config.SetAppSetting(\"UODataDir\", dataDir.Text);\r\n\r\n                IsValidClientAndDataDir();\r\n\r\n                if (!dataDir.Text.Equals(Path.GetDirectoryName(uoClient.Text)))\r\n                {\r\n                    MessageBox.Show(Language.GetString(LocString.ClientDataMismatch), \"Warning\", MessageBoxButtons.OK,\r\n                        MessageBoxIcon.Warning);\r\n                }\r\n            }\r\n        }\r\n\r\n        private void WelcomeForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)\r\n        {\r\n            SaveData();\r\n        }\r\n\r\n        private bool IsValidClientAndDataDir()\r\n        {\r\n            okay.Enabled = false;\r\n\r\n            if (string.IsNullOrEmpty(uoClient.Text) || string.IsNullOrEmpty(dataDir.Text))\r\n            {\r\n                return false;\r\n            }\r\n\r\n\r\n            if (!File.Exists(uoClient.Text) || !Directory.Exists(dataDir.Text))\r\n            {\r\n                return false;\r\n            }\r\n\r\n            okay.Enabled = true;\r\n            return true;\r\n        }\r\n\r\n        private void saveServer_Click(object sender, EventArgs e)\r\n        {\r\n            if (string.IsNullOrEmpty(serverName.Text) || string.IsNullOrEmpty(serverHost.Text) ||\r\n                string.IsNullOrEmpty(serverPort.Text))\r\n            {\r\n                MessageBox.Show(\"You must fill out all three fields\", \"Server Add/Edit\", MessageBoxButtons.OK,\r\n                    MessageBoxIcon.Error);\r\n                return;\r\n            }\r\n\r\n            if (int.TryParse(serverPort.Text, out _) == false)\r\n            {\r\n                MessageBox.Show(\"Invalid port\", \"Server Add/Edit\", MessageBoxButtons.OK, MessageBoxIcon.Error);\r\n                return;\r\n            }\r\n\r\n            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);\r\n            AppSettingsSection servers = (AppSettingsSection) config.GetSection(\"Servers\");\r\n\r\n            if (string.IsNullOrEmpty(serverList.Text)) // new entry\r\n            {\r\n                servers.Settings.Add(serverName.Text, $\"{serverHost.Text},{serverPort.Text}\");\r\n                config.Save(ConfigurationSaveMode.Modified, true);\r\n\r\n                ConfigurationManager.RefreshSection(\"Servers\");\r\n\r\n                serverList.Items.Add(new Custom_SE(serverName.Text, serverHost.Text, Convert.ToInt32(serverPort.Text)));\r\n\r\n                serverList.SelectedIndex = serverList.Items.Count - 1;\r\n            }\r\n            else\r\n            {\r\n                Dictionary<string, string> entries = new Dictionary<string, string>();\r\n\r\n                int index = 3;\r\n                foreach (KeyValueConfigurationElement server in servers.Settings)\r\n                {\r\n                    if (serverList.SelectedIndex == index)\r\n                    {\r\n                        entries.Add(serverName.Text, $\"{serverHost.Text},{serverPort.Text}\");\r\n                    }\r\n                    else\r\n                    {\r\n                        entries.Add(server.Key, server.Value);\r\n                    }\r\n\r\n                    index++;\r\n                }\r\n\r\n                servers.Settings.Clear();\r\n                serverList.Items.Clear();\r\n                \r\n                foreach (KeyValuePair<string, string> entry in entries)\r\n                {\r\n                    servers.Settings.Add(entry.Key, entry.Value);\r\n\r\n                    string[] address = entry.Value.Split(',');\r\n\r\n                    serverList.Items.Add(new Custom_SE(entry.Key, address[0], Convert.ToInt32(address[1])));\r\n                }\r\n\r\n                config.Save(ConfigurationSaveMode.Modified, true);\r\n                ConfigurationManager.RefreshSection(\"Servers\");\r\n            }\r\n\r\n            saveServer.Enabled = false;\r\n        }\r\n\r\n        private void newServer_Click(object sender, EventArgs e)\r\n        {\r\n            serverName.Text = string.Empty;\r\n            serverHost.Text = string.Empty;\r\n            serverPort.Text = string.Empty;\r\n            serverList.SelectedIndex = -1;\r\n\r\n            saveServer.Enabled = true;\r\n        }\r\n\r\n        private void serverName_TextChanged(object sender, EventArgs e)\r\n        {\r\n            saveServer.Enabled = true;\r\n        }\r\n\r\n        private void serverHost_TextChanged(object sender, EventArgs e)\r\n        {\r\n            saveServer.Enabled = true;\r\n        }\r\n\r\n        private void serverPort_TextChanged(object sender, EventArgs e)\r\n        {\r\n            saveServer.Enabled = true;\r\n        }\r\n\r\n        private void removeServer_Click(object sender, EventArgs e)\r\n        {\r\n            if (serverList.SelectedIndex < 0)\r\n                return;\r\n\r\n            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);\r\n            AppSettingsSection servers = (AppSettingsSection) config.GetSection(\"Servers\");\r\n\r\n            Dictionary<string, string> entries = new Dictionary<string, string>();\r\n\r\n            int index = 0;\r\n            foreach (KeyValueConfigurationElement server in servers.Settings)\r\n            {\r\n                if (serverList.SelectedIndex != index + 3)\r\n                {\r\n                    entries.Add(server.Key, server.Value);\r\n                }\r\n\r\n                index++;\r\n            }\r\n\r\n            servers.Settings.Clear();\r\n            serverList.Items.Clear();\r\n            \r\n            foreach (KeyValuePair<string, string> entry in entries)\r\n            {\r\n                servers.Settings.Add(entry.Key, entry.Value);\r\n\r\n                string[] address = entry.Value.Split(',');\r\n\r\n                serverList.Items.Add(new Custom_SE(entry.Key, address[0], Convert.ToInt32(address[1])));\r\n            }\r\n\r\n            config.Save(ConfigurationSaveMode.Modified, true);\r\n            ConfigurationManager.RefreshSection(\"Servers\");\r\n\r\n            serverName.Text = string.Empty;\r\n            serverHost.Text = string.Empty;\r\n            serverPort.Text = string.Empty;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "Razor/UI/WelcomeForm.resx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n  <!-- \r\n    Microsoft ResX Schema \r\n    \r\n    Version 2.0\r\n    \r\n    The primary goals of this format is to allow a simple XML format \r\n    that is mostly human readable. The generation and parsing of the \r\n    various data types are done through the TypeConverter classes \r\n    associated with the data types.\r\n    \r\n    Example:\r\n    \r\n    ... ado.net/XML headers & schema ...\r\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\r\n    <resheader name=\"version\">2.0</resheader>\r\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\r\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\r\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\r\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\r\n    </data>\r\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r\n        <comment>This is a comment</comment>\r\n    </data>\r\n                \r\n    There are any number of \"resheader\" rows that contain simple \r\n    name/value pairs.\r\n    \r\n    Each data row contains a name, and value. The row also contains a \r\n    type or mimetype. Type corresponds to a .NET class that support \r\n    text/value conversion through the TypeConverter architecture. \r\n    Classes that don't support this are serialized and stored with the \r\n    mimetype set.\r\n    \r\n    The mimetype is used for serialized objects, and tells the \r\n    ResXResourceReader how to depersist the object. This is currently not \r\n    extensible. For a given mimetype the value must be set accordingly:\r\n    \r\n    Note - application/x-microsoft.net.object.binary.base64 is the format \r\n    that the ResXResourceWriter will generate, however the reader can \r\n    read any of the formats listed below.\r\n    \r\n    mimetype: application/x-microsoft.net.object.binary.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\r\n            : and then encoded with base64 encoding.\r\n    \r\n    mimetype: application/x-microsoft.net.object.soap.base64\r\n    value   : The object must be serialized with \r\n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r\n            : and then encoded with base64 encoding.\r\n\r\n    mimetype: application/x-microsoft.net.object.bytearray.base64\r\n    value   : The object must be serialized into a byte array \r\n            : using a System.ComponentModel.TypeConverter\r\n            : and then encoded with base64 encoding.\r\n    -->\r\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\r\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\r\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\r\n      <xsd:complexType>\r\n        <xsd:choice maxOccurs=\"unbounded\">\r\n          <xsd:element name=\"metadata\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"assembly\">\r\n            <xsd:complexType>\r\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"data\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\r\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\r\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\r\n              <xsd:attribute ref=\"xml:space\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n          <xsd:element name=\"resheader\">\r\n            <xsd:complexType>\r\n              <xsd:sequence>\r\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\r\n              </xsd:sequence>\r\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\r\n            </xsd:complexType>\r\n          </xsd:element>\r\n        </xsd:choice>\r\n      </xsd:complexType>\r\n    </xsd:element>\r\n  </xsd:schema>\r\n  <resheader name=\"resmimetype\">\r\n    <value>text/microsoft-resx</value>\r\n  </resheader>\r\n  <resheader name=\"version\">\r\n    <value>2.0</value>\r\n  </resheader>\r\n  <resheader name=\"reader\">\r\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <resheader name=\"writer\">\r\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r\n  </resheader>\r\n  <metadata name=\"openFile.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\r\n    <value>17, 17</value>\r\n  </metadata>\r\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\r\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\r\n    <value>\r\n        AAABAAEAICAAAAAAAACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAQAAAAAAAAAAAAAAAEAAAAB\r\n        AAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYW\r\n        FgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAA\r\n        MwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm\r\n        /wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/\r\n        zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNm\r\n        ZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM\r\n        /wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYz\r\n        mQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbM\r\n        MwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkz\r\n        MwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnM\r\n        AACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwA\r\n        mQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZ\r\n        MwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/\r\n        zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9m\r\n        zADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/\r\n        ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKy\r\n        sgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//\r\n        AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK\r\n        CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCrcKCgoKCgoKCgoKCgoK\r\n        CgoKCgoKCgoKCgoKCgoKCgoK+QoKCgoKCgoKCgrSCgoKCgoKCgoKCgoKCgoKCgoKCgr5+QoKCgoKCgr5\r\n        sQoKCgoKCgoKCgoKCgoKCgoKCgoKCvn5CgoKCgoKsbEKCgoKCgoKCgoKCgoKCgoKCgoKCgoK+ZQKCgoK\r\n        CuPjCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr5sQoKCgpHsQoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgpq\r\n        Cgr5QbEKCgqxtwoKCgoKCgr5CgoK+QoKCgoKCgoKCuP5lPmUCgoKCrGxt7f5+fkKCvkK+fkKCgoKCgoK\r\n        CgoKFkH5lAoK+QoK+bcKCgr5t7cK+fn5CgoKCgoKCgoKCrdB+fkKCgoK0rext7EKCvn5Crf5+QoKCgoK\r\n        CgoKCgqx+UdBCgoKCgq3+fkKt5QK+fkK0vn5CgoKCgoKCgoKCgq3+UGUCgoKCvmxtwoKsbcK+QqUCvn5\r\n        +QoKCgoKCgoKCgr5F0f5CgoKCmqxCgoKavn5+eP5arexagoKCgoKCgoKCgqU+Wrj+QoKt7cKRmlq+Qq3\r\n        lJQXF+MWCgoKCgoKCgoKCvn5+flq4/kKCuvs7O0KCgoKCgoKCgoKCgoKCgoKCgoKCkfjCgoWRxaSku3s\r\n        7OwKCgoKCgoKCgoKCgoKCgoKCgoK+fkKCgr5bpKS7e3t7eztCgoKCgoKCgoKCgoKCgoKCgr5+ZQKCgqS\r\n        kpLt7e3t7e3tCgoKCgoKCgoKCgoKCgoKCgr54woK7++SkpLt7e3t7Ozs7fcKCgoKCgoKCgoKCrHjFkEX\r\n        FhZpku/3kpLt7e3s7Ozs7JIKCgoKCgoKCgoKR/n5+fn5+fkg7e+SkpLt7Ozs7Ozs7ZIKCgoKCgoKCgpH\r\n        QUFBQUcXahbt95KS7e3s7Ozs7Oztkvf3CgoKCgoKCgoKCgrs6+wKCpKS7e3t7Ozs7Ozt7ZL39+/vCgoK\r\n        CgoKCgoKCuzr6uzs7ZLt7ezs7Ozs7ZKS9+/v7+/vCgoKCgoKCgrr7JLrbeyS7ezs7Ozs7ZKS9/fv7wcH\r\n        BwcKCgoKCgoK7BLs7/fs7Ozs7Ozs7O2S9+/v7+8HBwcHBwoKCgoKCgoSbe8H7+zt7Ovs7O2Skvfv7+8H\r\n        BwcHBwcHCgoKCgoK7ezv7++S7O3v9+zs9/fv7+8HBwcHBwcH8fAKCgoKCuwS6+ztkvfv7+8HB/f3B7y8\r\n        vPDw8PDwvPP/8/////////////////f////3/v//8/n///Pz///z5///88////sc/u/4PAaf+GziP/Dw\r\n        ZH/h8SR/8PGVH/h5wA/8GQgP/AYf//5gD//+cAP//jgB//8wAD/4AAAf+AAAD/gAAAP/jAAB/4AAAP8A\r\n        AAD+AAAA/gAAAPwAAAD4AAAA\r\n</value>\r\n  </data>\r\n</root>"
  },
  {
    "path": "Razor/UltimaSDK/ASCIIFont.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\n// ascii text support written by arul\nnamespace Ultima\n{\n    public sealed class ASCIIFont\n    {\n        public byte Header { get; private set; }\n        public byte[] Unk { get; set; }\n        public Bitmap[] Characters { get; set; }\n        public int Height { get; set; }\n\n\n        public ASCIIFont(byte header)\n        {\n            Header = header;\n            Height = 0;\n            Unk = new byte[224];\n            Characters = new Bitmap[224];\n        }\n\n        /// <summary>\n        /// Gets Bitmap of given character\n        /// </summary>\n        /// <param name=\"character\"></param>\n        /// <returns></returns>\n        public Bitmap GetBitmap(char character)\n        {\n            return Characters[(((((int) character) - 0x20) & 0x7FFFFFFF) % 224)];\n        }\n\n        public int GetWidth(string text)\n        {\n            if (text == null || text.Length == 0)\n            {\n                return 0;\n            }\n\n            int width = 0;\n\n            for (int i = 0; i < text.Length; ++i)\n            {\n                width += GetBitmap(text[i]).Width;\n            }\n\n            return width;\n        }\n\n        public void ReplaceCharacter(int character, Bitmap import)\n        {\n            Characters[character] = import;\n            Height = import.Height;\n        }\n\n        public static ASCIIFont GetFixed(int font)\n        {\n            if (font < 0 || font > 9)\n            {\n                return ASCIIText.Fonts[3];\n            }\n\n            return ASCIIText.Fonts[font];\n        }\n    }\n\n    public static class ASCIIText\n    {\n        public static ASCIIFont[] Fonts = new ASCIIFont[10];\n\n        static ASCIIText()\n        {\n            Initialize();\n        }\n\n        /// <summary>\n        /// Reads fonts.mul\n        /// </summary>\n        public static unsafe void Initialize()\n        {\n            string path = Files.GetFilePath(\"fonts.mul\");\n\n            if (path != null)\n            {\n                using (FileStream reader = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    byte[] buffer = new byte[(int) reader.Length];\n                    reader.Read(buffer, 0, (int) reader.Length);\n                    fixed (byte* bin = buffer)\n                    {\n                        byte* read = bin;\n                        for (int i = 0; i < 10; ++i)\n                        {\n                            byte header = *read++;\n                            Fonts[i] = new ASCIIFont(header);\n\n                            for (int k = 0; k < 224; ++k)\n                            {\n                                byte width = *read++;\n                                byte height = *read++;\n                                byte unk = *read++; // delimeter?\n\n                                if (width > 0 && height > 0)\n                                {\n                                    if (height > Fonts[i].Height && k < 96)\n                                        Fonts[i].Height = height;\n\n                                    Bitmap bmp = new Bitmap(width, height);\n                                    BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),\n                                        ImageLockMode.WriteOnly, PixelFormat.Format16bppArgb1555);\n                                    ushort* line = (ushort*) bd.Scan0;\n                                    int delta = bd.Stride >> 1;\n\n                                    for (int y = 0; y < height; ++y, line += delta)\n                                    {\n                                        ushort* cur = line;\n                                        for (int x = 0; x < width; ++x)\n                                        {\n                                            ushort pixel = (ushort) (*read++ | (*read++ << 8));\n                                            if (pixel == 0)\n                                                cur[x] = pixel;\n                                            else\n                                                cur[x] = (ushort) (pixel ^ 0x8000);\n                                        }\n                                    }\n\n                                    bmp.UnlockBits(bd);\n                                    Fonts[i].Characters[k] = bmp;\n                                    Fonts[i].Unk[k] = unk;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        public static unsafe void Save(string FileName)\n        {\n            using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    for (int i = 0; i < 10; ++i)\n                    {\n                        bin.Write(Fonts[i].Header);\n                        for (int k = 0; k < 224; ++k)\n                        {\n                            bin.Write((byte) Fonts[i].Characters[k].Width);\n                            bin.Write((byte) Fonts[i].Characters[k].Height);\n                            bin.Write(Fonts[i].Unk[k]);\n                            Bitmap bmp = Fonts[i].Characters[k];\n                            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),\n                                ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555);\n                            ushort* line = (ushort*) bd.Scan0;\n                            int delta = bd.Stride >> 1;\n                            for (int y = 0; y < bmp.Height; ++y, line += delta)\n                            {\n                                ushort* cur = line;\n                                for (int x = 0; x < bmp.Width; ++x)\n                                {\n                                    if (cur[x] == 0)\n                                        bin.Write(cur[x]);\n                                    else\n                                        bin.Write((ushort) (cur[x] ^ 0x8000));\n                                }\n                            }\n\n                            bmp.UnlockBits(bd);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Draws Text with font in Bitmap and returns\n        /// </summary>\n        /// <param name=\"fontId\"></param>\n        /// <param name=\"text\"></param>\n        /// <returns></returns>\n        public static Bitmap DrawText(int fontId, string text)\n        {\n            ASCIIFont font = ASCIIFont.GetFixed(fontId);\n            Bitmap result = new Bitmap(font.GetWidth(text) + 2, font.Height + 2);\n\n            int dx = 2;\n            int dy = font.Height + 2;\n            using (Graphics graph = Graphics.FromImage(result))\n            {\n                for (int i = 0; i < text.Length; ++i)\n                {\n                    Bitmap bmp = font.GetBitmap(text[i]);\n                    graph.DrawImage(bmp, dx, dy - bmp.Height);\n                    dx += bmp.Width;\n                }\n            }\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/AnimationEdit.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\n//using System.Windows.Media.Imaging;\n\nnamespace Ultima\n{\n    public sealed class AnimationEdit\n    {\n        private static FileIndex m_FileIndex = new FileIndex(\"Anim.idx\", \"Anim.mul\", 6);\n        private static FileIndex m_FileIndex2 = new FileIndex(\"Anim2.idx\", \"Anim2.mul\", -1);\n        private static FileIndex m_FileIndex3 = new FileIndex(\"Anim3.idx\", \"Anim3.mul\", -1);\n        private static FileIndex m_FileIndex4 = new FileIndex(\"Anim4.idx\", \"Anim4.mul\", -1);\n        private static FileIndex m_FileIndex5 = new FileIndex(\"Anim5.idx\", \"Anim5.mul\", -1);\n\n        private static AnimIdx[] animcache;\n        private static AnimIdx[] animcache2;\n        private static AnimIdx[] animcache3;\n        private static AnimIdx[] animcache4;\n        private static AnimIdx[] animcache5;\n\n        static AnimationEdit()\n        {\n            if (m_FileIndex.IdxLength > 0)\n                animcache = new AnimIdx[m_FileIndex.IdxLength / 12];\n            if (m_FileIndex2.IdxLength > 0)\n                animcache2 = new AnimIdx[m_FileIndex2.IdxLength / 12];\n            if (m_FileIndex3.IdxLength > 0)\n                animcache3 = new AnimIdx[m_FileIndex3.IdxLength / 12];\n            if (m_FileIndex4.IdxLength > 0)\n                animcache4 = new AnimIdx[m_FileIndex4.IdxLength / 12];\n            if (m_FileIndex5.IdxLength > 0)\n                animcache5 = new AnimIdx[m_FileIndex5.IdxLength / 12];\n        }\n\n        /// <summary>\n        /// Rereads AnimX files\n        /// </summary>\n        public static void Reload()\n        {\n            m_FileIndex = new FileIndex(\"Anim.idx\", \"Anim.mul\", 6);\n            m_FileIndex2 = new FileIndex(\"Anim2.idx\", \"Anim2.mul\", -1);\n            m_FileIndex3 = new FileIndex(\"Anim3.idx\", \"Anim3.mul\", -1);\n            m_FileIndex4 = new FileIndex(\"Anim4.idx\", \"Anim4.mul\", -1);\n            m_FileIndex5 = new FileIndex(\"Anim5.idx\", \"Anim5.mul\", -1);\n            if (m_FileIndex.IdxLength > 0)\n                animcache = new AnimIdx[m_FileIndex.IdxLength / 12];\n            if (m_FileIndex2.IdxLength > 0)\n                animcache = new AnimIdx[m_FileIndex2.IdxLength / 12];\n            if (m_FileIndex3.IdxLength > 0)\n                animcache = new AnimIdx[m_FileIndex3.IdxLength / 12];\n            if (m_FileIndex4.IdxLength > 0)\n                animcache = new AnimIdx[m_FileIndex4.IdxLength / 12];\n            if (m_FileIndex5.IdxLength > 0)\n                animcache = new AnimIdx[m_FileIndex5.IdxLength / 12];\n        }\n\n        private static void GetFileIndex(int body, int fileType, int action, int direction, out FileIndex fileIndex,\n            out int index)\n        {\n            switch (fileType)\n            {\n                default:\n                case 1:\n                    fileIndex = m_FileIndex;\n                    if (body < 200)\n                        index = body * 110;\n                    else if (body < 400)\n                        index = 22000 + ((body - 200) * 65);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n                    break;\n                case 2:\n                    fileIndex = m_FileIndex2;\n                    if (body < 200)\n                        index = body * 110;\n                    else\n                        index = 22000 + ((body - 200) * 65);\n                    break;\n                case 3:\n                    fileIndex = m_FileIndex3;\n                    if (body < 300)\n                        index = body * 65;\n                    else if (body < 400)\n                        index = 33000 + ((body - 300) * 110);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n                    break;\n                case 4:\n                    fileIndex = m_FileIndex4;\n                    if (body < 200)\n                        index = body * 110;\n                    else if (body < 400)\n                        index = 22000 + ((body - 200) * 65);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n                    break;\n                case 5:\n                    fileIndex = m_FileIndex5;\n                    if ((body < 200) && (body != 34)) // looks strange, though it works.\n                        index = body * 110;\n                    else if (body < 400)\n                        index = 22000 + ((body - 200) * 65);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n                    break;\n            }\n\n            index += action * 5;\n\n            if (direction <= 4)\n                index += direction;\n            else\n                index += direction - (direction - 4) * 2;\n        }\n\n        private static AnimIdx[] GetCache(int filetype)\n        {\n            switch (filetype)\n            {\n                case 1:\n                    return animcache;\n                case 2:\n                    return animcache2;\n                case 3:\n                    return animcache3;\n                case 4:\n                    return animcache4;\n                case 5:\n                    return animcache5;\n                default:\n                    return animcache;\n            }\n        }\n\n        public static AnimIdx GetAnimation(int filetype, int body, int action, int dir)\n        {\n            AnimIdx[] cache = GetCache(filetype);\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, filetype, action, dir, out fileIndex, out index);\n\n            if (cache != null)\n            {\n                if (cache[index] != null)\n                    return cache[index];\n            }\n\n            return cache[index] = new AnimIdx(index, fileIndex, filetype);\n        }\n\n        public static bool IsActionDefinied(int filetype, int body, int action)\n        {\n            AnimIdx[] cache = GetCache(filetype);\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, filetype, action, 0, out fileIndex, out index);\n\n            if (cache != null)\n            {\n                if (cache[index] != null)\n                {\n                    if ((cache[index].Frames != null) && (cache[index].Frames.Count > 0))\n                        return true;\n                    else\n                        return false;\n                }\n            }\n\n            int AnimCount = Animations.GetAnimLength(body, filetype);\n            if (AnimCount < action)\n                return false;\n\n            int length, extra;\n            bool patched;\n            bool valid = fileIndex.Valid(index, out length, out extra, out patched);\n            if ((!valid) || (length < 1))\n                return false;\n            return true;\n        }\n\n        public static void LoadFromVD(int filetype, int body, BinaryReader bin)\n        {\n            AnimIdx[] cache = GetCache(filetype);\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, filetype, 0, 0, out fileIndex, out index);\n            int animlength = Animations.GetAnimLength(body, filetype) * 5;\n            Entry3D[] entries = new Entry3D[animlength];\n\n            for (int i = 0; i < animlength; ++i)\n            {\n                entries[i].lookup = bin.ReadInt32();\n                entries[i].length = bin.ReadInt32();\n                entries[i].extra = bin.ReadInt32();\n            }\n\n            foreach (Entry3D entry in entries)\n            {\n                if ((entry.lookup > 0) && (entry.lookup < bin.BaseStream.Length) && (entry.length > 0))\n                {\n                    bin.BaseStream.Seek(entry.lookup, SeekOrigin.Begin);\n                    cache[index] = new AnimIdx(bin, entry.extra);\n                }\n\n                ++index;\n            }\n        }\n\n        public static void ExportToVD(int filetype, int body, string file)\n        {\n            AnimIdx[] cache = GetCache(filetype);\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, filetype, 0, 0, out fileIndex, out index);\n            using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    bin.Write((short) 6);\n                    int animlength = Animations.GetAnimLength(body, filetype);\n                    int currtype = animlength == 22 ? 0 : animlength == 13 ? 1 : 2;\n                    bin.Write((short) currtype);\n                    long indexpos = bin.BaseStream.Position;\n                    long animpos = bin.BaseStream.Position + 12 * animlength * 5;\n                    for (int i = index; i < index + animlength * 5; i++)\n                    {\n                        AnimIdx anim;\n                        if (cache != null)\n                        {\n                            if (cache[i] != null)\n                                anim = cache[i];\n                            else\n                                anim = cache[i] = new AnimIdx(i, fileIndex, filetype);\n                        }\n                        else\n                            anim = cache[i] = new AnimIdx(i, fileIndex, filetype);\n\n                        if (anim == null)\n                        {\n                            bin.BaseStream.Seek(indexpos, SeekOrigin.Begin);\n                            bin.Write((int) -1);\n                            bin.Write((int) -1);\n                            bin.Write((int) -1);\n                            indexpos = bin.BaseStream.Position;\n                        }\n                        else\n                            anim.ExportToVD(bin, ref indexpos, ref animpos);\n                    }\n                }\n            }\n        }\n\n        public static void Save(int filetype, string path)\n        {\n            string filename;\n            AnimIdx[] cache;\n            FileIndex fileindex;\n            switch (filetype)\n            {\n                case 1:\n                    filename = \"anim\";\n                    cache = animcache;\n                    fileindex = m_FileIndex;\n                    break;\n                case 2:\n                    filename = \"anim2\";\n                    cache = animcache2;\n                    fileindex = m_FileIndex2;\n                    break;\n                case 3:\n                    filename = \"anim3\";\n                    cache = animcache3;\n                    fileindex = m_FileIndex3;\n                    break;\n                case 4:\n                    filename = \"anim4\";\n                    cache = animcache4;\n                    fileindex = m_FileIndex4;\n                    break;\n                case 5:\n                    filename = \"anim5\";\n                    cache = animcache5;\n                    fileindex = m_FileIndex5;\n                    break;\n                default:\n                    filename = \"anim\";\n                    cache = animcache;\n                    fileindex = m_FileIndex;\n                    break;\n            }\n\n            string idx = Path.Combine(path, filename + \".idx\");\n            string mul = Path.Combine(path, filename + \".mul\");\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter binidx = new BinaryWriter(fsidx),\n                    binmul = new BinaryWriter(fsmul))\n                {\n                    for (int idxc = 0; idxc < cache.Length; ++idxc)\n                    {\n                        AnimIdx anim;\n                        if (cache != null)\n                        {\n                            if (cache[idxc] != null)\n                                anim = cache[idxc];\n                            else\n                                anim = cache[idxc] = new AnimIdx(idxc, fileindex, filetype);\n                        }\n                        else\n                            anim = cache[idxc] = new AnimIdx(idxc, fileindex, filetype);\n\n                        if (anim == null)\n                        {\n                            binidx.Write((int) -1);\n                            binidx.Write((int) -1);\n                            binidx.Write((int) -1);\n                        }\n                        else\n                            anim.Save(binmul, binidx);\n                    }\n                }\n            }\n        }\n    }\n\n    public sealed class AnimIdx\n    {\n        public int idxextra;\n        public ushort[] Palette { get; private set; }\n        public List<FrameEdit> Frames { get; private set; }\n\n        public AnimIdx(int index, FileIndex fileIndex, int filetype)\n        {\n            Palette = new ushort[0x100];\n            int length, extra;\n            bool patched;\n            Stream stream = fileIndex.Seek(index, out length, out extra, out patched);\n            if ((stream == null) || (length < 1))\n                return;\n\n            idxextra = extra;\n            using (BinaryReader bin = new BinaryReader(stream))\n            {\n                for (int i = 0; i < 0x100; ++i)\n                    Palette[i] = (ushort) (bin.ReadUInt16() ^ 0x8000);\n\n                int start = (int) bin.BaseStream.Position;\n                int frameCount = bin.ReadInt32();\n\n                int[] lookups = new int[frameCount];\n\n                for (int i = 0; i < frameCount; ++i)\n                    lookups[i] = start + bin.ReadInt32();\n\n                Frames = new List<FrameEdit>();\n\n                for (int i = 0; i < frameCount; ++i)\n                {\n                    stream.Seek(lookups[i], SeekOrigin.Begin);\n                    Frames.Add(new FrameEdit(bin));\n                }\n            }\n\n            stream.Close();\n        }\n\n        public AnimIdx(BinaryReader bin, int extra)\n        {\n            Palette = new ushort[0x100];\n            idxextra = extra;\n            for (int i = 0; i < 0x100; ++i)\n                Palette[i] = (ushort) (bin.ReadUInt16() ^ 0x8000);\n\n            int start = (int) bin.BaseStream.Position;\n            int frameCount = bin.ReadInt32();\n\n            int[] lookups = new int[frameCount];\n\n            for (int i = 0; i < frameCount; ++i)\n                lookups[i] = start + bin.ReadInt32();\n\n            Frames = new List<FrameEdit>();\n\n            for (int i = 0; i < frameCount; ++i)\n            {\n                bin.BaseStream.Seek(lookups[i], SeekOrigin.Begin);\n                Frames.Add(new FrameEdit(bin));\n            }\n        }\n\n        public unsafe Bitmap[] GetFrames()\n        {\n            if ((Frames == null) || (Frames.Count == 0))\n                return null;\n            Bitmap[] bits = new Bitmap[Frames.Count];\n            for (int i = 0; i < bits.Length; ++i)\n            {\n                FrameEdit frame = Frames[i];\n                int width = frame.width;\n                int height = frame.height;\n                if (height == 0 || width == 0)\n                    continue;\n                Bitmap bmp = new Bitmap(width, height, PixelFormat.Format16bppArgb1555);\n                BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,\n                    PixelFormat.Format16bppArgb1555);\n                ushort* line = (ushort*) bd.Scan0;\n                int delta = bd.Stride >> 1;\n\n                int xBase = frame.Center.X - 0x200;\n                int yBase = frame.Center.Y + height - 0x200;\n\n                line += xBase;\n                line += yBase * delta;\n                for (int j = 0; j < frame.RawData.Length; ++j)\n                {\n                    FrameEdit.Raw raw = frame.RawData[j];\n\n                    ushort* cur = line + (((raw.offy) * delta) + ((raw.offx) & 0x3FF));\n                    ushort* end = cur + (raw.run);\n\n                    int ii = 0;\n                    while (cur < end)\n                    {\n                        *cur++ = Palette[raw.data[ii++]];\n                    }\n                }\n\n                bmp.UnlockBits(bd);\n                bits[i] = bmp;\n            }\n\n            return bits;\n        }\n\n        public void AddFrame(Bitmap bit)\n        {\n            if (Frames == null)\n                Frames = new List<FrameEdit>();\n            Frames.Add(new FrameEdit(bit, Palette, 0, 0));\n        }\n\n        public void ReplaceFrame(Bitmap bit, int index)\n        {\n            if ((Frames == null) || (Frames.Count == 0))\n                return;\n            if (index > Frames.Count)\n                return;\n            Frames[index] = new FrameEdit(bit, Palette, ((FrameEdit) Frames[index]).Center.X,\n                ((FrameEdit) Frames[index]).Center.Y);\n        }\n\n        public void RemoveFrame(int index)\n        {\n            if (Frames == null)\n                return;\n            if (index > Frames.Count)\n                return;\n            Frames.RemoveAt(index);\n        }\n\n        public void ClearFrames()\n        {\n            if (Frames == null)\n                return;\n            Frames.Clear();\n        }\n\n#if false\n\t\t//Soulblighter Modification\n\t\tpublic void GetGifPalette(Bitmap bit)\n\t\t{\n\t\t\tusing (MemoryStream imageStreamSource = new MemoryStream())\n\t\t\t{\n\t\t\t\tSystem.Drawing.ImageConverter ic = new System.Drawing.ImageConverter();\n\t\t\t\tbyte[] btImage = (byte[])ic.ConvertTo(bit, typeof(byte[]));\n\t\t\t\timageStreamSource.Write(btImage, 0, btImage.Length);\n\t\t\t\tGifBitmapDecoder decoder =\n new GifBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);\n\t\t\t\tBitmapPalette pal = decoder.Palette;\n\t\t\t\tint i;\n\t\t\t\tfor (i = 0; i < 0x100; i++)\n\t\t\t\t{\n\t\t\t\t\tthis.Palette[i] = 0;\n\t\t\t\t}\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile (i < 0x100)//&& i < pal.Colors.Count)\n\t\t\t\t\t{\n\n\t\t\t\t\t\tint Red = pal.Colors[i].R / 8;\n\t\t\t\t\t\tint Green = pal.Colors[i].G / 8;\n\t\t\t\t\t\tint Blue = pal.Colors[i].B / 8;\n\t\t\t\t\t\tint contaFinal = (((0x400 * Red) + (0x20 * Green)) + Blue) + 0x8000;\n\t\t\t\t\t\tif (contaFinal == 0x8000)\n\t\t\t\t\t\t\tcontaFinal = 0x8001;\n\t\t\t\t\t\tthis.Palette[i] = (ushort)contaFinal;\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (System.IndexOutOfRangeException)\n\t\t\t\t{ }\n\t\t\t\tcatch (System.ArgumentOutOfRangeException)\n\t\t\t\t{ }\n\t\t\t\tfor (i = 0; i < 0x100; i++)\n\t\t\t\t{\n\t\t\t\t\tif (this.Palette[i] < 0x8000)\n\t\t\t\t\t\tthis.Palette[i] = 0x8000;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\n        public unsafe void GetImagePalette(Bitmap bit)\n        {\n            int count = 0;\n            Bitmap bmp = new Bitmap(bit);\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly,\n                PixelFormat.Format16bppArgb1555);\n            ushort* line = (ushort*) bd.Scan0;\n            int delta = bd.Stride >> 1;\n            ushort* cur = line;\n            int i = 0;\n            while (i < 0x100)\n            {\n                this.Palette[i] = 0;\n                i++;\n            }\n\n            int y = 0;\n            while (y < bmp.Height)\n            {\n                cur = line;\n                for (int x = 0; x < bmp.Width; x++)\n                {\n                    ushort c = cur[x];\n                    if (c != 0)\n                    {\n                        bool found = false;\n                        i = 0;\n                        while (i < this.Palette.Length)\n                        {\n                            if (this.Palette[i] == c)\n                            {\n                                found = true;\n                                break;\n                            }\n\n                            i++;\n                        }\n\n                        if (!found)\n                            this.Palette[count++] = c;\n                        if (count >= 0x100)\n                            break;\n                    }\n                }\n\n                for (i = 0; i < 0x100; i++)\n                {\n                    if (this.Palette[i] < 0x8000)\n                        this.Palette[i] = 0x8000;\n                }\n\n                if (count >= 0x100)\n                    break;\n                y++;\n                line += delta;\n            }\n        }\n\n        public void PaletteConversor(int seletor)\n        {\n            int i;\n            for (i = 0; i < 0x100; i++)\n            {\n                int BlueTemp = (this.Palette[i] - 0x8000) / 0x20;\n                BlueTemp *= 0x20;\n                BlueTemp = (this.Palette[i] - 0x8000) - BlueTemp;\n                int GreenTemp = (this.Palette[i] - 0x8000) / 0x400;\n                GreenTemp *= 0x400;\n                GreenTemp = ((this.Palette[i] - 0x8000) - GreenTemp) - BlueTemp;\n                GreenTemp /= 0x20;\n                int RedTemp = (this.Palette[i] - 0x8000) / 0x400;\n                int contaFinal = 0;\n                switch (seletor)\n                {\n                    case 1:\n                        contaFinal = (((0x400 * RedTemp) + (0x20 * GreenTemp)) + BlueTemp) + 0x8000;\n                        break;\n                    case 2:\n                        contaFinal = (((0x400 * RedTemp) + (0x20 * BlueTemp)) + GreenTemp) + 0x8000;\n                        break;\n                    case 3:\n                        contaFinal = (((0x400 * GreenTemp) + (0x20 * RedTemp)) + BlueTemp) + 0x8000;\n                        break;\n                    case 4:\n                        contaFinal = (((0x400 * GreenTemp) + (0x20 * BlueTemp)) + RedTemp) + 0x8000;\n                        break;\n                    case 5:\n                        contaFinal = (((0x400 * BlueTemp) + (0x20 * GreenTemp)) + RedTemp) + 0x8000;\n                        break;\n                    case 6:\n                        contaFinal = (((0x400 * BlueTemp) + (0x20 * RedTemp)) + GreenTemp) + 0x8000;\n                        break;\n                }\n\n                if (contaFinal == 0x8000)\n                    contaFinal = 0x8001;\n                this.Palette[i] = (ushort) contaFinal;\n            }\n\n            for (i = 0; i < 0x100; i++)\n            {\n                if (this.Palette[i] < 0x8000)\n                    this.Palette[i] = 0x8000;\n            }\n        }\n\n        public void PaletteReductor(int Redp, int Greenp, int Bluep)\n        {\n            int i;\n            Redp /= 8;\n            Greenp /= 8;\n            Bluep /= 8;\n            for (i = 0; i < 0x100; i++)\n            {\n                int BlueTemp = (this.Palette[i] - 0x8000) / 0x20;\n                BlueTemp *= 0x20;\n                BlueTemp = (this.Palette[i] - 0x8000) - BlueTemp;\n                int GreenTemp = (this.Palette[i] - 0x8000) / 0x400;\n                GreenTemp *= 0x400;\n                GreenTemp = ((this.Palette[i] - 0x8000) - GreenTemp) - BlueTemp;\n                GreenTemp /= 0x20;\n                int RedTemp = (this.Palette[i] - 0x8000) / 0x400;\n                RedTemp += Redp;\n                GreenTemp += Greenp;\n                BlueTemp += Bluep;\n                if (RedTemp < 0)\n                    RedTemp = 0;\n                if (RedTemp > 0x1f)\n                    RedTemp = 0x1f;\n                if (GreenTemp < 0)\n                    GreenTemp = 0;\n                if (GreenTemp > 0x1f)\n                    GreenTemp = 0x1f;\n                if (BlueTemp < 0)\n                    BlueTemp = 0;\n                if (BlueTemp > 0x1f)\n                    BlueTemp = 0x1f;\n                int contaFinal = (((0x400 * RedTemp) + (0x20 * GreenTemp)) + BlueTemp) + 0x8000;\n                if (contaFinal == 0x8000)\n                    contaFinal = 0x8001;\n                this.Palette[i] = (ushort) contaFinal;\n            }\n\n            for (i = 0; i < 0x100; i++)\n            {\n                if (this.Palette[i] < 0x8000)\n                    this.Palette[i] = 0x8000;\n            }\n        }\n        //End of Soulblighter Modification\n\n\n        public unsafe void ExportPalette(string filename, int type)\n        {\n            switch (type)\n            {\n                case 0:\n                    using (StreamWriter Tex =\n                        new StreamWriter(new FileStream(filename, FileMode.Create, FileAccess.ReadWrite)))\n                    {\n                        for (int i = 0; i < 0x100; ++i)\n                        {\n                            Tex.WriteLine(Palette[i]);\n                        }\n                    }\n\n                    break;\n                case 1:\n                {\n                    Bitmap bmp = new Bitmap(0x100, 20, PixelFormat.Format16bppArgb1555);\n                    BitmapData bd = bmp.LockBits(new Rectangle(0, 0, 0x100, 20), ImageLockMode.WriteOnly,\n                        PixelFormat.Format16bppArgb1555);\n                    ushort* line = (ushort*) bd.Scan0;\n                    int delta = bd.Stride >> 1;\n                    for (int y = 0; y < bd.Height; ++y, line += delta)\n                    {\n                        ushort* cur = line;\n                        for (int i = 0; i < 0x100; ++i)\n                        {\n                            *cur++ = Palette[i];\n                        }\n                    }\n\n                    bmp.UnlockBits(bd);\n                    Bitmap b = new Bitmap(bmp);\n                    b.Save(filename, ImageFormat.Bmp);\n                    b.Dispose();\n                    bmp.Dispose();\n                    break;\n                }\n\n                case 2:\n                {\n                    Bitmap bmp = new Bitmap(0x100, 20, PixelFormat.Format16bppArgb1555);\n                    BitmapData bd = bmp.LockBits(new Rectangle(0, 0, 0x100, 20), ImageLockMode.WriteOnly,\n                        PixelFormat.Format16bppArgb1555);\n                    ushort* line = (ushort*) bd.Scan0;\n                    int delta = bd.Stride >> 1;\n                    for (int y = 0; y < bd.Height; ++y, line += delta)\n                    {\n                        ushort* cur = line;\n                        for (int i = 0; i < 0x100; ++i)\n                        {\n                            *cur++ = Palette[i];\n                        }\n                    }\n\n                    bmp.UnlockBits(bd);\n                    Bitmap b = new Bitmap(bmp);\n                    b.Save(filename, ImageFormat.Tiff);\n                    b.Dispose();\n                    bmp.Dispose();\n                    break;\n                }\n            }\n        }\n\n        public void ReplacePalette(ushort[] palette)\n        {\n            Palette = palette;\n        }\n\n        public void Save(BinaryWriter bin, BinaryWriter idx)\n        {\n            if ((Frames == null) || (Frames.Count == 0))\n            {\n                idx.Write((int) -1);\n                idx.Write((int) -1);\n                idx.Write((int) -1);\n                return;\n            }\n\n            long start = bin.BaseStream.Position;\n            idx.Write((int) start);\n\n            for (int i = 0; i < 0x100; ++i)\n                bin.Write((ushort) (Palette[i] ^ 0x8000));\n            long startpos = bin.BaseStream.Position;\n            bin.Write((int) Frames.Count);\n            long seek = bin.BaseStream.Position;\n            long curr = bin.BaseStream.Position + 4 * Frames.Count;\n            foreach (FrameEdit frame in Frames)\n            {\n                bin.BaseStream.Seek(seek, SeekOrigin.Begin);\n                bin.Write((int) (curr - startpos));\n                seek = bin.BaseStream.Position;\n                bin.BaseStream.Seek(curr, SeekOrigin.Begin);\n                frame.Save(bin);\n                curr = bin.BaseStream.Position;\n            }\n\n            start = bin.BaseStream.Position - start;\n            idx.Write((int) start);\n            idx.Write((int) idxextra);\n        }\n\n        public void ExportToVD(BinaryWriter bin, ref long indexpos, ref long animpos)\n        {\n            bin.BaseStream.Seek(indexpos, SeekOrigin.Begin);\n            if ((Frames == null) || (Frames.Count == 0))\n            {\n                bin.Write((int) -1);\n                bin.Write((int) -1);\n                bin.Write((int) -1);\n                indexpos = bin.BaseStream.Position;\n                return;\n            }\n\n            bin.Write((int) animpos);\n            indexpos = bin.BaseStream.Position;\n            bin.BaseStream.Seek(animpos, SeekOrigin.Begin);\n\n            for (int i = 0; i < 0x100; ++i)\n                bin.Write((ushort) (Palette[i] ^ 0x8000));\n            long startpos = (int) bin.BaseStream.Position;\n            bin.Write((int) Frames.Count);\n            long seek = (int) bin.BaseStream.Position;\n            long curr = bin.BaseStream.Position + 4 * Frames.Count;\n            foreach (FrameEdit frame in Frames)\n            {\n                bin.BaseStream.Seek(seek, SeekOrigin.Begin);\n                bin.Write((int) (curr - startpos));\n                seek = bin.BaseStream.Position;\n                bin.BaseStream.Seek(curr, SeekOrigin.Begin);\n                frame.Save(bin);\n                curr = bin.BaseStream.Position;\n            }\n\n            long length = bin.BaseStream.Position - animpos;\n            animpos = bin.BaseStream.Position;\n            bin.BaseStream.Seek(indexpos, SeekOrigin.Begin);\n            bin.Write((int) length);\n            bin.Write((int) idxextra);\n            indexpos = bin.BaseStream.Position;\n        }\n    }\n\n    public sealed class FrameEdit\n    {\n        private const int DoubleXor = (0x200 << 22) | (0x200 << 12);\n\n        public struct Raw\n        {\n            public int run;\n            public int offx;\n            public int offy;\n            public byte[] data;\n        }\n\n        public Raw[] RawData { get; private set; }\n        public Point Center { get; set; }\n        public int width;\n        public int height;\n\n        public FrameEdit(BinaryReader bin)\n        {\n            int xCenter = bin.ReadInt16();\n            int yCenter = bin.ReadInt16();\n\n            width = bin.ReadUInt16();\n            height = bin.ReadUInt16();\n            if (height == 0 || width == 0)\n                return;\n            int header;\n\n            List<Raw> tmp = new List<Raw>();\n            while ((header = bin.ReadInt32()) != 0x7FFF7FFF)\n            {\n                Raw raw = new Raw();\n                header ^= DoubleXor;\n                raw.run = (header & 0xFFF);\n                raw.offy = ((header >> 12) & 0x3FF);\n                raw.offx = ((header >> 22) & 0x3FF);\n\n                int i = 0;\n                raw.data = new byte[raw.run];\n                while (i < raw.run)\n                {\n                    raw.data[i++] = bin.ReadByte();\n                }\n\n                tmp.Add(raw);\n            }\n\n            RawData = tmp.ToArray();\n            Center = new Point(xCenter, yCenter);\n        }\n\n        public unsafe FrameEdit(Bitmap bit, ushort[] palette, int centerx, int centery)\n        {\n            Center = new Point(centerx, centery);\n            width = bit.Width;\n            height = bit.Height;\n            BitmapData bd = bit.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly,\n                PixelFormat.Format16bppArgb1555);\n            ushort* line = (ushort*) bd.Scan0;\n            int delta = bd.Stride >> 1;\n            List<Raw> tmp = new List<Raw>();\n\n            int X = 0;\n            for (int Y = 0; Y < bit.Height; ++Y, line += delta)\n            {\n                ushort* cur = line;\n                int i = 0;\n                int j = 0;\n                X = 0;\n                while (i < bit.Width)\n                {\n                    i = X;\n                    for (i = X; i <= bit.Width; ++i)\n                    {\n                        //first pixel set\n                        if (i < bit.Width)\n                        {\n                            if (cur[i] != 0)\n                                break;\n                        }\n                    }\n\n                    if (i < bit.Width)\n                    {\n                        for (j = (i + 1); j < bit.Width; ++j)\n                        {\n                            //next non set pixel\n                            if (cur[j] == 0)\n                                break;\n                        }\n\n                        Raw raw = new Raw();\n                        raw.run = j - i;\n                        raw.offx = j - raw.run - centerx;\n                        raw.offx += 512;\n                        raw.offy = Y - centery - bit.Height;\n                        raw.offy += 512;\n\n                        int r = 0;\n                        raw.data = new byte[raw.run];\n                        while (r < raw.run)\n                        {\n                            ushort col = (ushort) (cur[r + i]);\n                            raw.data[r++] = GetPaletteIndex(palette, col);\n                        }\n\n                        tmp.Add(raw);\n                        X = j + 1;\n                        i = X;\n                    }\n                }\n            }\n\n            RawData = tmp.ToArray();\n            bit.UnlockBits(bd);\n        }\n\n        public void ChangeCenter(int x, int y)\n        {\n            for (int i = 0; i < RawData.Length; i++)\n            {\n                RawData[i].offx += Center.X;\n                RawData[i].offx -= x;\n                RawData[i].offy += Center.Y;\n                RawData[i].offy -= y;\n            }\n\n            Center = new Point(x, y);\n        }\n\n        private static byte GetPaletteIndex(ushort[] palette, ushort col)\n        {\n            for (int i = 0; i < palette.Length; i++)\n            {\n                if (palette[i] == col)\n                    return (byte) i;\n            }\n\n            return (byte) 0;\n        }\n\n        public void Save(BinaryWriter bin)\n        {\n            bin.Write((short) Center.X);\n            bin.Write((short) Center.Y);\n            bin.Write((ushort) width);\n            bin.Write((ushort) height);\n            if (RawData != null)\n            {\n                for (int j = 0; j < RawData.Length; j++)\n                {\n                    int newHeader = RawData[j].run | (RawData[j].offy << 12) | (RawData[j].offx << 22);\n                    newHeader ^= DoubleXor;\n                    bin.Write((int) newHeader);\n                    foreach (byte b in RawData[j].data)\n                        bin.Write(b);\n                }\n            }\n\n            bin.Write((int) 0x7FFF7FFF);\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Animations.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\nnamespace Ultima\n{\n    /// <summary>\n    /// Contains translation tables used for mapping body values to file subsets.\n    /// <seealso cref=\"Animations\" />\n    /// </summary>\n    public sealed class BodyConverter\n    {\n        public static int[] Table1 { get; private set; }\n        public static int[] Table2 { get; private set; }\n        public static int[] Table3 { get; private set; }\n        public static int[] Table4 { get; private set; }\n\n        private BodyConverter()\n        {\n        }\n\n        static BodyConverter()\n        {\n            Initialize();\n        }\n\n        /// <summary>\n        /// Fills bodyconv.def Tables\n        /// </summary>\n        public static void Initialize()\n        {\n            string path = Files.GetFilePath(\"bodyconv.def\");\n\n            if (path == null)\n                return;\n\n            List<int> list1 = new List<int>(),\n                list2 = new List<int>(),\n                list3 = new List<int>(),\n                list4 = new List<int>();\n            int max1 = 0, max2 = 0, max3 = 0, max4 = 0;\n\n            using (StreamReader ip = new StreamReader(path))\n            {\n                string line;\n\n                while ((line = ip.ReadLine()) != null)\n                {\n                    if ((line = line.Trim()).Length == 0 || line.StartsWith(\"#\"))\n                        continue;\n\n                    try\n                    {\n                        string[] split = line.Split('\\t');\n\n                        int original = System.Convert.ToInt32(split[0]);\n                        int anim2 = System.Convert.ToInt32(split[1]);\n                        int anim3;\n                        int anim4;\n                        int anim5;\n\n                        try\n                        {\n                            anim3 = System.Convert.ToInt32(split[2]);\n                        }\n                        catch\n                        {\n                            anim3 = -1;\n                        }\n\n                        try\n                        {\n                            anim4 = System.Convert.ToInt32(split[3]);\n                        }\n                        catch\n                        {\n                            anim4 = -1;\n                        }\n\n                        try\n                        {\n                            anim5 = System.Convert.ToInt32(split[4]);\n                        }\n                        catch\n                        {\n                            anim5 = -1;\n                        }\n\n                        if (anim2 != -1)\n                        {\n                            if (anim2 == 68)\n                                anim2 = 122;\n\n                            if (original > max1)\n                                max1 = original;\n\n                            list1.Add(original);\n                            list1.Add(anim2);\n                        }\n\n                        if (anim3 != -1)\n                        {\n                            if (original > max2)\n                                max2 = original;\n\n                            list2.Add(original);\n                            list2.Add(anim3);\n                        }\n\n                        if (anim4 != -1)\n                        {\n                            if (original > max3)\n                                max3 = original;\n\n                            list3.Add(original);\n                            list3.Add(anim4);\n                        }\n\n                        if (anim5 != -1)\n                        {\n                            if (original > max4)\n                                max4 = original;\n\n                            list4.Add(original);\n                            list4.Add(anim5);\n                        }\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n\n            Table1 = new int[max1 + 1];\n\n            for (int i = 0; i < Table1.Length; ++i)\n                Table1[i] = -1;\n\n            for (int i = 0; i < list1.Count; i += 2)\n                Table1[list1[i]] = list1[i + 1];\n\n            Table2 = new int[max2 + 1];\n\n            for (int i = 0; i < Table2.Length; ++i)\n                Table2[i] = -1;\n\n            for (int i = 0; i < list2.Count; i += 2)\n                Table2[list2[i]] = list2[i + 1];\n\n            Table3 = new int[max3 + 1];\n\n            for (int i = 0; i < Table3.Length; ++i)\n                Table3[i] = -1;\n\n            for (int i = 0; i < list3.Count; i += 2)\n                Table3[list3[i]] = list3[i + 1];\n\n            Table4 = new int[max4 + 1];\n\n            for (int i = 0; i < Table4.Length; ++i)\n                Table4[i] = -1;\n\n            for (int i = 0; i < list4.Count; i += 2)\n                Table4[list4[i]] = list4[i + 1];\n        }\n\n        /// <summary>\n        /// Checks to see if <paramref name=\"body\" /> is contained within the mapping table.\n        /// </summary>\n        /// <returns>True if it is, false if not.</returns>\n        public static bool Contains(int body)\n        {\n            if (Table1 != null && body >= 0 && body < Table1.Length && Table1[body] != -1)\n                return true;\n\n            if (Table2 != null && body >= 0 && body < Table2.Length && Table2[body] != -1)\n                return true;\n\n            if (Table3 != null && body >= 0 && body < Table3.Length && Table3[body] != -1)\n                return true;\n\n            if (Table4 != null && body >= 0 && body < Table4.Length && Table4[body] != -1)\n                return true;\n\n            return false;\n        }\n\n        /// <summary>\n        /// Attempts to convert <paramref name=\"body\" /> to a body index relative to a file subset, specified by the return value.\n        /// </summary>\n        /// <returns>A value indicating a file subset:\n        /// <list type=\"table\">\n        /// <listheader>\n        /// <term>Return Value</term>\n        /// <description>File Subset</description>\n        /// </listheader>\n        /// <item>\n        /// <term>1</term>\n        /// <description>Anim.mul, Anim.idx (Standard)</description>\n        /// </item>\n        /// <item>\n        /// <term>2</term>\n        /// <description>Anim2.mul, Anim2.idx (LBR)</description>\n        /// </item>\n        /// <item>\n        /// <term>3</term>\n        /// <description>Anim3.mul, Anim3.idx (AOS)</description>\n        /// </item>\n        /// <item>\n        /// <term>4</term>\n        /// <description>Anim4.mul, Anim4.idx (SE)</description>\n        /// </item>\n        /// <item>\n        /// <term>5</term>\n        /// <description>Anim5.mul, Anim5.idx (ML)</description>\n        /// </item>\n        /// </list>\n        /// </returns>\n        public static int Convert(ref int body)\n        {\n            if (Table1 != null && body >= 0 && body < Table1.Length)\n            {\n                int val = Table1[body];\n\n                if (val != -1)\n                {\n                    body = val;\n                    return 2;\n                }\n            }\n\n            if (Table2 != null && body >= 0 && body < Table2.Length)\n            {\n                int val = Table2[body];\n\n                if (val != -1)\n                {\n                    body = val;\n                    return 3;\n                }\n            }\n\n            if (Table3 != null && body >= 0 && body < Table3.Length)\n            {\n                int val = Table3[body];\n\n                if (val != -1)\n                {\n                    body = val;\n                    return 4;\n                }\n            }\n\n            if (Table4 != null && body >= 0 && body < Table4.Length)\n            {\n                int val = Table4[body];\n\n                if (val != -1)\n                {\n                    body = val;\n                    return 5;\n                }\n            }\n\n            return 1;\n        }\n\n        /// <summary>\n        /// Converts backward\n        /// </summary>\n        /// <param name=\"FileType\"></param>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static int GetTrueBody(int FileType, int index)\n        {\n            switch (FileType)\n            {\n                default:\n                case 1:\n                    return index;\n                case 2:\n                    if (Table1 != null && index >= 0)\n                    {\n                        for (int i = 0; i < Table1.Length; ++i)\n                        {\n                            if (Table1[i] == index)\n                                return i;\n                        }\n                    }\n\n                    break;\n                case 3:\n                    if (Table2 != null && index >= 0)\n                    {\n                        for (int i = 0; i < Table2.Length; ++i)\n                        {\n                            if (Table2[i] == index)\n                                return i;\n                        }\n                    }\n\n                    break;\n                case 4:\n                    if (Table3 != null && index >= 0)\n                    {\n                        for (int i = 0; i < Table3.Length; ++i)\n                        {\n                            if (Table3[i] == index)\n                                return i;\n                        }\n                    }\n\n                    break;\n                case 5:\n                    if (Table4 != null && index >= 0)\n                    {\n                        for (int i = 0; i < Table4.Length; ++i)\n                        {\n                            if (Table4[i] == index)\n                                return i;\n                        }\n                    }\n\n                    break;\n            }\n\n            return -1;\n        }\n    }\n\n    public sealed class Animations\n    {\n        private static FileIndex m_FileIndex = new FileIndex(\"Anim.idx\", \"Anim.mul\", 0x40000, 6);\n        //public static FileIndex FileIndex{ get{ return m_FileIndex; } }\n\n        private static FileIndex m_FileIndex2 = new FileIndex(\"Anim2.idx\", \"Anim2.mul\", 0x10000, -1);\n        //public static FileIndex FileIndex2{ get{ return m_FileIndex2; } }\n\n        private static FileIndex m_FileIndex3 = new FileIndex(\"Anim3.idx\", \"Anim3.mul\", 0x20000, -1);\n        //public static FileIndex FileIndex3{ get{ return m_FileIndex3; } }\n\n        private static FileIndex m_FileIndex4 = new FileIndex(\"Anim4.idx\", \"Anim4.mul\", 0x20000, -1);\n        //public static FileIndex FileIndex4{ get{ return m_FileIndex4; } }\n\n        private static FileIndex m_FileIndex5 = new FileIndex(\"Anim5.idx\", \"Anim5.mul\", 0x20000, -1);\n        //public static FileIndex FileIndex5 { get { return m_FileIndex5; } }\n\n        private static byte[] m_StreamBuffer;\n        private static MemoryStream m_MemoryStream;\n\n        /// <summary>\n        /// Rereads AnimX files and bodyconv, body.def\n        /// </summary>\n        public static void Reload()\n        {\n            m_FileIndex = new FileIndex(\"Anim.idx\", \"Anim.mul\", 0x40000, 6);\n            m_FileIndex2 = new FileIndex(\"Anim2.idx\", \"Anim2.mul\", 0x10000, -1);\n            m_FileIndex3 = new FileIndex(\"Anim3.idx\", \"Anim3.mul\", 0x20000, -1);\n            m_FileIndex4 = new FileIndex(\"Anim4.idx\", \"Anim4.mul\", 0x20000, -1);\n            m_FileIndex5 = new FileIndex(\"Anim5.idx\", \"Anim5.mul\", 0x20000, -1);\n\n            BodyConverter.Initialize();\n            BodyTable.Initialize();\n        }\n\n        /// <summary>\n        /// Returns Framelist\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <param name=\"action\"></param>\n        /// <param name=\"direction\"></param>\n        /// <param name=\"hue\"></param>\n        /// <param name=\"preserveHue\">No Hue override <see cref=\"bodydev\"/></param>\n        /// <param name=\"FirstFrame\"></param>\n        /// <returns></returns>\n        public static Frame[] GetAnimation(int body, int action, int direction, ref int hue, bool preserveHue,\n            bool FirstFrame)\n        {\n            if (preserveHue)\n                Translate(ref body);\n            else\n                Translate(ref body, ref hue);\n\n            int fileType = BodyConverter.Convert(ref body);\n\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, action, direction, fileType, out fileIndex, out index);\n\n            int length, extra;\n            bool patched;\n            Stream stream = fileIndex.Seek(index, out length, out extra, out patched);\n\n            if (stream == null)\n                return null;\n            if (m_StreamBuffer == null || m_StreamBuffer.Length < length)\n                m_StreamBuffer = new byte[length];\n            stream.Read(m_StreamBuffer, 0, length);\n            m_MemoryStream = new MemoryStream(m_StreamBuffer, false);\n\n            bool flip = direction > 4;\n            Frame[] frames;\n            using (BinaryReader bin = new BinaryReader(m_MemoryStream))\n            {\n                ushort[] palette = new ushort[0x100];\n\n                for (int i = 0; i < 0x100; ++i)\n                    palette[i] = (ushort) (bin.ReadUInt16() ^ 0x8000);\n\n                int start = (int) bin.BaseStream.Position;\n                int frameCount = bin.ReadInt32();\n\n                int[] lookups = new int[frameCount];\n\n                for (int i = 0; i < frameCount; ++i)\n                    lookups[i] = start + bin.ReadInt32();\n\n                bool onlyHueGrayPixels = (hue & 0x8000) != 0;\n\n                hue = (hue & 0x3FFF) - 1;\n\n                Hue hueObject;\n\n                if (hue >= 0 && hue < Hues.List.Length)\n                    hueObject = Hues.List[hue];\n                else\n                    hueObject = null;\n\n                if (FirstFrame)\n                    frameCount = 1;\n                frames = new Frame[frameCount];\n\n                for (int i = 0; i < frameCount; ++i)\n                {\n                    bin.BaseStream.Seek(lookups[i], SeekOrigin.Begin);\n                    frames[i] = new Frame(palette, bin, flip);\n\n                    if (hueObject != null)\n                    {\n                        if (frames[i] != null)\n                        {\n                            if (frames[i].Bitmap != null)\n                                hueObject.ApplyTo(frames[i].Bitmap, onlyHueGrayPixels);\n                        }\n                    }\n                }\n\n                bin.Close();\n            }\n\n            m_MemoryStream.Close();\n            return frames;\n        }\n\n        public static Frame[] GetAnimation(int body, int action, int direction, int fileType)\n        {\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, action, direction, fileType, out fileIndex, out index);\n\n            int length, extra;\n            bool patched;\n\n            Stream stream = fileIndex.Seek(index, out length, out extra, out patched);\n\n            if (stream == null)\n                return null;\n\n\n            bool flip = direction > 4;\n\n            using (BinaryReader bin = new BinaryReader(stream))\n            {\n                ushort[] palette = new ushort[0x100];\n\n                for (int i = 0; i < 0x100; ++i)\n                    palette[i] = (ushort) (bin.ReadUInt16() ^ 0x8000);\n\n                int start = (int) bin.BaseStream.Position;\n                int frameCount = bin.ReadInt32();\n\n                int[] lookups = new int[frameCount];\n\n                for (int i = 0; i < frameCount; ++i)\n                    lookups[i] = start + bin.ReadInt32();\n\n                Frame[] frames = new Frame[frameCount];\n\n                for (int i = 0; i < frameCount; ++i)\n                {\n                    bin.BaseStream.Seek(lookups[i], SeekOrigin.Begin);\n                    frames[i] = new Frame(palette, bin, flip);\n                }\n\n                return frames;\n            }\n        }\n\n        private static int[] m_Table;\n\n        /// <summary>\n        /// Translates body (body.def)\n        /// </summary>\n        /// <param name=\"body\"></param>\n        public static void Translate(ref int body)\n        {\n            if (m_Table == null)\n                LoadTable();\n            if (body <= 0 || body >= m_Table.Length)\n            {\n                body = 0;\n                return;\n            }\n\n            body = m_Table[body] & 0x7FFF;\n        }\n\n        /// <summary>\n        /// Translates body and hue (body.def)\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <param name=\"hue\"></param>\n        public static void Translate(ref int body, ref int hue)\n        {\n            if (m_Table == null)\n                LoadTable();\n            if (body <= 0 || body >= m_Table.Length)\n            {\n                body = 0;\n                return;\n            }\n\n            int table = m_Table[body];\n\n            if ((table & (1 << 31)) != 0)\n            {\n                body = table & 0x7FFF;\n\n                int vhue = (hue & 0x3FFF) - 1;\n\n                if (vhue < 0 || vhue >= Hues.List.Length)\n                    hue = (table >> 15) & 0xFFFF;\n            }\n        }\n\n        private static void LoadTable()\n        {\n            int count = 400 + ((m_FileIndex.Index.Length - 35000) / 175);\n\n            m_Table = new int[count];\n\n            for (int i = 0; i < count; ++i)\n            {\n                object o = BodyTable.m_Entries[i];\n\n                if (o == null || BodyConverter.Contains(i))\n                {\n                    m_Table[i] = i;\n                }\n                else\n                {\n                    BodyTableEntry bte = (BodyTableEntry) o;\n\n                    m_Table[i] = bte.OldID | (1 << 31) | ((bte.NewHue & 0xFFFF) << 15);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Is Body with action and direction definied\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <param name=\"action\"></param>\n        /// <param name=\"direction\"></param>\n        /// <returns></returns>\n        public static bool IsActionDefined(int body, int action, int direction)\n        {\n            Translate(ref body);\n            int fileType = BodyConverter.Convert(ref body);\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, action, direction, fileType, out fileIndex, out index);\n\n            int length, extra;\n            bool patched;\n            bool valid = fileIndex.Valid(index, out length, out extra, out patched);\n            if ((!valid) || (length < 1))\n                return false;\n            return true;\n        }\n\n        /// <summary>\n        /// Is Animation in given animfile definied\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <param name=\"action\"></param>\n        /// <param name=\"dir\"></param>\n        /// <param name=\"fileType\"></param>\n        /// <returns></returns>\n        public static bool IsAnimDefinied(int body, int action, int dir, int fileType)\n        {\n            FileIndex fileIndex;\n            int index;\n            GetFileIndex(body, action, dir, fileType, out fileIndex, out index);\n\n            int length, extra;\n            bool patched;\n            Stream stream = fileIndex.Seek(index, out length, out extra, out patched);\n            bool def = true;\n            if ((stream == null) || (length == 0))\n                def = false;\n            if (stream != null)\n                stream.Close();\n            return def;\n        }\n\n        /// <summary>\n        /// Returns Animationcount in given animfile\n        /// </summary>\n        /// <param name=\"fileType\"></param>\n        /// <returns></returns>\n        public static int GetAnimCount(int fileType)\n        {\n            int count;\n            switch (fileType)\n            {\n                default:\n                case 1:\n                    count = 400 + (int) (m_FileIndex.IdxLength - 35000 * 12) / (12 * 175);\n                    break;\n                case 2:\n                    count = 200 + (int) (m_FileIndex2.IdxLength - 22000 * 12) / (12 * 65);\n                    break;\n                case 3:\n                    count = 400 + (int) (m_FileIndex3.IdxLength - 35000 * 12) / (12 * 175);\n                    break;\n                case 4:\n                    count = 400 + (int) (m_FileIndex4.IdxLength - 35000 * 12) / (12 * 175);\n                    break;\n                case 5:\n                    count = 400 + (int) (m_FileIndex5.IdxLength - 35000 * 12) / (12 * 175);\n                    break;\n            }\n\n            return count;\n        }\n\n        /// <summary>\n        /// Actioncount of given Body in given anim file\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <param name=\"fileType\"></param>\n        /// <returns></returns>\n        public static int GetAnimLength(int body, int fileType)\n        {\n            int length = 0;\n            switch (fileType)\n            {\n                default:\n                case 1:\n                    if (body < 200)\n                        length = 22; //high\n                    else if (body < 400)\n                        length = 13; //low\n                    else\n                        length = 35; //people\n                    break;\n                case 2:\n                    if (body < 200)\n                        length = 22; //high\n                    else\n                        length = 13; //low\n                    break;\n                case 3:\n                    if (body < 300)\n                        length = 13;\n                    else if (body < 400)\n                        length = 22;\n                    else\n                        length = 35;\n                    break;\n                case 4:\n                    if (body < 200)\n                        length = 22;\n                    else if (body < 400)\n                        length = 13;\n                    else\n                        length = 35;\n                    break;\n                case 5:\n                    if (body < 200)\n                        length = 22;\n                    else if (body < 400)\n                        length = 13;\n                    else\n                        length = 35;\n                    break;\n            }\n\n            return length;\n        }\n\n        /// <summary>\n        /// Gets Fileseek index based on fileType,body,action,direction\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <param name=\"action\"></param>\n        /// <param name=\"direction\"></param>\n        /// <param name=\"fileType\">animX</param>\n        /// <param name=\"fileIndex\"></param>\n        /// <param name=\"index\"></param>\n        private static void GetFileIndex(int body, int action, int direction, int fileType, out FileIndex fileIndex,\n            out int index)\n        {\n            switch (fileType)\n            {\n                default:\n                case 1:\n                    fileIndex = m_FileIndex;\n                    if (body < 200)\n                        index = body * 110;\n                    else if (body < 400)\n                        index = 22000 + ((body - 200) * 65);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n\n                    break;\n                case 2:\n                    fileIndex = m_FileIndex2;\n                    if (body < 200)\n                        index = body * 110;\n                    else\n                        index = 22000 + ((body - 200) * 65);\n\n                    break;\n                case 3:\n                    fileIndex = m_FileIndex3;\n                    if (body < 300)\n                        index = body * 65;\n                    else if (body < 400)\n                        index = 33000 + ((body - 300) * 110);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n\n                    break;\n                case 4:\n                    fileIndex = m_FileIndex4;\n                    if (body < 200)\n                        index = body * 110;\n                    else if (body < 400)\n                        index = 22000 + ((body - 200) * 65);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n\n                    break;\n                case 5:\n                    fileIndex = m_FileIndex5;\n                    if ((body < 200) && (body != 34)) // looks strange, though it works.\n                        index = body * 110;\n                    else if (body < 400)\n                        index = 22000 + ((body - 200) * 65);\n                    else\n                        index = 35000 + ((body - 400) * 175);\n\n                    break;\n            }\n\n            index += action * 5;\n\n            if (direction <= 4)\n                index += direction;\n            else\n                index += direction - (direction - 4) * 2;\n        }\n\n        /// <summary>\n        /// Returns Filename body is in\n        /// </summary>\n        /// <param name=\"body\"></param>\n        /// <returns>anim{0}.mul</returns>\n        public static string GetFileName(int body)\n        {\n            Translate(ref body);\n            int fileType = BodyConverter.Convert(ref body);\n\n            if (fileType == 1)\n                return \"anim.mul\";\n            else\n                return $\"anim{fileType}.mul\";\n        }\n    }\n\n    public sealed class Frame\n    {\n        public Point Center { get; set; }\n        public Bitmap Bitmap { get; set; }\n\n        private const int DoubleXor = (0x200 << 22) | (0x200 << 12);\n\n        public static readonly Frame Empty = new Frame();\n        //public static readonly Frame[] EmptyFrames = new Frame[1] { Empty };\n\n        private Frame()\n        {\n            Bitmap = new Bitmap(1, 1);\n        }\n\n        public unsafe Frame(ushort[] palette, BinaryReader bin, bool flip)\n        {\n            int xCenter = bin.ReadInt16();\n            int yCenter = bin.ReadInt16();\n\n            int width = bin.ReadUInt16();\n            int height = bin.ReadUInt16();\n            if (height == 0 || width == 0)\n                return;\n            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format16bppArgb1555);\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,\n                PixelFormat.Format16bppArgb1555);\n            ushort* line = (ushort*) bd.Scan0;\n            int delta = bd.Stride >> 1;\n\n            int header;\n\n            int xBase = xCenter - 0x200;\n            int yBase = (yCenter + height) - 0x200;\n\n            if (!flip)\n            {\n                line += xBase;\n                line += yBase * delta;\n\n                while ((header = bin.ReadInt32()) != 0x7FFF7FFF)\n                {\n                    header ^= DoubleXor;\n\n                    ushort* cur = line + ((((header >> 12) & 0x3FF) * delta) + ((header >> 22) & 0x3FF));\n                    ushort* end = cur + (header & 0xFFF);\n                    while (cur < end)\n                        *cur++ = palette[bin.ReadByte()];\n                }\n            }\n            else\n            {\n                line -= xBase - width + 1;\n                line += yBase * delta;\n\n                while ((header = bin.ReadInt32()) != 0x7FFF7FFF)\n                {\n                    header ^= DoubleXor;\n\n                    ushort* cur = line + ((((header >> 12) & 0x3FF) * delta) - ((header >> 22) & 0x3FF));\n                    ushort* end = cur - (header & 0xFFF);\n\n                    while (cur > end)\n                        *cur-- = palette[bin.ReadByte()];\n                }\n\n                xCenter = width - xCenter;\n            }\n\n            bmp.UnlockBits(bd);\n\n            Center = new Point(xCenter, yCenter);\n            Bitmap = bmp;\n        }\n    }\n\n    public sealed class BodyTableEntry\n    {\n        public int OldID { get; set; }\n        public int NewID { get; set; }\n        public int NewHue { get; set; }\n\n        public BodyTableEntry(int oldID, int newID, int newHue)\n        {\n            OldID = oldID;\n            NewID = newID;\n            NewHue = newHue;\n        }\n    }\n\n    public sealed class BodyTable\n    {\n        public static Hashtable m_Entries;\n\n        static BodyTable()\n        {\n            Initialize();\n        }\n\n        public static void Initialize()\n        {\n            m_Entries = new Hashtable();\n\n            string filePath = Files.GetFilePath(\"body.def\");\n\n            if (filePath == null)\n                return;\n\n            using (StreamReader def = new StreamReader(filePath))\n            {\n                string line;\n\n                while ((line = def.ReadLine()) != null)\n                {\n                    if ((line = line.Trim()).Length == 0 || line.StartsWith(\"#\"))\n                        continue;\n\n                    try\n                    {\n                        int index1 = line.IndexOf(\"{\");\n                        int index2 = line.IndexOf(\"}\");\n\n                        string param1 = line.Substring(0, index1);\n                        string param2 = line.Substring(index1 + 1, index2 - index1 - 1);\n                        string param3 = line.Substring(index2 + 1);\n\n                        int indexOf = param2.IndexOf(',');\n\n                        if (indexOf > -1)\n                            param2 = param2.Substring(0, indexOf).Trim();\n\n                        int iParam1 = Convert.ToInt32(param1.Trim());\n                        int iParam2 = Convert.ToInt32(param2.Trim());\n                        int iParam3 = Convert.ToInt32(param3.Trim());\n\n                        m_Entries[iParam1] = new BodyTableEntry(iParam2, iParam1, iParam3);\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Animdata.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections;\nusing System.IO;\n\nnamespace Ultima\n{\n    public sealed class Animdata\n    {\n        private static int[] m_Header;\n        private static byte[] m_Unknown;\n\n        public static Hashtable AnimData { get; set; }\n\n        static Animdata()\n        {\n            Initialize();\n        }\n\n        /// <summary>\n        /// Reads animdata.mul and fills <see cref=\"AnimData\"/>\n        /// </summary>\n        public static void Initialize()\n        {\n            AnimData = new Hashtable();\n            string path = Files.GetFilePath(\"animdata.mul\");\n            if (path != null)\n            {\n                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    using (BinaryReader bin = new BinaryReader(fs))\n                    {\n                        unsafe\n                        {\n                            int id = 0;\n                            int h = 0;\n                            byte unk;\n                            byte fcount;\n                            byte finter;\n                            byte fstart;\n                            sbyte[] fdata;\n                            m_Header = new int[bin.BaseStream.Length / (4 + 8 * (64 + 4))];\n                            while (h < m_Header.Length /*bin.BaseStream.Length != bin.BaseStream.Position*/)\n                            {\n                                m_Header[h++] = bin.ReadInt32(); // chunk header\n                                // Read 8 tiles\n                                byte[] buffer = bin.ReadBytes(544);\n                                fixed (byte* buf = buffer)\n                                {\n                                    byte* data = buf;\n                                    for (int i = 0; i < 8; ++i, ++id)\n                                    {\n                                        fdata = new sbyte[64];\n                                        for (int j = 0; j < 64; ++j)\n                                            fdata[j] = (sbyte) *data++;\n                                        unk = *data++;\n                                        fcount = *data++;\n                                        finter = *data++;\n                                        fstart = *data++;\n                                        if (fcount > 0)\n                                            AnimData[id] = new Data(fdata, unk, fcount, finter, fstart);\n                                    }\n                                }\n                            }\n\n                            int remaining = (int) (bin.BaseStream.Length - bin.BaseStream.Position);\n                            if (remaining > 0)\n                                m_Unknown = bin.ReadBytes(remaining);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets Animation <see cref=\"Data\"/>\n        /// </summary>\n        /// <param name=\"id\"></param>\n        /// <returns></returns>\n        public static Data GetAnimData(int id)\n        {\n            if (AnimData.Contains(id))\n                return ((Data) AnimData[id]);\n            else\n                return null;\n        }\n\n        public static void Save(string path)\n        {\n            string FileName = Path.Combine(path, \"animdata.mul\");\n            using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    int id = 0;\n                    int h = 0;\n                    while (id < m_Header.Length * 8)\n                    {\n                        bin.Write(m_Header[h++]);\n                        for (int i = 0; i < 8; ++i, ++id)\n                        {\n                            Data data = GetAnimData(id);\n                            for (int j = 0; j < 64; ++j)\n                            {\n                                if (data != null)\n                                    bin.Write(data.FrameData[j]);\n                                else\n                                    bin.Write((sbyte) 0);\n                            }\n\n                            if (data != null)\n                            {\n                                bin.Write(data.Unknown);\n                                bin.Write(data.FrameCount);\n                                bin.Write(data.FrameInterval);\n                                bin.Write(data.FrameStart);\n                            }\n                            else\n                            {\n                                bin.Write((byte) 0);\n                                bin.Write((byte) 0);\n                                bin.Write((byte) 0);\n                                bin.Write((byte) 0);\n                            }\n                        }\n                    }\n\n                    if (m_Unknown != null)\n                        bin.Write(m_Unknown);\n                }\n            }\n        }\n\n        public class Data\n        {\n            public sbyte[] FrameData { get; set; }\n            public byte Unknown { get; private set; }\n            public byte FrameCount { get; set; }\n            public byte FrameInterval { get; set; }\n            public byte FrameStart { get; set; }\n\n            public Data(sbyte[] frame, byte unk, byte fcount, byte finter, byte fstart)\n            {\n                FrameData = frame;\n                Unknown = unk;\n                FrameCount = fcount;\n                FrameInterval = finter;\n                FrameStart = fstart;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Art.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\nusing System.Security.Cryptography;\nusing System.Collections.Generic;\n\nnamespace Ultima\n{\n    public sealed class Art\n    {\n        private static FileIndex m_FileIndex = new FileIndex(\"Artidx.mul\", \"Art.mul\", \"artLegacyMUL.uop\",\n            0x10000 /*0x13FDC*/, 4, \".tga\", 0x13FDC, false);\n\n        private static Bitmap[] m_Cache;\n        private static bool[] m_Removed;\n        private static Hashtable m_patched = new Hashtable();\n        public static bool Modified = false;\n\n        private static byte[] m_StreamBuffer;\n        private static byte[] Validbuffer;\n\n\n        struct CheckSums\n        {\n            public byte[] checksum;\n            public int pos;\n            public int length;\n            public int index;\n        }\n\n        private static List<CheckSums> checksumsLand;\n        private static List<CheckSums> checksumsStatic;\n\n        static Art()\n        {\n            m_Cache = new Bitmap[GetIdxLength()];\n            m_Removed = new bool[GetIdxLength()];\n        }\n\n        public static int GetMaxItemID()\n        {\n            if (GetIdxLength() == 0xC000)\n                return 0x7FFF;\n\n            if (GetIdxLength() == 0x13FDC)\n                return 0xFFDB;\n\n            return 0x3FFF;\n        }\n\n        public static bool IsUOAHS()\n        {\n            return (GetIdxLength() == 0x13FDC);\n        }\n\n        public static ushort GetLegalItemID(int itemID, bool checkmaxid = true)\n        {\n            if (itemID < 0)\n                return 0;\n\n            if (checkmaxid)\n            {\n                int max = GetMaxItemID();\n                if (itemID > max)\n                    return 0;\n            }\n\n            return (ushort) itemID;\n        }\n\n        public static int GetIdxLength()\n        {\n            return (int) (m_FileIndex.IdxLength / 12);\n        }\n\n        /// <summary>\n        /// ReReads Art.mul\n        /// </summary>\n        public static void Reload()\n        {\n            m_FileIndex = new FileIndex(\"Artidx.mul\", \"Art.mul\", \"artLegacyMUL.uop\", 0x10000 /*0x13FDC*/, 4, \".tga\",\n                0x13FDC, false);\n            m_Cache = new Bitmap[GetIdxLength()];\n            m_Removed = new bool[GetIdxLength()];\n            m_patched.Clear();\n            Modified = false;\n        }\n\n        /// <summary>\n        /// Sets bmp of index in <see cref=\"m_Cache\"/> of Static\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"bmp\"></param>\n        public static void ReplaceStatic(int index, Bitmap bmp)\n        {\n            index = Art.GetLegalItemID(index);\n            index += 0x4000;\n\n            m_Cache[index] = bmp;\n            m_Removed[index] = false;\n            if (m_patched.Contains(index))\n                m_patched.Remove(index);\n            Modified = true;\n        }\n\n        /// <summary>\n        /// Sets bmp of index in <see cref=\"m_Cache\"/> of Land\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"bmp\"></param>\n        public static void ReplaceLand(int index, Bitmap bmp)\n        {\n            index &= 0x3FFF;\n            m_Cache[index] = bmp;\n            m_Removed[index] = false;\n            if (m_patched.Contains(index))\n                m_patched.Remove(index);\n            Modified = true;\n        }\n\n        /// <summary>\n        /// Removes Static index <see cref=\"m_Removed\"/>\n        /// </summary>\n        /// <param name=\"index\"></param>\n        public static void RemoveStatic(int index)\n        {\n            index = Art.GetLegalItemID(index);\n            index += 0x4000;\n\n            m_Removed[index] = true;\n            Modified = true;\n        }\n\n        /// <summary>\n        /// Removes Land index <see cref=\"m_Removed\"/>\n        /// </summary>\n        /// <param name=\"index\"></param>\n        public static void RemoveLand(int index)\n        {\n            index &= 0x3FFF;\n            m_Removed[index] = true;\n            Modified = true;\n        }\n\n        /// <summary>\n        /// Tests if Static is definied (width and hight check)\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static unsafe bool IsValidStatic(int index)\n        {\n            index = GetLegalItemID(index);\n            index += 0x4000;\n\n            if (m_Removed[index])\n                return false;\n            if (m_Cache[index] != null)\n                return true;\n\n            int length, extra;\n            bool patched;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n\n            if (stream == null)\n                return false;\n\n            if (Validbuffer == null)\n                Validbuffer = new byte[4];\n            stream.Seek(4, SeekOrigin.Current);\n            stream.Read(Validbuffer, 0, 4);\n            fixed (byte* b = Validbuffer)\n            {\n                short* dat = (short*) b;\n                if (*dat++ <= 0 || *dat <= 0)\n                    return false;\n                return true;\n            }\n        }\n\n        /// <summary>\n        /// Tests if LandTile is definied\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static bool IsValidLand(int index)\n        {\n            index &= 0x3FFF;\n            if (m_Removed[index])\n                return false;\n            if (m_Cache[index] != null)\n                return true;\n\n            int length, extra;\n            bool patched;\n\n            return m_FileIndex.Valid(index, out length, out extra, out patched);\n        }\n\n        /// <summary>\n        /// Returns Bitmap of LandTile (with Cache)\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static Bitmap GetLand(int index)\n        {\n            bool patched;\n            return GetLand(index, out patched);\n        }\n\n        /// <summary>\n        /// Returns Bitmap of LandTile (with Cache) and verdata bool\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"patched\"></param>\n        /// <returns></returns>\n        public static Bitmap GetLand(int index, out bool patched)\n        {\n            index &= 0x3FFF;\n            if (m_patched.Contains(index))\n                patched = (bool) m_patched[index];\n            else\n                patched = false;\n\n            if (m_Removed[index])\n                return null;\n            if (m_Cache[index] != null)\n                return m_Cache[index];\n\n            int length, extra;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n            if (stream == null)\n                return null;\n            if (patched)\n                m_patched[index] = true;\n\n            if (Files.CacheData)\n                return m_Cache[index] = LoadLand(stream, length);\n            else\n                return LoadLand(stream, length);\n        }\n\n        public static byte[] GetRawLand(int index)\n        {\n            index &= 0x3FFF;\n\n            int length, extra;\n            bool patched;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n            if (stream == null)\n                return null;\n            byte[] buffer = new byte[length];\n            stream.Read(buffer, 0, length);\n            stream.Close();\n            return buffer;\n        }\n\n        /// <summary>\n        /// Returns Bitmap of Static (with Cache)\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static Bitmap GetStatic(int index, bool checkmaxid = true)\n        {\n            bool patched;\n            return GetStatic(index, out patched, checkmaxid);\n        }\n\n        /// <summary>\n        /// Returns Bitmap of Static (with Cache) and verdata bool\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"patched\"></param>\n        /// <returns></returns>\n        public static Bitmap GetStatic(int index, out bool patched, bool checkmaxid = true)\n        {\n            index = GetLegalItemID(index, checkmaxid);\n            index += 0x4000;\n\n            if (m_patched.Contains(index))\n                patched = (bool) m_patched[index];\n            else\n                patched = false;\n\n            if (m_Removed[index])\n                return null;\n            if (m_Cache[index] != null)\n                return m_Cache[index];\n\n            int length, extra;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n            if (stream == null)\n                return null;\n            if (patched)\n                m_patched[index] = true;\n\n            if (Files.CacheData)\n                return m_Cache[index] = LoadStatic(stream, length);\n            else\n                return LoadStatic(stream, length);\n        }\n\n        public static byte[] GetRawStatic(int index)\n        {\n            index = GetLegalItemID(index);\n            index += 0x4000;\n\n            int length, extra;\n            bool patched;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n            if (stream == null)\n                return null;\n            byte[] buffer = new byte[length];\n            stream.Read(buffer, 0, length);\n            stream.Close();\n            return buffer;\n        }\n\n        public unsafe static void Measure(Bitmap bmp, out int xMin, out int yMin, out int xMax, out int yMax)\n        {\n            xMin = yMin = 0;\n            xMax = yMax = -1;\n\n            if (bmp == null || bmp.Width <= 0 || bmp.Height <= 0)\n                return;\n\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly,\n                PixelFormat.Format16bppArgb1555);\n\n            int delta = (bd.Stride >> 1) - bd.Width;\n            int lineDelta = bd.Stride >> 1;\n\n            ushort* pBuffer = (ushort*) bd.Scan0;\n            ushort* pLineEnd = pBuffer + bd.Width;\n            ushort* pEnd = pBuffer + (bd.Height * lineDelta);\n\n            bool foundPixel = false;\n\n            int x = 0, y = 0;\n\n            while (pBuffer < pEnd)\n            {\n                while (pBuffer < pLineEnd)\n                {\n                    ushort c = *pBuffer++;\n\n                    if ((c & 0x8000) != 0)\n                    {\n                        if (!foundPixel)\n                        {\n                            foundPixel = true;\n                            xMin = xMax = x;\n                            yMin = yMax = y;\n                        }\n                        else\n                        {\n                            if (x < xMin)\n                                xMin = x;\n\n                            if (y < yMin)\n                                yMin = y;\n\n                            if (x > xMax)\n                                xMax = x;\n\n                            if (y > yMax)\n                                yMax = y;\n                        }\n                    }\n\n                    ++x;\n                }\n\n                pBuffer += delta;\n                pLineEnd += lineDelta;\n                ++y;\n                x = 0;\n            }\n\n            bmp.UnlockBits(bd);\n        }\n\n        private static unsafe Bitmap LoadStatic(Stream stream, int length)\n        {\n            Bitmap bmp;\n            if (m_StreamBuffer == null || m_StreamBuffer.Length < length)\n                m_StreamBuffer = new byte[length];\n            stream.Read(m_StreamBuffer, 0, length);\n            stream.Close();\n\n            fixed (byte* data = m_StreamBuffer)\n            {\n                ushort* bindata = (ushort*) data;\n                int count = 2;\n                //bin.ReadInt32();\n                int width = bindata[count++];\n                int height = bindata[count++];\n\n                if (width <= 0 || height <= 0)\n                    return null;\n\n                int[] lookups = new int[height];\n\n                int start = (height + 4);\n\n                for (int i = 0; i < height; ++i)\n                    lookups[i] = (int) (start + (bindata[count++]));\n\n                bmp = new Bitmap(width, height, PixelFormat.Format16bppArgb1555);\n                BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,\n                    PixelFormat.Format16bppArgb1555);\n\n\n                ushort* line = (ushort*) bd.Scan0;\n                int delta = bd.Stride >> 1;\n\n\n                for (int y = 0; y < height; ++y, line += delta)\n                {\n                    count = lookups[y];\n\n                    ushort* cur = line;\n                    ushort* end;\n                    int xOffset, xRun;\n\n                    while (((xOffset = bindata[count++]) + (xRun = bindata[count++])) != 0)\n                    {\n                        if (xOffset > delta)\n                            break;\n                        cur += xOffset;\n                        if (xOffset + xRun > delta)\n                            break;\n                        end = cur + xRun;\n\n                        while (cur < end)\n                            *cur++ = (ushort) (bindata[count++] ^ 0x8000);\n                    }\n                }\n\n                bmp.UnlockBits(bd);\n            }\n\n            return bmp;\n        }\n\n        private static unsafe Bitmap LoadLand(Stream stream, int length)\n        {\n            Bitmap bmp = new Bitmap(44, 44, PixelFormat.Format16bppArgb1555);\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, 44, 44), ImageLockMode.WriteOnly,\n                PixelFormat.Format16bppArgb1555);\n            if (m_StreamBuffer == null || m_StreamBuffer.Length < length)\n                m_StreamBuffer = new byte[length];\n            stream.Read(m_StreamBuffer, 0, length);\n            stream.Close();\n            fixed (byte* bindata = m_StreamBuffer)\n            {\n                ushort* bdata = (ushort*) bindata;\n                int xOffset = 21;\n                int xRun = 2;\n\n                ushort* line = (ushort*) bd.Scan0;\n                int delta = bd.Stride >> 1;\n\n                for (int y = 0; y < 22; ++y, --xOffset, xRun += 2, line += delta)\n                {\n                    ushort* cur = line + xOffset;\n                    ushort* end = cur + xRun;\n\n                    while (cur < end)\n                        *cur++ = (ushort) (*bdata++ | 0x8000);\n                }\n\n                xOffset = 0;\n                xRun = 44;\n\n                for (int y = 0; y < 22; ++y, ++xOffset, xRun -= 2, line += delta)\n                {\n                    ushort* cur = line + xOffset;\n                    ushort* end = cur + xRun;\n\n                    while (cur < end)\n                        *cur++ = (ushort) (*bdata++ | 0x8000);\n                }\n            }\n\n            bmp.UnlockBits(bd);\n            return bmp;\n        }\n\n\n        /// <summary>\n        /// Saves mul\n        /// </summary>\n        /// <param name=\"path\"></param>\n        public static unsafe void Save(string path)\n        {\n            checksumsLand = new List<CheckSums>();\n            checksumsStatic = new List<CheckSums>();\n            string idx = Path.Combine(path, \"artidx.mul\");\n            string mul = Path.Combine(path, \"art.mul\");\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                MemoryStream memidx = new MemoryStream();\n                MemoryStream memmul = new MemoryStream();\n                SHA256Managed sha = new SHA256Managed();\n                //StreamWriter Tex = new StreamWriter(new FileStream(\"d:/artlog.txt\", FileMode.Create, FileAccess.ReadWrite));\n\n                using (BinaryWriter binidx = new BinaryWriter(memidx),\n                    binmul = new BinaryWriter(memmul))\n                {\n                    for (int index = 0; index < GetIdxLength(); index++)\n                    {\n                        Files.FireFileSaveEvent();\n                        if (m_Cache[index] == null)\n                        {\n                            if (index < 0x4000)\n                                m_Cache[index] = GetLand(index);\n                            else\n                                m_Cache[index] = GetStatic(index - 0x4000, false);\n                        }\n\n                        Bitmap bmp = m_Cache[index];\n                        if ((bmp == null) || (m_Removed[index]))\n                        {\n                            binidx.Write((int) -1); // lookup\n                            binidx.Write((int) 0); // length\n                            binidx.Write((int) -1); // extra\n                            //Tex.WriteLine(System.String.Format(\"0x{0:X4} : 0x{1:X4} 0x{2:X4}\", index, (int)-1, (int)-1));\n                        }\n                        else if (index < 0x4000)\n                        {\n                            MemoryStream ms = new MemoryStream();\n                            bmp.Save(ms, ImageFormat.Bmp);\n                            byte[] checksum = sha.ComputeHash(ms.ToArray());\n                            CheckSums sum;\n                            if (compareSaveImagesLand(checksum, out sum))\n                            {\n                                binidx.Write((int) sum.pos); //lookup\n                                binidx.Write((int) sum.length);\n                                binidx.Write((int) 0);\n                                //Tex.WriteLine(System.String.Format(\"0x{0:X4} : 0x{1:X4} 0x{2:X4}\", index, (int)sum.pos, (int)sum.length));\n                                //Tex.WriteLine(System.String.Format(\"0x{0:X4} -> 0x{1:X4}\", sum.index, index));\n                                continue;\n                            }\n\n                            //land\n                            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),\n                                ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555);\n                            ushort* line = (ushort*) bd.Scan0;\n                            int delta = bd.Stride >> 1;\n                            binidx.Write((int) binmul.BaseStream.Position); //lookup\n                            int length = (int) binmul.BaseStream.Position;\n                            int x = 22;\n                            int y = 0;\n                            int linewidth = 2;\n                            for (int m = 0; m < 22; ++m, ++y, line += delta, linewidth += 2)\n                            {\n                                --x;\n                                ushort* cur = line;\n                                for (int n = 0; n < linewidth; ++n)\n                                    binmul.Write((ushort) (cur[x + n] ^ 0x8000));\n                            }\n\n                            x = 0;\n                            linewidth = 44;\n                            y = 22;\n                            line = (ushort*) bd.Scan0;\n                            line += delta * 22;\n                            for (int m = 0; m < 22; m++, y++, line += delta, ++x, linewidth -= 2)\n                            {\n                                ushort* cur = line;\n                                for (int n = 0; n < linewidth; n++)\n                                    binmul.Write((ushort) (cur[x + n] ^ 0x8000));\n                            }\n\n                            int start = length;\n                            length = (int) binmul.BaseStream.Position - length;\n                            binidx.Write(length);\n                            binidx.Write((int) 0);\n                            bmp.UnlockBits(bd);\n                            CheckSums s = new CheckSums()\n                                {pos = start, length = length, checksum = checksum, index = index};\n                            //Tex.WriteLine(System.String.Format(\"0x{0:X4} : 0x{1:X4} 0x{2:X4}\", index, start, length));\n                            checksumsLand.Add(s);\n                        }\n                        else\n                        {\n                            MemoryStream ms = new MemoryStream();\n                            bmp.Save(ms, ImageFormat.Bmp);\n                            byte[] checksum = sha.ComputeHash(ms.ToArray());\n                            CheckSums sum;\n                            if (compareSaveImagesStatic(checksum, out sum))\n                            {\n                                binidx.Write((int) sum.pos); //lookup\n                                binidx.Write((int) sum.length);\n                                binidx.Write((int) 0);\n                                //Tex.WriteLine(System.String.Format(\"0x{0:X4} -> 0x{1:X4}\", sum.index, index));\n                                //Tex.WriteLine(System.String.Format(\"0x{0:X4} : 0x{1:X4} 0x{2:X4}\", index, sum.pos, sum.length));\n                                continue;\n                            }\n\n                            // art\n                            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),\n                                ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555);\n                            ushort* line = (ushort*) bd.Scan0;\n                            int delta = bd.Stride >> 1;\n                            binidx.Write((int) binmul.BaseStream.Position); //lookup\n                            int length = (int) binmul.BaseStream.Position;\n                            binmul.Write((int) 1234); // header\n                            binmul.Write((short) bmp.Width);\n                            binmul.Write((short) bmp.Height);\n                            int lookup = (int) binmul.BaseStream.Position;\n                            int streamloc = lookup + bmp.Height * 2;\n                            int width = 0;\n                            for (int i = 0; i < bmp.Height; ++i) // fill lookup\n                                binmul.Write(width);\n                            int X = 0;\n                            for (int Y = 0; Y < bmp.Height; ++Y, line += delta)\n                            {\n                                ushort* cur = line;\n                                width = (int) (binmul.BaseStream.Position - streamloc) / 2;\n                                binmul.BaseStream.Seek(lookup + Y * 2, SeekOrigin.Begin);\n                                binmul.Write(width);\n                                binmul.BaseStream.Seek(streamloc + width * 2, SeekOrigin.Begin);\n                                int i = 0;\n                                int j = 0;\n                                X = 0;\n                                while (i < bmp.Width)\n                                {\n                                    i = X;\n                                    for (i = X; i <= bmp.Width; ++i)\n                                    {\n                                        //first pixel set\n                                        if (i < bmp.Width)\n                                        {\n                                            if (cur[i] != 0)\n                                                break;\n                                        }\n                                    }\n\n                                    if (i < bmp.Width)\n                                    {\n                                        for (j = (i + 1); j < bmp.Width; ++j)\n                                        {\n                                            //next non set pixel\n                                            if (cur[j] == 0)\n                                                break;\n                                        }\n\n                                        binmul.Write((short) (i - X)); //xoffset\n                                        binmul.Write((short) (j - i)); //run\n                                        for (int p = i; p < j; ++p)\n                                            binmul.Write((ushort) (cur[p] ^ 0x8000));\n                                        X = j;\n                                    }\n                                }\n\n                                binmul.Write((short) 0); //xOffset\n                                binmul.Write((short) 0); //Run\n                            }\n\n                            int start = length;\n                            length = (int) binmul.BaseStream.Position - length;\n                            binidx.Write(length);\n                            binidx.Write((int) 0);\n                            bmp.UnlockBits(bd);\n                            CheckSums s = new CheckSums()\n                                {pos = start, length = length, checksum = checksum, index = index};\n                            //Tex.WriteLine(System.String.Format(\"0x{0:X4} : 0x{1:X4} 0x{2:X4}\", index, start, length));\n                            checksumsStatic.Add(s);\n                        }\n                    }\n\n                    memidx.WriteTo(fsidx);\n                    memmul.WriteTo(fsmul);\n                }\n            }\n        }\n\n        private static bool compareSaveImagesLand(byte[] newchecksum, out CheckSums sum)\n        {\n            sum = new CheckSums();\n            for (int i = 0; i < checksumsLand.Count; ++i)\n            {\n                byte[] cmp = checksumsLand[i].checksum;\n                if (((cmp == null) || (newchecksum == null))\n                    || (cmp.Length != newchecksum.Length))\n                {\n                    return false;\n                }\n\n                bool valid = true;\n                for (int j = 0; j < cmp.Length; ++j)\n                {\n                    if (cmp[j] != newchecksum[j])\n                    {\n                        valid = false;\n                        break;\n                    }\n                }\n\n                if (valid)\n                {\n                    sum = checksumsLand[i];\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private static bool compareSaveImagesStatic(byte[] newchecksum, out CheckSums sum)\n        {\n            sum = new CheckSums();\n            for (int i = 0; i < checksumsStatic.Count; ++i)\n            {\n                byte[] cmp = checksumsStatic[i].checksum;\n                if (((cmp == null) || (newchecksum == null))\n                    || (cmp.Length != newchecksum.Length))\n                {\n                    return false;\n                }\n\n                bool valid = true;\n                for (int j = 0; j < cmp.Length; ++j)\n                {\n                    if (cmp[j] != newchecksum[j])\n                    {\n                        valid = false;\n                        break;\n                    }\n                }\n\n                if (valid)\n                {\n                    sum = checksumsStatic[i];\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/BwtDecompress.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2024 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\nusing System;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\n\nnamespace Ultima\n{\n    internal static class BwtDecompress\n    {\n        public static byte[] Decompress(byte[] buffer)\n        {\n            byte[] output = null;\n\n            using (var reader = new BinaryReader(new MemoryStream(buffer)))\n            {\n                var header = reader.ReadUInt32();\n                var len = 0u;\n\n                var firstChar = reader.ReadByte();\n\n                Span<ushort> table = new ushort[256 * 256];\n                table = BuildTable(table, firstChar);\n\n                var list = new byte[reader.BaseStream.Length - 4];\n                var i = 0;\n                while (reader.BaseStream.Position < reader.BaseStream.Length)\n                {\n                    var currentValue = firstChar;\n                    var value = table[currentValue];\n                    if (currentValue > 0)\n                    {\n                        do\n                        {\n                            table[currentValue] = table[currentValue - 1];\n                        } while (--currentValue > 0);\n                    }\n\n                    table[0] = value;\n\n                    list[i++] = (byte) value;\n                    firstChar = reader.ReadByte();\n                }\n\n                output = InternalDecompress(list, len);\n            }\n\n            return output;\n        }\n\n        /// \n        static void MergeSort(Span<ushort> span)\n        {\n            if (span.Length <= 1)\n                return;\n\n            var list = span.ToArray().ToList();\n            list.Sort();\n\n            int mid = span.Length / 2;\n            var left = span.Slice(0, mid);\n            var right = span.Slice(mid);\n\n            MergeSort(left);\n            MergeSort(right);\n\n            Merge(span, left, right);\n        }\n\n        static void Merge(Span<ushort> destination, Span<ushort> left, Span<ushort> right)\n        {\n            int i = 0, j = 0, k = 0;\n\n            while (i < left.Length && j < right.Length)\n            {\n                if (left[i] <= right[j])\n                {\n                    destination[k++] = left[i++];\n                }\n                else\n                {\n                    destination[k++] = right[j++];\n                }\n            }\n\n            while (i < left.Length)\n            {\n                destination[k++] = left[i++];\n            }\n\n            while (j < right.Length)\n            {\n                destination[k++] = right[j++];\n            }\n        }\n\n        /// \n\n        static Span<ushort> BuildTable(Span<ushort> table, byte startValue)\n        {\n            int index = 0;\n            byte firstByte = startValue;\n            byte secondByte = 0;\n            for (int i = 0; i < 256 * 256; i++)\n            {\n                var val = (ushort) (firstByte + (secondByte << 8));\n                table[index++] = val;\n\n                firstByte++;\n                if (firstByte == 0)\n                {\n                    secondByte++;\n                }\n            }\n\n            var list = table.ToArray().ToList();\n            list.Sort();\n            return list.ToArray();\n        }\n\n        static byte[] InternalDecompress(Span<byte> input, uint len)\n        {\n            Span<char> symbolTable = stackalloc char[256];\n            Span<char> frequency = stackalloc char[256];\n            Span<int> partialInput = stackalloc int[256 * 3];\n            partialInput.Clear();\n\n            for (var i = 0; i < 256; i++)\n                symbolTable[i] = (char) i;\n\n            input.Slice(0, 1024).CopyTo(MemoryMarshal.AsBytes(partialInput));\n\n            var sum = 0;\n            for (var i = 0; i < 256; i++)\n                sum += partialInput[i];\n\n            if (len == 0)\n            {\n                len = (uint) sum;\n            }\n\n            if (sum != len)\n                return Array.Empty<byte>();\n\n            var output = new byte[len];\n\n            var count = 0;\n            var nonZeroCount = 0;\n\n            for (var i = 0; i < 256; i++)\n            {\n                if (partialInput[i] != 0)\n                    nonZeroCount++;\n            }\n\n            Frequency(partialInput, frequency);\n\n            for (int i = 0, m = 0; i < nonZeroCount; ++i)\n            {\n                var freq = (byte) frequency[i];\n                symbolTable[input[m + 1024]] = (char) freq;\n                partialInput[freq + 256] = m + 1;\n                m += partialInput[freq];\n                partialInput[freq + 512] = m;\n            }\n\n            var val = (byte) symbolTable[0];\n\n            if (len != 0)\n            {\n                do\n                {\n                    ref var firstValRef = ref partialInput[val + 256];\n                    output[count] = val;\n\n                    if (firstValRef >= partialInput[val + 512])\n                    {\n                        if (nonZeroCount-- > 0)\n                        {\n                            ShiftLeft(symbolTable, nonZeroCount);\n                            val = (byte) symbolTable[0];\n                        }\n                    }\n                    else\n                    {\n                        var idx = (char) input[firstValRef + 1024];\n                        firstValRef++;\n\n                        if (idx != 0)\n                        {\n                            ShiftLeft(symbolTable, idx);\n                            symbolTable[(byte) idx] = (char) val;\n                            val = (byte) symbolTable[0];\n                        }\n                    }\n\n                    count++;\n                } while (count < len);\n            }\n\n            return output;\n        }\n\n        static void Frequency(Span<int> input, Span<char> output)\n        {\n            Span<int> tmp = stackalloc int[256];\n            input.Slice(0, tmp.Length).CopyTo(tmp);\n\n            for (var i = 0; i < 256; i++)\n            {\n                uint value = 0;\n                byte index = 0;\n\n                for (var j = 0; j < 256; j++)\n                {\n                    if (tmp[j] > value)\n                    {\n                        index = (byte) j;\n                        value = (uint) tmp[j];\n                    }\n                }\n\n                if (value == 0)\n                    break;\n\n                output[i] = (char) index;\n                tmp[index] = 0;\n            }\n        }\n\n        static void ShiftLeft(Span<char> input, int max)\n        {\n            for (var i = 0; i < max; ++i)\n                input[i] = input[i + 1];\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/CalibrationInfo.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\n\nnamespace Ultima\n{\n    public sealed class CalibrationInfo\n    {\n        public byte[] Mask { get; private set; }\n        public byte[] Vals { get; private set; }\n        public byte[] DetX { get; private set; }\n        public byte[] DetY { get; private set; }\n        public byte[] DetZ { get; private set; }\n        public byte[] DetF { get; private set; }\n\n        public CalibrationInfo(byte[] mask, byte[] vals, byte[] detx, byte[] dety, byte[] detz, byte[] detf)\n        {\n            Mask = mask;\n            Vals = vals;\n            DetX = detx;\n            DetY = dety;\n            DetZ = detz;\n            DetF = detf;\n        }\n\n        private static byte[] ReadBytes(StreamReader ip)\n        {\n            string line = ip.ReadLine();\n\n            if (line == null)\n                return null;\n\n            byte[] buffer = new byte[(line.Length + 2) / 3];\n            int index = 0;\n\n            for (int i = 0; (i + 1) < line.Length; i += 3)\n            {\n                char ch = line[i + 0];\n                char cl = line[i + 1];\n\n                if (ch >= '0' && ch <= '9')\n                    ch -= '0';\n                else if (ch >= 'a' && ch <= 'f')\n                    ch -= (char) ('a' - 10);\n                else if (ch >= 'A' && ch <= 'F')\n                    ch -= (char) ('A' - 10);\n                else\n                    return null;\n\n                if (cl >= '0' && cl <= '9')\n                    cl -= '0';\n                else if (cl >= 'a' && cl <= 'f')\n                    cl -= (char) ('a' - 10);\n                else if (cl >= 'A' && cl <= 'F')\n                    cl -= (char) ('A' - 10);\n                else\n                    return null;\n\n                buffer[index++] = (byte) ((ch << 4) | cl);\n            }\n\n            return buffer;\n        }\n\n        private static CalibrationInfo[] m_DefaultList = new CalibrationInfo[]\n        {\n            new CalibrationInfo( //Post 7.0.4.0 (Andreew)\n                new byte[]\n                {\n                    0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,\n                    0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF\n                },\n                new byte[]\n                {\n                    0xFF, 0xD0, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x11, 0x8B,\n                    0x82, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x5B, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC\n                },\n                new byte[] {0x22, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x0C}, //x\n                new byte[] {0x22, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x08}, //y\n                new byte[] {0x22, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x04}, //z\n                new byte[] {0x22, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x10}), //f\n            new CalibrationInfo( /* (arul) 6.0.9.x+ : Calibrates both  */\n                new byte[]\n                {\n                    0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,\n                    0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF\n                },\n                new byte[]\n                {\n                    0xFF, 0xD0, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x11, 0x8B,\n                    0x82, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x5E, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x0D\n                },\n                new byte[] {0x1F, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x0C},\n                new byte[] {0x1F, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x08},\n                new byte[] {0x1F, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x04},\n                new byte[] {0x1F, 0x04, 0xFF, 0xFF, 0xFF, 0x04, 0x10}),\n            new CalibrationInfo( /* Facet */\n                new byte[] {0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},\n                new byte[] {0xA0, 0x00, 0x00, 0x00, 0x00, 0x84, 0xC0, 0x0F, 0x85, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x0D},\n                new byte[0],\n                new byte[0],\n                new byte[0],\n                new byte[] {0x01, 0x04, 0xFF, 0xFF, 0xFF, 0x01}\n            ),\n            new CalibrationInfo( /* Location */\n                new byte[]\n                {\n                    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00,\n                    0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00\n                },\n                new byte[]\n                {\n                    0x8B, 0x15, 0x00, 0x00, 0x00, 0x00, 0x83, 0xC4, 0x10, 0x66, 0x89, 0x5A, 0x00, 0xA1, 0x00, 0x00,\n                    0x00, 0x00, 0x66, 0x89, 0x78, 0x00, 0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x66, 0x89, 0x71, 0x00\n                },\n                new byte[] {0x02, 0x04, 0x04, 0x0C, 0x01, 0x02},\n                new byte[] {0x0E, 0x04, 0x04, 0x15, 0x01, 0x02},\n                new byte[] {0x18, 0x04, 0x04, 0x1F, 0x01, 0x02},\n                new byte[0]\n            ),\n            new CalibrationInfo( /* UO3D Only, calibrates both */\n                new byte[]\n                {\n                    0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,\n                    0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n                    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00\n                },\n                new byte[]\n                {\n                    0xA1, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x2E, 0x04, 0x01, 0x0F, 0xBF, 0x50, 0x00, 0x0F, 0xBF,\n                    0x48, 0x00, 0x52, 0x51, 0x0F, 0xBF, 0x50, 0x00, 0x52, 0x8D, 0x85, 0xE4, 0xFD, 0xFF, 0xFF, 0x68,\n                    0x00, 0x00, 0x00, 0x00, 0x50, 0xE8, 0x07, 0x44, 0x10, 0x00, 0x8A, 0x0D, 0x00, 0x00, 0x00, 0x00\n                },\n                new byte[] {0x01, 0x04, 0x04, 0x17, 0x01, 0x02},\n                new byte[] {0x01, 0x04, 0x04, 0x11, 0x01, 0x02},\n                new byte[] {0x01, 0x04, 0x04, 0x0D, 0x01, 0x02},\n                new byte[] {0x2C, 0x04, 0xFF, 0xFF, 0xFF, 0x01}\n            )\n        };\n\n        public static CalibrationInfo[] DefaultList\n        {\n            get { return m_DefaultList; }\n            set { m_DefaultList = value; }\n        }\n\n        public static CalibrationInfo[] GetList()\n        {\n            List<CalibrationInfo> list = new List<CalibrationInfo>();\n\n            string path = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);\n            path = Path.Combine(path, \"calibration.cfg\");\n\n            if (File.Exists(path))\n            {\n                using (StreamReader ip = new StreamReader(path))\n                {\n                    string line;\n\n                    while ((line = ip.ReadLine()) != null)\n                    {\n                        line = line.Trim();\n\n                        if (line.Equals(\"Begin\", StringComparison.OrdinalIgnoreCase))\n                        {\n                            byte[] mask, vals, detx, dety, detz, detf;\n\n                            if ((mask = ReadBytes(ip)) == null)\n                                continue;\n\n                            if ((vals = ReadBytes(ip)) == null)\n                                continue;\n\n                            if ((detx = ReadBytes(ip)) == null)\n                                continue;\n\n                            if ((dety = ReadBytes(ip)) == null)\n                                continue;\n\n                            if ((detz = ReadBytes(ip)) == null)\n                                continue;\n\n                            if ((detf = ReadBytes(ip)) == null)\n                                continue;\n\n                            list.Add(new CalibrationInfo(mask, vals, detx, dety, detz, detf));\n                        }\n                    }\n                }\n            }\n\n            list.AddRange(DefaultList);\n\n            return list.ToArray();\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Client.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.IO;\n\nnamespace Ultima\n{\n    /// <summary>\n    /// Provides methods to interact with the Ultima Online client.\n    /// </summary>\n    public sealed class Client\n    {\n        private const int WM_CHAR = 0x102;\n\n        private static ClientWindowHandle m_Handle = ClientWindowHandle.Invalid;\n\n        private static WindowProcessStream m_ProcStream;\n        private static LocationPointer m_LocationPointer;\n\n        private static bool m_Is_Iris2 = false;\n\n        private Client()\n        {\n        }\n\n        /// <summary>\n        /// Gets a <see cref=\"ProcessStream\" /> instance which can be used to read the memory. Null is returned if the Client is not running.\n        /// </summary>\n        public static ProcessStream ProcessStream\n        {\n            get\n            {\n                if (m_ProcStream == null || m_ProcStream.Window != Handle)\n                {\n                    if (Running)\n                        m_ProcStream = new WindowProcessStream(Handle);\n                    else\n                        m_ProcStream = null;\n                }\n\n                return m_ProcStream;\n            }\n        }\n\n        /// <summary>\n        /// Reads the current <paramref name=\"x\" />, <paramref name=\"y\" />, and <paramref name=\"z\" /> from memory based on a <see cref=\"Calibrate\">calibrated memory location</see>.\n        /// <seealso cref=\"Calibrate\" />\n        /// <seealso cref=\"ProcessStream\" />\n        /// <returns>True if the location was found, false if not</returns>\n        /// </summary>\n        public static bool FindLocation(ref int x, ref int y, ref int z, ref int facet)\n        {\n            LocationPointer lp = LocationPointer;\n            ProcessStream pc = ProcessStream;\n\n            if (pc == null || lp == null)\n                return false;\n\n            pc.BeginAccess();\n\n            if (lp.PointerX > 0)\n            {\n                pc.Seek(lp.PointerX, SeekOrigin.Begin);\n                x = Read(pc, lp.SizeX);\n            }\n\n            if (lp.PointerY > 0)\n            {\n                pc.Seek(lp.PointerY, SeekOrigin.Begin);\n                y = Read(pc, lp.SizeY);\n            }\n\n            if (lp.PointerZ > 0)\n            {\n                pc.Seek(lp.PointerZ, SeekOrigin.Begin);\n                z = Read(pc, lp.SizeZ);\n            }\n\n            if (lp.PointerF > 0)\n            {\n                pc.Seek(lp.PointerF, SeekOrigin.Begin);\n                facet = Read(pc, lp.SizeF);\n            }\n\n            pc.EndAccess();\n\n            return true;\n        }\n\n        public static int Read(ProcessStream pc, int bytes)\n        {\n            byte[] buffer = new byte[bytes];\n\n            pc.Read(buffer, 0, bytes);\n\n            switch (bytes)\n            {\n                case 1: return (sbyte) buffer[0];\n                case 2: return (short) (buffer[0] | (buffer[1] << 8));\n                case 4: return (int) (buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24));\n            }\n\n            int val = 0;\n            int bits = 0;\n\n            for (int i = 0; i < buffer.Length; ++i)\n            {\n                val |= buffer[i] << bits;\n                bits += 8;\n            }\n\n            return val;\n        }\n\n        public static int Search(ProcessStream pc, byte[] mask, byte[] vals)\n        {\n            if (mask.Length != vals.Length)\n                throw new Exception();\n\n            const int chunkSize = 4096;\n            int readSize = chunkSize + mask.Length;\n\n            pc.BeginAccess();\n\n            byte[] read = new byte[readSize];\n\n            for (int i = 0;; ++i)\n            {\n                pc.Seek(0x400000 + (i * chunkSize), SeekOrigin.Begin);\n                int count = pc.Read(read, 0, readSize);\n\n                if (count != readSize)\n                    break;\n\n                for (int j = 0; j < chunkSize; ++j)\n                {\n                    bool ok = true;\n\n                    for (int k = 0; ok && k < mask.Length; ++k)\n                        ok = ((read[j + k] & mask[k]) == vals[k]);\n\n                    if (ok)\n                    {\n                        pc.EndAccess();\n                        return 0x400000 + (i * chunkSize) + j;\n                    }\n                }\n            }\n\n            pc.EndAccess();\n            return 0;\n        }\n\n        public static int Search(ProcessStream pc, byte[] buffer)\n        {\n            const int chunkSize = 4096;\n            int readSize = chunkSize + buffer.Length;\n\n            pc.BeginAccess();\n\n            byte[] read = new byte[readSize];\n\n            for (int i = 0;; ++i)\n            {\n                pc.Seek(0x400000 + (i * chunkSize), SeekOrigin.Begin);\n                int count = pc.Read(read, 0, readSize);\n\n                if (count != readSize)\n                    break;\n\n                for (int j = 0; j < chunkSize; ++j)\n                {\n                    bool ok = true;\n\n                    for (int k = 0; ok && k < buffer.Length; ++k)\n                        ok = (buffer[k] == read[j + k]);\n\n                    if (ok)\n                    {\n                        pc.EndAccess();\n                        return 0x400000 + (i * chunkSize) + j;\n                    }\n                }\n            }\n\n            pc.EndAccess();\n            return 0;\n        }\n\n        /// <summary>\n        /// Attempts to calibrate the <see cref=\"FindLocation\" /> method based on an input <paramref name=\"x\" />, <paramref name=\"y\" />, and <paramref name=\"z\" />.\n        /// <seealso cref=\"FindLocation\" />\n        /// <seealso cref=\"ProcessStream\" />\n        /// </summary>\n        /// <returns>The calibrated memory location -or- 0 if it could not be found.</returns>\n        public static void Calibrate(int x, int y, int z)\n        {\n            m_LocationPointer = null;\n\n            ProcessStream pc = ProcessStream;\n\n            if (pc == null)\n                return;\n\n            byte[] buffer = new byte[12];\n\n            buffer[0] = (byte) z;\n            buffer[1] = (byte) (z >> 8);\n            buffer[2] = (byte) (z >> 16);\n            buffer[3] = (byte) (z >> 24);\n\n            buffer[4] = (byte) y;\n            buffer[5] = (byte) (y >> 8);\n            buffer[6] = (byte) (y >> 16);\n            buffer[7] = (byte) (y >> 24);\n\n            buffer[8] = (byte) x;\n            buffer[9] = (byte) (x >> 8);\n            buffer[10] = (byte) (x >> 16);\n            buffer[11] = (byte) (x >> 24);\n\n            int ptr = Search(pc, buffer);\n\n            if (ptr == 0)\n                return;\n\n            m_LocationPointer = new LocationPointer(ptr + 8, ptr + 4, ptr, 0, 4, 4, 4, 0);\n        }\n\n        /// <summary>\n        /// Attempts to automatically calibrate the <see cref=\"FindLocation\" /> method.\n        /// </summary>\n        /// <returns>The calibrated memory location -or- 0 if it could not be found.</returns>\n        public static void Calibrate()\n        {\n            Calibrate(CalibrationInfo.GetList());\n        }\n\n        /// <summary>\n        /// Attempts to automatically calibrate the <see cref=\"FindLocation\" /> method.\n        /// </summary>\n        /// <returns>The calibrated memory location -or- 0 if it could not be found.</returns>\n        public static void Calibrate(CalibrationInfo[] info)\n        {\n            m_LocationPointer = null;\n\n            ProcessStream pc = ProcessStream;\n\n            if (pc == null)\n                return;\n\n            int ptrX = 0, sizeX = 0;\n            int ptrY = 0, sizeY = 0;\n            int ptrZ = 0, sizeZ = 0;\n            int ptrF = 0, sizeF = 0;\n\n            for (int i = 0; i < info.Length; ++i)\n            {\n                CalibrationInfo ci = info[i];\n\n                int ptr = Search(pc, ci.Mask, ci.Vals);\n\n                if (ptr == 0)\n                    continue;\n\n                if (ptrX == 0 && ci.DetX.Length > 0)\n                    GetCoordDetails(pc, ptr, ci.DetX, out ptrX, out sizeX);\n\n                if (ptrY == 0 && ci.DetY.Length > 0)\n                    GetCoordDetails(pc, ptr, ci.DetY, out ptrY, out sizeY);\n\n                if (ptrZ == 0 && ci.DetZ.Length > 0)\n                    GetCoordDetails(pc, ptr, ci.DetZ, out ptrZ, out sizeZ);\n\n                if (ptrF == 0 && ci.DetF.Length > 0)\n                    GetCoordDetails(pc, ptr, ci.DetF, out ptrF, out sizeF);\n\n                if (ptrX != 0 && ptrY != 0 && ptrZ != 0 && ptrF != 0)\n                    break;\n            }\n\n            if (ptrX != 0 || ptrY != 0 || ptrZ != 0 || ptrF != 0)\n                m_LocationPointer = new LocationPointer(ptrX, ptrY, ptrZ, ptrF, sizeX, sizeY, sizeZ, sizeF);\n        }\n\n        private static void GetCoordDetails(ProcessStream pc, int ptr, byte[] dets, out int coordPointer,\n            out int coordSize)\n        {\n            pc.Seek(ptr + dets[0], SeekOrigin.Begin);\n            coordPointer = Read(pc, dets[1]);\n\n            if (dets[2] < 0xFF)\n            {\n                pc.Seek(coordPointer, SeekOrigin.Begin);\n                coordPointer = Read(pc, dets[2]);\n            }\n\n            if (dets[3] < 0xFF)\n            {\n                pc.Seek(ptr + dets[3], SeekOrigin.Begin);\n                coordPointer += Read(pc, dets[4]);\n            }\n\n            /*\n             * arul:\n             *\tThe variable 'dets[6]' represents an offset into the struct that holds an info about players current location.\n             *\tAdded not to break functionality with the older clients (I hope).\n             * \n             * The struct looks as follows: \n             * \n             *  DWORD fLoggedIn; \n             *\tDWORD Z;\n             *  DWORD Y;\n             *\tDWORD X;\n             *\tDWORD Facet;  \n             *  \n             */\n            if (dets.Length == 7 && dets[6] < 0xFF)\n            {\n                coordPointer += dets[6];\n            }\n\n            coordSize = dets[5];\n        }\n\n        /// <summary>\n        /// Gets or sets the memory location currently used for the <see cref=\"FindLocation\" /> method.\n        /// <seealso cref=\"FindLocation\" />\n        /// <seealso cref=\"Calibrate\" />\n        /// </summary>\n        public static LocationPointer LocationPointer\n        {\n            get { return m_LocationPointer; }\n            set { m_LocationPointer = value; }\n        }\n\n        /// <summary>\n        /// Gets the current window handle. A value of <c>ClientHandle.Invalid</c> is returned if the Client is not currently running.\n        /// <seealso cref=\"Running\" />\n        /// </summary>\n        public static ClientWindowHandle Handle\n        {\n            get\n            {\n                if (NativeMethods.IsWindow(m_Handle) == 0)\n                    m_Handle = FindHandle();\n\n                return m_Handle;\n            }\n        }\n\n        /// <summary>\n        /// Whether or not the Client is currently running.\n        /// <seealso cref=\"ClientHandle\" />\n        /// </summary>\n        public static bool Running\n        {\n            get { return (!Handle.IsInvalid); }\n        }\n\n        /// <summary>\n        /// Is Client Iris2\n        /// </summary>\n        public static bool Is_Iris2\n        {\n            get { return m_Is_Iris2; }\n            set { m_Is_Iris2 = value; }\n        }\n\n        private static void SendChar(ClientWindowHandle hWnd, char c)\n        {\n            int value = (int) c;\n            int lParam = 1 | ((NativeMethods.OemKeyScan(value) & 0xFF) << 16) | (0x3 << 30);\n\n            NativeMethods.PostMessage(hWnd, WM_CHAR, value, lParam);\n        }\n\n        /// <summary>\n        /// Brings the Client window to the foreground.\n        /// </summary>\n        /// <returns>True if the Client is running, false if not.</returns>\n        public static bool BringToTop()\n        {\n            ClientWindowHandle hWnd = Handle;\n\n            if (!hWnd.IsInvalid)\n            {\n                NativeMethods.SetForegroundWindow(hWnd);\n\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Sends a <see cref=\"String\" /> of characters (<paramref name=\"text\" />) to the Client. The string is followed by a carriage return and line feed.\n        /// </summary>\n        /// <returns>True if the Client is running, false if not.</returns>\n        public static bool SendText(string text)\n        {\n            ClientWindowHandle hWnd = Handle;\n\n            if (!hWnd.IsInvalid)\n            {\n                for (int i = 0; i < text.Length; ++i)\n                    SendChar(hWnd, text[i]);\n\n                SendChar(hWnd, '\\r');\n                SendChar(hWnd, '\\n');\n\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        /// <summary>\n        /// Sends a formatted <see cref=\"String\" /> of characters to the Client. The string is followed by a carriage return and line feed. The format functionality is the same as <see cref=\"String.Format\">String.Format</see>.\n        /// </summary>\n        /// <returns>True if the Client is running, false if not.</returns>\n        public static bool SendText(string format, params object[] args)\n        {\n            return SendText(String.Format(format, args));\n        }\n\n\n        private static ClientWindowHandle FindHandle()\n        {\n            ClientWindowHandle hWnd;\n\n            if (NativeMethods.IsWindow(hWnd = NativeMethods.FindWindowA(\"Ultima Online\", null)) != 0)\n                return hWnd;\n\n            if (NativeMethods.IsWindow(hWnd = NativeMethods.FindWindowA(\"Ultima Online Third Dawn\", null)) != 0)\n                return hWnd;\n            if (NativeMethods.IsWindow(hWnd = NativeMethods.FindWindowA(\"OgreGLWindow\", null)) != 0)\n            {\n                m_Is_Iris2 = true;\n                return hWnd;\n            }\n\n\n            return ClientWindowHandle.Invalid;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/ClientHandles.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing Microsoft.Win32.SafeHandles;\n\nnamespace Ultima\n{\n    public class ClientWindowHandle : CriticalHandleZeroOrMinusOneIsInvalid\n    {\n        public static ClientWindowHandle Invalid = new ClientWindowHandle(new IntPtr(-1));\n\n        public ClientWindowHandle()\n        {\n        }\n\n        public ClientWindowHandle(IntPtr value)\n        {\n            handle = value;\n        }\n\n        protected override bool ReleaseHandle()\n        {\n            if (!this.IsClosed)\n                return ReleaseHandle();\n            return true;\n        }\n    }\n\n    public class ClientProcessHandle : CriticalHandleZeroOrMinusOneIsInvalid\n    {\n        public static ClientProcessHandle Invalid = new ClientProcessHandle(new IntPtr(-1));\n\n        public ClientProcessHandle()\n            : base()\n        {\n        }\n\n        public ClientProcessHandle(IntPtr value)\n            : base()\n        {\n            handle = value;\n        }\n\n        protected override bool ReleaseHandle()\n        {\n            return NativeMethods.CloseHandle(this) == 0;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/FileIndex.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\nnamespace Ultima\n{\n    public sealed class FileIndex\n    {\n        public Entry3D[] Index { get; private set; }\n        public Stream Stream { get; private set; }\n        public long IdxLength { get; private set; }\n        private string MulPath;\n\n        public Stream Seek(int index, out int length, out int extra, out bool patched)\n        {\n            if (index < 0 || index >= Index.Length)\n            {\n                length = extra = 0;\n                patched = false;\n                return null;\n            }\n\n            Entry3D e = Index[index];\n\n            if (e.lookup < 0)\n            {\n                length = extra = 0;\n                patched = false;\n                return null;\n            }\n\n            length = e.length & 0x7FFFFFFF;\n            extra = e.extra;\n\n            if ((e.length & (1 << 31)) != 0)\n            {\n                patched = true;\n                Verdata.Seek(e.lookup);\n                return Verdata.Stream;\n            }\n\n            if (e.length < 0)\n            {\n                length = extra = 0;\n                patched = false;\n                return null;\n            }\n\n            if ((Stream == null) || (!Stream.CanRead) || (!Stream.CanSeek))\n            {\n                if (MulPath == null)\n                    Stream = null;\n                else\n                    Stream = new FileStream(MulPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n            }\n\n            if (Stream == null)\n            {\n                length = extra = 0;\n                patched = false;\n                return null;\n            }\n            else if (Stream.Length < e.lookup)\n            {\n                length = extra = 0;\n                patched = false;\n                return null;\n            }\n\n            patched = false;\n\n            Stream.Seek(e.lookup, SeekOrigin.Begin);\n            return Stream;\n        }\n\n        public bool Valid(int index, out int length, out int extra, out bool patched)\n        {\n            if (index < 0 || index >= Index.Length)\n            {\n                length = extra = 0;\n                patched = false;\n                return false;\n            }\n\n            Entry3D e = Index[index];\n\n            if (e.lookup < 0)\n            {\n                length = extra = 0;\n                patched = false;\n                return false;\n            }\n\n            length = e.length & 0x7FFFFFFF;\n            extra = e.extra;\n\n            if ((e.length & (1 << 31)) != 0)\n            {\n                patched = true;\n                return true;\n            }\n\n            if (e.length < 0)\n            {\n                length = extra = 0;\n                patched = false;\n                return false;\n            }\n\n            if ((MulPath == null) || !File.Exists(MulPath))\n            {\n                length = extra = 0;\n                patched = false;\n                return false;\n            }\n\n            if ((Stream == null) || (!Stream.CanRead) || (!Stream.CanSeek))\n            {\n                Stream = new FileStream(MulPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n            }\n\n            if (Stream.Length < e.lookup)\n            {\n                length = extra = 0;\n                patched = false;\n                return false;\n            }\n\n            patched = false;\n\n            return true;\n        }\n\n        public FileIndex(string idxFile, string mulFile, int length, int file) : this(idxFile, mulFile, null, length,\n            file, \".dat\", -1, false)\n        {\n        }\n\n        public FileIndex(string idxFile, string mulFile, string uopFile, int length, int file, string uopEntryExtension,\n            int idxLength, bool hasExtra)\n        {\n            Index = new Entry3D[length];\n\n            string idxPath = null;\n            MulPath = null;\n            string uopPath = null;\n\n            if (Files.MulPath == null)\n                Files.LoadMulPath();\n\n            if (Files.MulPath.Count > 0)\n            {\n                idxPath = Files.MulPath[idxFile.ToLower()];\n                MulPath = Files.MulPath[mulFile.ToLower()];\n\n                if (!String.IsNullOrEmpty(uopFile) && Files.MulPath.ContainsKey(uopFile.ToLower()))\n                    uopPath = Files.MulPath[uopFile.ToLower()];\n\n                if (String.IsNullOrEmpty(idxPath))\n                {\n                    idxPath = null;\n                }\n                else\n                {\n                    if (String.IsNullOrEmpty(Path.GetDirectoryName(idxPath)))\n                        idxPath = Path.Combine(Files.RootDir, idxPath);\n\n                    if (!File.Exists(idxPath))\n                        idxPath = null;\n                }\n\n                if (String.IsNullOrEmpty(MulPath))\n                {\n                    MulPath = null;\n                }\n                else\n                {\n                    if (String.IsNullOrEmpty(Path.GetDirectoryName(MulPath)))\n                        MulPath = Path.Combine(Files.RootDir, MulPath);\n\n                    if (!File.Exists(MulPath))\n                        MulPath = null;\n                }\n\n                if (String.IsNullOrEmpty(uopPath))\n                {\n                    uopPath = null;\n                }\n                else\n                {\n                    if (String.IsNullOrEmpty(Path.GetDirectoryName(uopPath)))\n                        uopPath = Path.Combine(Files.RootDir, uopPath);\n\n                    if (!File.Exists(uopPath))\n                        uopPath = null;\n                    else\n                        MulPath = uopPath;\n                }\n            }\n\n            /* UOP files support code, written by Wyatt (c) www.ruosi.org\n             * idxLength variable was added for compatibility with legacy code for art (see art.cs)\n             * At the moment the only UOP file having entries with extra field is gumpartlegacy.uop,\n             * and it's two dwords in the beginning of the entry.\n             * It's possible that UOP can include some entries with unknown hash: not really unknown for me, but\n             * not useful for reading legacy entries. That's why i removed unknown hash exception throwing from this code\n             */\n            if (MulPath != null && MulPath.EndsWith(\".uop\"))\n            {\n                using (FileStream index = new FileStream(MulPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    Stream = new FileStream(MulPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n\n                    FileInfo fi = new FileInfo(MulPath);\n                    string uopPattern = fi.Name.Replace(fi.Extension, \"\").ToLowerInvariant();\n\n                    using (BinaryReader br = new BinaryReader(Stream))\n                    {\n                        br.BaseStream.Seek(0, SeekOrigin.Begin);\n\n                        if (br.ReadInt32() != 0x50594D)\n                            throw new ArgumentException(\"Bad UOP file.\");\n\n                        br.ReadInt64(); // version + signature\n                        long nextBlock = br.ReadInt64();\n                        br.ReadInt32(); // block capacity\n                        int count = br.ReadInt32();\n\n                        if (idxLength > 0)\n                            IdxLength = idxLength * 12;\n\n                        Dictionary<ulong, int> hashes = new Dictionary<ulong, int>();\n\n                        for (int i = 0; i < length; i++)\n                        {\n                            string entryName = $\"build/{uopPattern}/{i:D8}{uopEntryExtension}\";\n                            ulong hash = HashFileName(entryName);\n\n                            if (!hashes.ContainsKey(hash))\n                                hashes.Add(hash, i);\n                        }\n\n                        br.BaseStream.Seek(nextBlock, SeekOrigin.Begin);\n\n                        do\n                        {\n                            int filesCount = br.ReadInt32();\n                            nextBlock = br.ReadInt64();\n\n                            for (int i = 0; i < filesCount; i++)\n                            {\n                                long offset = br.ReadInt64();\n                                int headerLength = br.ReadInt32();\n                                int compressedLength = br.ReadInt32();\n                                int decompressedLength = br.ReadInt32();\n                                ulong hash = br.ReadUInt64();\n                                br.ReadUInt32(); // Adler32\n                                short flag = br.ReadInt16();\n\n                                int entryLength = flag == 1 ? compressedLength : decompressedLength;\n\n                                if (offset == 0)\n                                    continue;\n\n                                int idx;\n                                if (hashes.TryGetValue(hash, out idx))\n                                {\n                                    if (idx < 0 || idx > Index.Length)\n                                        throw new IndexOutOfRangeException(\n                                            \"hashes dictionary and files collection have different count of entries!\");\n\n                                    Index[idx].lookup = (int) (offset + headerLength);\n                                    Index[idx].length = entryLength;\n\n                                    if (hasExtra)\n                                    {\n                                        long curPos = br.BaseStream.Position;\n\n                                        br.BaseStream.Seek(offset + headerLength, SeekOrigin.Begin);\n\n                                        byte[] extra = br.ReadBytes(8);\n\n                                        short extra1 =\n                                            (short) ((extra[3] << 24) | (extra[2] << 16) | (extra[1] << 8) | extra[0]);\n                                        short extra2 =\n                                            (short) ((extra[7] << 24) | (extra[6] << 16) | (extra[5] << 8) | extra[4]);\n\n                                        Index[idx].lookup += 8;\n                                        Index[idx].extra = extra1 << 16 | extra2;\n\n                                        br.BaseStream.Seek(curPos, SeekOrigin.Begin);\n                                    }\n                                }\n                            }\n                        } while (br.BaseStream.Seek(nextBlock, SeekOrigin.Begin) != 0);\n                    }\n                }\n            }\n            else if ((idxPath != null) && (MulPath != null))\n            {\n                using (FileStream index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    Stream = new FileStream(MulPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n                    int count = (int) (index.Length / 12);\n                    IdxLength = index.Length;\n                    GCHandle gc = GCHandle.Alloc(Index, GCHandleType.Pinned);\n                    byte[] buffer = new byte[index.Length];\n                    index.Read(buffer, 0, (int) index.Length);\n                    Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(), (int) Math.Min(IdxLength, length * 12));\n                    gc.Free();\n                    for (int i = count; i < length; ++i)\n                    {\n                        Index[i].lookup = -1;\n                        Index[i].length = -1;\n                        Index[i].extra = -1;\n                    }\n                }\n            }\n            else\n            {\n                Stream = null;\n                return;\n            }\n\n            Entry5D[] patches = Verdata.Patches;\n\n            if (file > -1)\n            {\n                for (int i = 0; i < patches.Length; ++i)\n                {\n                    Entry5D patch = patches[i];\n\n                    if (patch.file == file && patch.index >= 0 && patch.index < length)\n                    {\n                        Index[patch.index].lookup = patch.lookup;\n                        Index[patch.index].length = patch.length | (1 << 31);\n                        Index[patch.index].extra = patch.extra;\n                    }\n                }\n            }\n        }\n\n        public FileIndex(string idxFile, string mulFile, int file)\n        {\n            string idxPath = null;\n            MulPath = null;\n            if (Files.MulPath == null)\n                Files.LoadMulPath();\n            if (Files.MulPath.Count > 0)\n            {\n                idxPath = Files.MulPath[idxFile.ToLower()];\n                MulPath = Files.MulPath[mulFile.ToLower()];\n                if (String.IsNullOrEmpty(idxPath))\n                    idxPath = null;\n                else\n                {\n                    if (String.IsNullOrEmpty(Path.GetDirectoryName(idxPath)))\n                        idxPath = Path.Combine(Files.RootDir, idxPath);\n                    if (!File.Exists(idxPath))\n                        idxPath = null;\n                }\n\n                if (String.IsNullOrEmpty(MulPath))\n                    MulPath = null;\n                else\n                {\n                    if (String.IsNullOrEmpty(Path.GetDirectoryName(MulPath)))\n                        MulPath = Path.Combine(Files.RootDir, MulPath);\n                    if (!File.Exists(MulPath))\n                        MulPath = null;\n                }\n            }\n\n            if ((idxPath != null) && (MulPath != null))\n            {\n                using (FileStream index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    Stream = new FileStream(MulPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n                    int count = (int) (index.Length / 12);\n                    IdxLength = index.Length;\n                    Index = new Entry3D[count];\n                    GCHandle gc = GCHandle.Alloc(Index, GCHandleType.Pinned);\n                    byte[] buffer = new byte[index.Length];\n                    index.Read(buffer, 0, (int) index.Length);\n                    Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(), (int) index.Length);\n                    gc.Free();\n                }\n            }\n            else\n            {\n                Stream = null;\n                Index = new Entry3D[1];\n                return;\n            }\n\n            Entry5D[] patches = Verdata.Patches;\n\n            if (file > -1)\n            {\n                for (int i = 0; i < patches.Length; ++i)\n                {\n                    Entry5D patch = patches[i];\n\n                    if (patch.file == file && patch.index >= 0 && patch.index < Index.Length)\n                    {\n                        Index[patch.index].lookup = patch.lookup;\n                        Index[patch.index].length = patch.length | (1 << 31);\n                        Index[patch.index].extra = patch.extra;\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Method for calculating entry hash by it's name.\n        /// Taken from Mythic.Package.dll\n        /// </summary>\n        /// <param name=\"s\"></param>\n        /// <returns></returns>\n        public static ulong HashFileName(string s)\n        {\n            uint eax, ecx, edx, ebx, esi, edi;\n\n            eax = ecx = edx = ebx = esi = edi = 0;\n            ebx = edi = esi = (uint) s.Length + 0xDEADBEEF;\n\n            int i = 0;\n\n            for (i = 0; i + 12 < s.Length; i += 12)\n            {\n                edi = (uint) ((s[i + 7] << 24) | (s[i + 6] << 16) | (s[i + 5] << 8) | s[i + 4]) + edi;\n                esi = (uint) ((s[i + 11] << 24) | (s[i + 10] << 16) | (s[i + 9] << 8) | s[i + 8]) + esi;\n                edx = (uint) ((s[i + 3] << 24) | (s[i + 2] << 16) | (s[i + 1] << 8) | s[i]) - esi;\n\n                edx = (edx + ebx) ^ (esi >> 28) ^ (esi << 4);\n                esi += edi;\n                edi = (edi - edx) ^ (edx >> 26) ^ (edx << 6);\n                edx += esi;\n                esi = (esi - edi) ^ (edi >> 24) ^ (edi << 8);\n                edi += edx;\n                ebx = (edx - esi) ^ (esi >> 16) ^ (esi << 16);\n                esi += edi;\n                edi = (edi - ebx) ^ (ebx >> 13) ^ (ebx << 19);\n                ebx += esi;\n                esi = (esi - edi) ^ (edi >> 28) ^ (edi << 4);\n                edi += ebx;\n            }\n\n            if (s.Length - i > 0)\n            {\n                switch (s.Length - i)\n                {\n                    case 12:\n                        esi += (uint) s[i + 11] << 24;\n                        goto case 11;\n                    case 11:\n                        esi += (uint) s[i + 10] << 16;\n                        goto case 10;\n                    case 10:\n                        esi += (uint) s[i + 9] << 8;\n                        goto case 9;\n                    case 9:\n                        esi += (uint) s[i + 8];\n                        goto case 8;\n                    case 8:\n                        edi += (uint) s[i + 7] << 24;\n                        goto case 7;\n                    case 7:\n                        edi += (uint) s[i + 6] << 16;\n                        goto case 6;\n                    case 6:\n                        edi += (uint) s[i + 5] << 8;\n                        goto case 5;\n                    case 5:\n                        edi += (uint) s[i + 4];\n                        goto case 4;\n                    case 4:\n                        ebx += (uint) s[i + 3] << 24;\n                        goto case 3;\n                    case 3:\n                        ebx += (uint) s[i + 2] << 16;\n                        goto case 2;\n                    case 2:\n                        ebx += (uint) s[i + 1] << 8;\n                        goto case 1;\n                    case 1:\n                        ebx += (uint) s[i];\n                        break;\n                }\n\n                esi = (esi ^ edi) - ((edi >> 18) ^ (edi << 14));\n                ecx = (esi ^ ebx) - ((esi >> 21) ^ (esi << 11));\n                edi = (edi ^ ecx) - ((ecx >> 7) ^ (ecx << 25));\n                esi = (esi ^ edi) - ((edi >> 16) ^ (edi << 16));\n                edx = (esi ^ ecx) - ((esi >> 28) ^ (esi << 4));\n                edi = (edi ^ edx) - ((edx >> 18) ^ (edx << 14));\n                eax = (esi ^ edi) - ((edi >> 8) ^ (edi << 24));\n\n                return ((ulong) edi << 32) | eax;\n            }\n\n            return ((ulong) esi << 32) | eax;\n        }\n    }\n\n    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public struct Entry3D\n    {\n        public int lookup;\n        public int length;\n        public int extra;\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Files.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Configuration;\nusing System.IO;\nusing Assistant;\nusing Microsoft.Win32;\n\nnamespace Ultima\n{\n    public sealed class Files\n    {\n        public delegate void FileSaveHandler();\n\n        public static event FileSaveHandler FileSaveEvent;\n\n        public static void FireFileSaveEvent()\n        {\n            if (FileSaveEvent != null)\n                FileSaveEvent();\n        }\n\n        private static bool m_CacheData = true;\n        private static bool m_UseHashFile = false;\n        private static Dictionary<string, string> m_MulPath;\n        private static string m_Directory;\n        private static string m_RootDir;\n\n        /// <summary>\n        /// Should loaded Data be cached\n        /// </summary>\n        public static bool CacheData\n        {\n            get { return m_CacheData; }\n            set { m_CacheData = value; }\n        }\n\n        /// <summary>\n        /// Should a Hashfile be used to speed up loading\n        /// </summary>\n        public static bool UseHashFile\n        {\n            get { return m_UseHashFile; }\n            set { m_UseHashFile = value; }\n        }\n\n        /// <summary>\n        /// Contains the path infos\n        /// </summary>\n        public static Dictionary<string, string> MulPath\n        {\n            get { return m_MulPath; }\n            set { m_MulPath = value; }\n        }\n\n        /// <summary>\n        /// Gets a list of paths to the Client's data files.\n        /// </summary>\n        public static string Directory\n        {\n            get { return m_Directory; }\n        }\n\n        /// <summary>\n        /// Contains the rootDir (so relative values are possible for <see cref=\"MulPath\"/>\n        /// </summary>\n        public static string RootDir\n        {\n            get { return m_RootDir; }\n            set { m_RootDir = value; }\n        }\n\n        private static string[] m_Files = new string[]\n        {\n            \"anim.idx\",\n            \"anim.mul\",\n            \"anim2.idx\",\n            \"anim2.mul\",\n            \"anim3.idx\",\n            \"anim3.mul\",\n            \"anim4.idx\",\n            \"anim4.mul\",\n            \"anim5.idx\",\n            \"anim5.mul\",\n            \"animdata.mul\",\n            \"art.mul\",\n            \"artidx.mul\",\n            \"artlegacymul.uop\",\n            \"body.def\",\n            \"bodyconv.def\",\n            \"client.exe\",\n            \"cliloc.custom1\",\n            \"cliloc.custom2\",\n            \"cliloc.deu\",\n            \"cliloc.enu\",\n            \"equipconv.def\",\n            \"facet00.mul\",\n            \"facet01.mul\",\n            \"facet02.mul\",\n            \"facet03.mul\",\n            \"facet04.mul\",\n            \"facet05.mul\",\n            \"fonts.mul\",\n            \"gump.def\",\n            \"gumpart.mul\",\n            \"gumpidx.mul\",\n            \"gumpartlegacymul.uop\",\n            \"hues.mul\",\n            \"light.mul\",\n            \"lightidx.mul\",\n            \"map0.mul\",\n            \"map1.mul\",\n            \"map2.mul\",\n            \"map3.mul\",\n            \"map4.mul\",\n            \"map5.mul\",\n            \"map0legacymul.uop\",\n            \"map1legacymul.uop\",\n            \"map2legacymul.uop\",\n            \"map3legacymul.uop\",\n            \"map4legacymul.uop\",\n            \"map5legacymul.uop\",\n            \"mapdif0.mul\",\n            \"mapdif1.mul\",\n            \"mapdif2.mul\",\n            \"mapdif3.mul\",\n            \"mapdif4.mul\",\n            \"mapdifl0.mul\",\n            \"mapdifl1.mul\",\n            \"mapdifl2.mul\",\n            \"mapdifl3.mul\",\n            \"mapdifl4.mul\",\n            \"mobtypes.txt\",\n            \"multi.idx\",\n            \"multi.mul\",\n            \"multimap.rle\",\n            \"radarcol.mul\",\n            \"skillgrp.mul\",\n            \"skills.idx\",\n            \"skills.mul\",\n            \"sound.def\",\n            \"sound.mul\",\n            \"soundidx.mul\",\n            \"soundlegacymul.uop\",\n            \"speech.mul\",\n            \"stadif0.mul\",\n            \"stadif1.mul\",\n            \"stadif2.mul\",\n            \"stadif3.mul\",\n            \"stadif4.mul\",\n            \"stadifi0.mul\",\n            \"stadifi1.mul\",\n            \"stadifi2.mul\",\n            \"stadifi3.mul\",\n            \"stadifi4.mul\",\n            \"stadifl0.mul\",\n            \"stadifl1.mul\",\n            \"stadifl2.mul\",\n            \"stadifl3.mul\",\n            \"stadifl4.mul\",\n            \"staidx0.mul\",\n            \"staidx1.mul\",\n            \"staidx2.mul\",\n            \"staidx3.mul\",\n            \"staidx4.mul\",\n            \"staidx5.mul\",\n            \"statics0.mul\",\n            \"statics1.mul\",\n            \"statics2.mul\",\n            \"statics3.mul\",\n            \"statics4.mul\",\n            \"statics5.mul\",\n            \"texidx.mul\",\n            \"texmaps.mul\",\n            \"tiledata.mul\",\n            \"unifont.mul\",\n            \"unifont1.mul\",\n            \"unifont2.mul\",\n            \"unifont3.mul\",\n            \"unifont4.mul\",\n            \"unifont5.mul\",\n            \"unifont6.mul\",\n            \"unifont7.mul\",\n            \"unifont8.mul\",\n            \"unifont9.mul\",\n            \"unifont10.mul\",\n            \"unifont11.mul\",\n            \"unifont12.mul\",\n            \"uotd.exe\",\n            \"verdata.mul\"\n        };\n\n\n        /// <summary>\n        /// ReReads Registry Client dir\n        /// </summary>\n        public static void ReLoadDirectory()\n        {\n            m_Directory = LoadDirectory();\n        }\n\n        /// <summary>\n        /// Fills <see cref=\"MulPath\"/> with <see cref=\"Files.Directory\"/>\n        /// </summary>\n        public static void LoadMulPath()\n        {\n            m_MulPath = new Dictionary<string, string>();\n            m_RootDir = Directory;\n            if (m_RootDir == null)\n                m_RootDir = \"\";\n            foreach (string file in m_Files)\n            {\n                string filePath = Path.Combine(m_RootDir, file);\n                if (File.Exists(filePath))\n                    m_MulPath[file] = file;\n                else if (File.Exists(Path.Combine(m_RootDir, char.ToUpper(file[0]) + file.Substring(1))))\n                    m_MulPath[file] = Path.Combine(m_RootDir, char.ToUpper(file[0]) + file.Substring(1));\n                else\n                    m_MulPath[file] = \"\";\n            }\n        }\n\n        /// <summary>\n        /// ReSets <see cref=\"MulPath\"/> with given path\n        /// </summary>\n        /// <param name=\"path\"></param>\n        public static void SetMulPath(string path)\n        {\n            m_RootDir = path;\n            foreach (string file in m_Files)\n            {\n                string filePath;\n                if (!String.IsNullOrEmpty(m_MulPath[file])) //file was set\n                {\n                    if (String.IsNullOrEmpty(Path.GetDirectoryName(m_MulPath[file]))) //and relative\n                    {\n                        filePath = Path.Combine(m_RootDir, m_MulPath[file]);\n                        if (File.Exists(filePath)) // exists in new Root?\n                        {\n                            m_MulPath[file] = filePath;\n                            continue;\n                        }\n                    }\n                    else // absolut dir ignore\n                        continue;\n                }\n\n                filePath = Path.Combine(m_RootDir, file); //file was not set, or relative and non existent\n                if (File.Exists(filePath))\n                    m_MulPath[file] = file;\n                else\n                    m_MulPath[file] = \"\";\n            }\n        }\n\n        /// <summary>\n        /// Sets <see cref=\"MulPath\"/> key to path\n        /// </summary>\n        /// <param name=\"path\"></param>\n        /// <param name=\"key\"></param>\n        public static void SetMulPath(string path, string key)\n        {\n            MulPath[key] = path;\n        }\n\n        /// <summary>\n        /// Looks up a given <paramref name=\"file\" /> in <see cref=\"Files.MulPath\"/>\n        /// </summary>\n        /// <returns>The absolute path to <paramref name=\"file\" /> -or- <c>null</c> if <paramref name=\"file\" /> was not found.</returns>\n        public static string GetFilePath(string file)\n        {\n            if (MulPath.Count > 0)\n            {\n                string path = \"\";\n                if (MulPath.ContainsKey(file.ToLower()))\n                    path = MulPath[file.ToLower()];\n                if (String.IsNullOrEmpty(path))\n                    return null;\n                if (String.IsNullOrEmpty(Path.GetDirectoryName(path)))\n                    path = Path.Combine(m_RootDir, path);\n                if (File.Exists(path))\n                    return path;\n            }\n\n            return null;\n        }\n\n        internal static string GetFilePath(string format, params object[] args)\n        {\n            return GetFilePath(String.Format(format, args));\n        }\n\n        static readonly string[] knownRegkeys = new string[]\n        {\n            @\"Origin Worlds Online\\Ultima Online\\1.0\",\n            @\"Origin Worlds Online\\Ultima Online Third Dawn\\1.0\",\n            @\"EA GAMES\\Ultima Online Samurai Empire\",\n            @\"EA GAMES\\Ultima Online Samurai Empire\\1.0\",\n            @\"EA GAMES\\Ultima Online Samurai Empire\\1.00.0000\",\n            @\"EA GAMES\\Ultima Online: Samurai Empire\\1.0\",\n            @\"EA GAMES\\Ultima Online: Samurai Empire\\1.00.0000\",\n            @\"EA Games\\Ultima Online: Mondain's Legacy\",\n            @\"EA Games\\Ultima Online: Mondain's Legacy\\1.0\",\n            @\"EA Games\\Ultima Online: Mondain's Legacy\\1.00.0000\",\n            @\"Origin Worlds Online\\Ultima Online Samurai Empire BETA\\2d\\1.0\",\n            @\"Origin Worlds Online\\Ultima Online Samurai Empire BETA\\3d\\1.0\",\n            @\"Origin Worlds Online\\Ultima Online Samurai Empire\\2d\\1.0\",\n            @\"Origin Worlds Online\\Ultima Online Samurai Empire\\3d\\1.0\",\n            @\"Origin Worlds Online\\Ultima Online\\KR Legacy Beta\",\n            @\"Electronic Arts\\EA Games\\Ultima Online Stygian Abyss Classic\",\n            @\"Electronic Arts\\EA Games\\Ultima Online Classic\",\n        };\n\n        static readonly string[] knownRegPathkeys = new string[]\n        {\n            \"ExePath\",\n            \"Install Dir\",\n            \"InstallDir\"\n        };\n\n        private static string LoadDirectory()\n        {\n            string dir = Config.GetAppSetting<string>(\"UODataDir\");\n\n            // If they're using the ClassicUO client, pull the UO data dir from the plugin\n            if (!Assistant.Client.IsOSI)\n            {\n                dir = Assistant.Client.Instance.GetUoFilePath();\n            }\n\n\n            if (string.IsNullOrEmpty(dir) || !System.IO.Directory.Exists(dir)\n            ) // If the path in the config looks bad, try the registry as a fallback\n            {\n                for (int i = knownRegkeys.Length - 1; i >= 0; i--)\n                {\n                    string exePath;\n\n                    if (Environment.Is64BitOperatingSystem)\n                        exePath = GetPath($@\"Wow6432Node\\{knownRegkeys[i]}\");\n                    else\n                        exePath = GetPath(knownRegkeys[i]);\n\n                    if (exePath != null)\n                    {\n                        dir = exePath;\n                        break;\n                    }\n                }\n            }\n\n            return dir;\n        }\n\n        private static string GetPath(string regkey)\n        {\n            try\n            {\n                RegistryKey key = Registry.LocalMachine.OpenSubKey($@\"SOFTWARE\\{regkey}\");\n\n                if (key == null)\n                {\n                    key = Registry.CurrentUser.OpenSubKey($@\"SOFTWARE\\{regkey}\");\n\n                    if (key == null)\n                        return null;\n                }\n\n                string path = null;\n                foreach (string pathkey in knownRegPathkeys)\n                {\n                    path = key.GetValue(pathkey) as string;\n\n                    if ((path == null) || (path.Length <= 0))\n                        continue;\n\n                    if (pathkey == \"InstallDir\")\n                        path = path + @\"\\\";\n\n                    if (!System.IO.Directory.Exists(path) && !File.Exists(path))\n                        continue;\n\n                    break;\n                }\n\n                if (path == null)\n                    return null;\n\n                if (!System.IO.Directory.Exists(path))\n                    path = Path.GetDirectoryName(path);\n\n                if ((path == null) || (!System.IO.Directory.Exists(path)))\n                    return null;\n\n                return path;\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Compares given MD5 hash with hash of given file\n        /// </summary>\n        /// <param name=\"file\"></param>\n        /// <param name=\"hash\"></param>\n        /// <returns></returns>\n        public static bool CompareMD5(string file, string hash)\n        {\n            if (file == null)\n                return false;\n            System.IO.FileStream FileCheck = System.IO.File.OpenRead(file);\n            using (System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider())\n            {\n                byte[] md5Hash = md5.ComputeHash(FileCheck);\n                FileCheck.Close();\n                string md5string = BitConverter.ToString(md5Hash).Replace(\"-\", \"\").ToLower();\n                if (md5string == hash)\n                    return true;\n                else\n                    return false;\n            }\n        }\n\n        /// <summary>\n        /// Returns MD5 hash from given file\n        /// </summary>\n        /// <param name=\"file\"></param>\n        /// <returns></returns>\n        public static byte[] GetMD5(string file)\n        {\n            if (file == null)\n                return null;\n            System.IO.FileStream FileCheck = System.IO.File.OpenRead(file);\n            using (System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider())\n            {\n                byte[] md5Hash = md5.ComputeHash(FileCheck);\n                FileCheck.Close();\n                return md5Hash;\n            }\n        }\n\n        /// <summary>\n        /// Compares MD5 hash from given mul file with hash in responsible hash-file\n        /// </summary>\n        /// <param name=\"what\"></param>\n        /// <returns></returns>\n        public static bool CompareHashFile(string what, string path)\n        {\n            string FileName = Path.Combine(path, $\"UOFiddler{what}.hash\");\n            if (File.Exists(FileName))\n            {\n                try\n                {\n                    using (BinaryReader bin =\n                        new BinaryReader(new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read)))\n                    {\n                        int length = bin.ReadInt32();\n                        byte[] buffer = new byte[length];\n                        bin.Read(buffer, 0, length);\n                        string hashold = BitConverter.ToString(buffer).Replace(\"-\", \"\").ToLower();\n                        return Files.CompareMD5(Files.GetFilePath($\"{what}.mul\"), hashold);\n                    }\n                }\n                catch\n                {\n                    return false;\n                }\n            }\n\n            return false;\n        }\n\n        /// <summary>\n        /// Checks if map1.mul exists and sets <see cref=\"Ultima.Map\"/>\n        /// </summary>\n        public static void CheckForNewMapSize()\n        {\n            if (Files.GetFilePath(\"map1.mul\") != null)\n            {\n                if (Ultima.Map.Trammel.Width == 7168)\n                    Ultima.Map.Trammel = new Ultima.Map(1, 1, 7168, 4096);\n                else\n                    Ultima.Map.Trammel = new Ultima.Map(1, 1, 6144, 4096);\n            }\n            else\n            {\n                if (Ultima.Map.Trammel.Width == 7168)\n                    Ultima.Map.Trammel = new Ultima.Map(0, 1, 7168, 4096);\n                else\n                    Ultima.Map.Trammel = new Ultima.Map(0, 1, 6144, 4096);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Gumps.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\nnamespace Ultima\n{\n    public sealed class Gumps\n    {\n        private static FileIndex m_FileIndex = new FileIndex(\"Gumpidx.mul\", \"Gumpart.mul\", \"gumpartLegacyMUL.uop\",\n            0xFFFF, 12, \".tga\", -1, true);\n\n        private static Bitmap[] m_Cache;\n        private static bool[] m_Removed;\n        private static Hashtable m_patched = new Hashtable();\n\n        private static byte[] m_PixelBuffer;\n        private static byte[] m_StreamBuffer;\n        private static byte[] m_ColorTable;\n\n        static Gumps()\n        {\n            if (m_FileIndex != null)\n            {\n                m_Cache = new Bitmap[m_FileIndex.Index.Length];\n                m_Removed = new bool[m_FileIndex.Index.Length];\n            }\n            else\n            {\n                m_Cache = new Bitmap[0xFFFF];\n                m_Removed = new bool[0xFFFF];\n            }\n        }\n\n        /// <summary>\n        /// ReReads gumpart\n        /// </summary>\n        public static void Reload()\n        {\n            try\n            {\n                m_FileIndex = new FileIndex(\"Gumpidx.mul\", \"Gumpart.mul\", \"gumpartLegacyMUL.uop\", 12, -1, \".tga\", -1,\n                    true);\n                m_Cache = new Bitmap[m_FileIndex.Index.Length];\n                m_Removed = new bool[m_FileIndex.Index.Length];\n            }\n            catch\n            {\n                m_FileIndex = null;\n                m_Cache = new Bitmap[0xFFFF];\n                m_Removed = new bool[0xFFFF];\n            }\n\n            m_PixelBuffer = null;\n            m_StreamBuffer = null;\n            m_ColorTable = null;\n            m_patched.Clear();\n        }\n\n        public static int GetCount()\n        {\n            return m_Cache.Length;\n        }\n\n        /// <summary>\n        /// Replaces Gump <see cref=\"m_Cache\"/>\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"bmp\"></param>\n        public static void ReplaceGump(int index, Bitmap bmp)\n        {\n            m_Cache[index] = bmp;\n            m_Removed[index] = false;\n            if (m_patched.Contains(index))\n                m_patched.Remove(index);\n        }\n\n        /// <summary>\n        /// Removes Gumpindex <see cref=\"m_Removed\"/>\n        /// </summary>\n        /// <param name=\"index\"></param>\n        public static void RemoveGump(int index)\n        {\n            m_Removed[index] = true;\n        }\n\n        /// <summary>\n        /// Tests if index is definied\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static bool IsValidIndex(int index)\n        {\n            if (m_FileIndex == null)\n                return false;\n            if (index > m_Cache.Length - 1)\n                return false;\n            if (m_Removed[index])\n                return false;\n            if (m_Cache[index] != null)\n                return true;\n            int length, extra;\n            bool patched;\n\n            if (!m_FileIndex.Valid(index, out length, out extra, out patched))\n                return false;\n            if (extra == -1)\n                return false;\n            int width = (extra >> 16) & 0xFFFF;\n            int height = extra & 0xFFFF;\n\n            if (width <= 0 || height <= 0)\n                return false;\n\n            return true;\n        }\n\n        public static byte[] GetRawGump(int index, out int width, out int height)\n        {\n            width = -1;\n            height = -1;\n            int length, extra;\n            bool patched;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n            if (stream == null)\n                return null;\n            if (extra == -1)\n                return null;\n            width = (extra >> 16) & 0xFFFF;\n            height = extra & 0xFFFF;\n            if (width <= 0 || height <= 0)\n                return null;\n            byte[] buffer = new byte[length];\n            stream.Read(buffer, 0, length);\n            stream.Close();\n            return buffer;\n        }\n\n        /// <summary>\n        /// Returns Bitmap of index and applies Hue\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"hue\"></param>\n        /// <param name=\"onlyHueGrayPixels\"></param>\n        /// <returns></returns>\n        public unsafe static Bitmap GetGump(int index, Hue hue, bool onlyHueGrayPixels, out bool patched)\n        {\n            int length, extra;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n\n            if (stream == null)\n                return null;\n            if (extra == -1)\n            {\n                stream.Close();\n                return null;\n            }\n\n            int width = (extra >> 16) & 0xFFFF;\n            int height = extra & 0xFFFF;\n\n            if (width <= 0 || height <= 0)\n            {\n                stream.Close();\n                return null;\n            }\n\n            int bytesPerLine = width << 1;\n            int bytesPerStride = (bytesPerLine + 3) & ~3;\n            int bytesForImage = height * bytesPerStride;\n\n            int pixelsPerStride = (width + 1) & ~1;\n            int pixelsPerStrideDelta = pixelsPerStride - width;\n\n            byte[] pixelBuffer = m_PixelBuffer;\n\n            if (pixelBuffer == null || pixelBuffer.Length < bytesForImage)\n                m_PixelBuffer = pixelBuffer = new byte[(bytesForImage + 2047) & ~2047];\n\n            byte[] streamBuffer = m_StreamBuffer;\n\n            if (streamBuffer == null || streamBuffer.Length < length)\n                m_StreamBuffer = streamBuffer = new byte[(length + 2047) & ~2047];\n\n            byte[] colorTable = m_ColorTable;\n\n            if (colorTable == null)\n                m_ColorTable = colorTable = new byte[128];\n\n            stream.Read(streamBuffer, 0, length);\n\n            fixed (short* psHueColors = hue.Colors)\n            {\n                fixed (byte* pbStream = streamBuffer)\n                {\n                    fixed (byte* pbPixels = pixelBuffer)\n                    {\n                        fixed (byte* pbColorTable = colorTable)\n                        {\n                            ushort* pHueColors = (ushort*) psHueColors;\n                            ushort* pHueColorsEnd = pHueColors + 32;\n\n                            ushort* pColorTable = (ushort*) pbColorTable;\n\n                            ushort* pColorTableOpaque = pColorTable;\n\n                            while (pHueColors < pHueColorsEnd)\n                                *pColorTableOpaque++ = *pHueColors++;\n\n                            ushort* pPixelDataStart = (ushort*) pbPixels;\n\n                            int* pLookup = (int*) pbStream;\n                            int* pLookupEnd = pLookup + height;\n                            int* pPixelRleStart = pLookup;\n                            int* pPixelRle;\n\n                            ushort* pPixel = pPixelDataStart;\n                            ushort* pRleEnd = pPixel;\n                            ushort* pPixelEnd = pPixel + width;\n\n                            ushort color, count;\n\n                            if (onlyHueGrayPixels)\n                            {\n                                while (pLookup < pLookupEnd)\n                                {\n                                    pPixelRle = pPixelRleStart + *pLookup++;\n                                    pRleEnd = pPixel;\n\n                                    while (pPixel < pPixelEnd)\n                                    {\n                                        color = *(ushort*) pPixelRle;\n                                        count = *(1 + (ushort*) pPixelRle);\n                                        ++pPixelRle;\n\n                                        pRleEnd += count;\n\n                                        if (color != 0 && (color & 0x1F) == ((color >> 5) & 0x1F) &&\n                                            (color & 0x1F) == ((color >> 10) & 0x1F))\n                                            color = pColorTable[color >> 10];\n                                        else if (color != 0)\n                                            color ^= 0x8000;\n\n                                        while (pPixel < pRleEnd)\n                                            *pPixel++ = color;\n                                    }\n\n                                    pPixel += pixelsPerStrideDelta;\n                                    pPixelEnd += pixelsPerStride;\n                                }\n                            }\n                            else\n                            {\n                                while (pLookup < pLookupEnd)\n                                {\n                                    pPixelRle = pPixelRleStart + *pLookup++;\n                                    pRleEnd = pPixel;\n\n                                    while (pPixel < pPixelEnd)\n                                    {\n                                        color = *(ushort*) pPixelRle;\n                                        count = *(1 + (ushort*) pPixelRle);\n                                        ++pPixelRle;\n\n                                        pRleEnd += count;\n\n                                        if (color != 0)\n                                            color = pColorTable[color >> 10];\n\n                                        while (pPixel < pRleEnd)\n                                            *pPixel++ = color;\n                                    }\n\n                                    pPixel += pixelsPerStrideDelta;\n                                    pPixelEnd += pixelsPerStride;\n                                }\n                            }\n\n                            stream.Close();\n                            return new Bitmap(width, height, bytesPerStride, PixelFormat.Format16bppArgb1555,\n                                (IntPtr) pPixelDataStart);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Returns Bitmap of index\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public unsafe static Bitmap GetGump(int index)\n        {\n            bool patched;\n            return GetGump(index, out patched);\n        }\n\n        /// <summary>\n        /// Returns Bitmap of index and if verdata patched\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"patched\"></param>\n        /// <returns></returns>\n        public unsafe static Bitmap GetGump(int index, out bool patched)\n        {\n            if (m_patched.Contains(index))\n                patched = (bool) m_patched[index];\n            else\n                patched = false;\n            if (index > m_Cache.Length - 1)\n                return null;\n            if (m_Removed[index])\n                return null;\n            if (m_Cache[index] != null)\n                return m_Cache[index];\n            int length, extra;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n            if (stream == null)\n                return null;\n            if (extra == -1)\n            {\n                stream.Close();\n                return null;\n            }\n\n            if (patched)\n                m_patched[index] = true;\n\n            int width = (extra >> 16) & 0xFFFF;\n            int height = extra & 0xFFFF;\n\n            if (width <= 0 || height <= 0)\n                return null;\n            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format16bppArgb1555);\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,\n                PixelFormat.Format16bppArgb1555);\n\n            if (m_StreamBuffer == null || m_StreamBuffer.Length < length)\n                m_StreamBuffer = new byte[length];\n            stream.Read(m_StreamBuffer, 0, length);\n\n            fixed (byte* data = m_StreamBuffer)\n            {\n                int* lookup = (int*) data;\n                ushort* dat = (ushort*) data;\n\n                ushort* line = (ushort*) bd.Scan0;\n                int delta = bd.Stride >> 1;\n                int count = 0;\n                for (int y = 0; y < height; ++y, line += delta)\n                {\n                    count = (*lookup++ * 2);\n\n                    ushort* cur = line;\n                    ushort* end = line + bd.Width;\n\n                    while (cur < end)\n                    {\n                        ushort color = dat[count++];\n                        ushort* next = cur + dat[count++];\n\n                        if (color == 0)\n                            cur = next;\n                        else\n                        {\n                            color ^= 0x8000;\n                            while (cur < next)\n                                *cur++ = color;\n                        }\n                    }\n                }\n            }\n\n            bmp.UnlockBits(bd);\n            if (Files.CacheData)\n                return m_Cache[index] = bmp;\n            else\n                return bmp;\n        }\n\n        public static unsafe void Save(string path)\n        {\n            string idx = Path.Combine(path, \"Gumpidx.mul\");\n            string mul = Path.Combine(path, \"Gumpart.mul\");\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter binidx = new BinaryWriter(fsidx),\n                    binmul = new BinaryWriter(fsmul))\n                {\n                    for (int index = 0; index < m_Cache.Length; index++)\n                    {\n                        if (m_Cache[index] == null)\n                            m_Cache[index] = GetGump(index);\n\n                        Bitmap bmp = m_Cache[index];\n                        if ((bmp == null) || (m_Removed[index]))\n                        {\n                            binidx.Write((int) -1); // lookup\n                            binidx.Write((int) -1); // length\n                            binidx.Write((int) -1); // extra\n                        }\n                        else\n                        {\n                            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),\n                                ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555);\n                            ushort* line = (ushort*) bd.Scan0;\n                            int delta = bd.Stride >> 1;\n\n                            binidx.Write((int) fsmul.Position); //lookup\n                            int length = (int) fsmul.Position;\n                            int fill = 0;\n                            for (int i = 0; i < bmp.Height; ++i)\n                            {\n                                binmul.Write(fill);\n                            }\n\n                            for (int Y = 0; Y < bmp.Height; ++Y, line += delta)\n                            {\n                                ushort* cur = line;\n\n                                int X = 0;\n                                int current = (int) fsmul.Position;\n                                fsmul.Seek(length + Y * 4, SeekOrigin.Begin);\n                                int offset = (current - length) / 4;\n                                binmul.Write(offset);\n                                fsmul.Seek(length + offset * 4, SeekOrigin.Begin);\n\n                                while (X < bd.Width)\n                                {\n                                    int Run = 1;\n                                    ushort c = cur[X];\n                                    while ((X + Run) < bd.Width)\n                                    {\n                                        if (c != cur[X + Run])\n                                            break;\n                                        ++Run;\n                                    }\n\n                                    if (c == 0)\n                                        binmul.Write(c);\n                                    else\n                                        binmul.Write((ushort) (c ^ 0x8000));\n                                    binmul.Write((short) Run);\n                                    X += Run;\n                                }\n                            }\n\n                            length = (int) fsmul.Position - length;\n                            binidx.Write(length);\n                            binidx.Write((int) (bmp.Width << 16) + bmp.Height);\n                            bmp.UnlockBits(bd);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Hues.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Ultima\n{\n    public sealed class Hues\n    {\n        private static int[] m_Header;\n\n        public static Hue[] List { get; private set; }\n\n        static Hues()\n        {\n            Initialize();\n        }\n\n        /// <summary>\n        /// Reads hues.mul and fills <see cref=\"List\"/>\n        /// </summary>\n        public static void Initialize()\n        {\n            string path = Files.GetFilePath(\"hues.mul\");\n            int index = 0;\n\n            List = new Hue[3000];\n\n            if (path != null)\n            {\n                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    int blockCount = (int) fs.Length / 708;\n\n                    if (blockCount > 375)\n                        blockCount = 375;\n                    m_Header = new int[blockCount];\n                    unsafe\n                    {\n                        int structsize = Marshal.SizeOf(typeof(HueDataMul));\n                        byte[] buffer = new byte[blockCount * (4 + 8 * structsize)];\n                        GCHandle gc = GCHandle.Alloc(buffer, GCHandleType.Pinned);\n                        try\n                        {\n                            fs.Read(buffer, 0, buffer.Length);\n                            long currpos = 0;\n\n                            for (int i = 0; i < blockCount; ++i)\n                            {\n                                IntPtr ptrheader = new IntPtr((long) gc.AddrOfPinnedObject() + currpos);\n                                currpos += 4;\n                                m_Header[i] = (int) Marshal.PtrToStructure(ptrheader, typeof(int));\n\n                                for (int j = 0; j < 8; ++j, ++index)\n                                {\n                                    IntPtr ptr = new IntPtr((long) gc.AddrOfPinnedObject() + currpos);\n                                    currpos += structsize;\n                                    HueDataMul cur = (HueDataMul) Marshal.PtrToStructure(ptr, typeof(HueDataMul));\n                                    List[index] = new Hue(index, cur);\n                                }\n                            }\n                        }\n                        finally\n                        {\n                            gc.Free();\n                        }\n                    }\n                }\n            }\n\n            for (; index < List.Length; ++index)\n                List[index] = new Hue(index);\n        }\n\n        public static void Save(string path)\n        {\n            string mul = Path.Combine(path, \"hues.mul\");\n            using (FileStream fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter binmul = new BinaryWriter(fsmul))\n                {\n                    int index = 0;\n                    for (int i = 0; i < m_Header.Length; ++i)\n                    {\n                        binmul.Write(m_Header[i]);\n                        for (int j = 0; j < 8; ++j, ++index)\n                        {\n                            for (int c = 0; c < 32; ++c)\n                                binmul.Write((short) (List[index].Colors[c] ^ 0x8000));\n\n                            binmul.Write((short) (List[index].TableStart ^ 0x8000));\n                            binmul.Write((short) (List[index].TableEnd ^ 0x8000));\n                            byte[] b = new byte[20];\n                            if (List[index].Name != null)\n                            {\n                                byte[] bb = Encoding.Default.GetBytes(List[index].Name);\n                                if (bb.Length > 20)\n                                    Array.Resize(ref bb, 20);\n                                bb.CopyTo(b, 0);\n                            }\n\n                            binmul.Write(b);\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Returns <see cref=\"Hue\"/>\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static Hue GetHue(int index)\n        {\n            index &= 0x3FFF;\n\n            if (index >= 0 && index < 3000)\n                return List[index];\n\n            return List[0];\n        }\n\n        /// <summary>\n        /// Converts RGB value to Huecolor\n        /// </summary>\n        /// <param name=\"c\"></param>\n        /// <returns></returns>\n        public static short ColorToHue(Color c)\n        {\n            ushort origred = c.R;\n            ushort origgreen = c.G;\n            ushort origblue = c.B;\n            const double scale = 31.0 / 255;\n            ushort newred = (ushort) (origred * scale);\n            if (newred == 0 && origred != 0)\n                newred = 1;\n            ushort newgreen = (ushort) (origgreen * scale);\n            if (newgreen == 0 && origgreen != 0)\n                newgreen = 1;\n            ushort newblue = (ushort) (origblue * scale);\n            if (newblue == 0 && origblue != 0)\n                newblue = 1;\n\n            return (short) ((newred << 10) | (newgreen << 5) | (newblue));\n        }\n\n        /// <summary>\n        /// Converts Huecolor to RGBColor\n        /// </summary>\n        /// <param name=\"hue\"></param>\n        /// <returns></returns>\n        public static Color HueToColor(short hue)\n        {\n            const int scale = 255 / 31;\n            return Color.FromArgb(\n                (((hue & 0x7c00) >> 10) * scale),\n                (((hue & 0x3e0) >> 5) * scale),\n                ((hue & 0x1f) * scale)\n            );\n        }\n\n        public static int HueToColorR(short hue)\n        {\n            return (((hue & 0x7c00) >> 10) * (255 / 31));\n        }\n\n        public static int HueToColorG(short hue)\n        {\n            return (((hue & 0x3e0) >> 5) * (255 / 31));\n        }\n\n        public static int HueToColorB(short hue)\n        {\n            return ((hue & 0x1f) * (255 / 31));\n        }\n\n        public unsafe static void ApplyTo(Bitmap bmp, short[] Colors, bool onlyHueGrayPixels)\n        {\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite,\n                PixelFormat.Format16bppArgb1555);\n\n            int stride = bd.Stride >> 1;\n            int width = bd.Width;\n            int height = bd.Height;\n            int delta = stride - width;\n\n            ushort* pBuffer = (ushort*) bd.Scan0;\n            ushort* pLineEnd = pBuffer + width;\n            ushort* pImageEnd = pBuffer + (stride * height);\n\n            if (onlyHueGrayPixels)\n            {\n                int c;\n                int r;\n                int g;\n                int b;\n\n                while (pBuffer < pImageEnd)\n                {\n                    while (pBuffer < pLineEnd)\n                    {\n                        c = *pBuffer;\n                        if (c != 0)\n                        {\n                            r = (c >> 10) & 0x1F;\n                            g = (c >> 5) & 0x1F;\n                            b = c & 0x1F;\n                            if (r == g && r == b)\n                                *pBuffer = (ushort) Colors[(c >> 10) & 0x1F];\n                        }\n\n                        ++pBuffer;\n                    }\n\n                    pBuffer += delta;\n                    pLineEnd += stride;\n                }\n            }\n            else\n            {\n                while (pBuffer < pImageEnd)\n                {\n                    while (pBuffer < pLineEnd)\n                    {\n                        if (*pBuffer != 0)\n                            *pBuffer = (ushort) Colors[(*pBuffer >> 10) & 0x1F];\n                        ++pBuffer;\n                    }\n\n                    pBuffer += delta;\n                    pLineEnd += stride;\n                }\n            }\n\n            bmp.UnlockBits(bd);\n        }\n    }\n\n    public sealed class Hue\n    {\n        public int Index { get; private set; }\n        public short[] Colors { get; set; }\n        public string Name { get; set; }\n        public short TableStart { get; set; }\n        public short TableEnd { get; set; }\n\n        public Hue(int index)\n        {\n            Name = \"Null\";\n            Index = index;\n            Colors = new short[32];\n            TableStart = 0;\n            TableEnd = 0;\n        }\n\n        public Color GetColor(int index)\n        {\n            return Hues.HueToColor(Colors[index]);\n        }\n\n        private static byte[] m_StringBuffer = new byte[20];\n        private static byte[] m_Buffer = new byte[88];\n\n        public Hue(int index, BinaryReader bin)\n        {\n            Index = index;\n            Colors = new short[32];\n\n            m_Buffer = bin.ReadBytes(88);\n            unsafe\n            {\n                fixed (byte* buffer = m_Buffer)\n                {\n                    ushort* buf = (ushort*) buffer;\n                    for (int i = 0; i < 32; ++i)\n                        Colors[i] = (short) (*buf++ | 0x8000);\n                    TableStart = (short) (*buf++ | 0x8000);\n                    TableEnd = (short) (*buf++ | 0x8000);\n                    byte* sbuf = (byte*) buf;\n                    int count;\n                    for (count = 0; count < 20 && *sbuf != 0; ++count)\n                        m_StringBuffer[count] = *sbuf++;\n                    Name = Encoding.Default.GetString(m_StringBuffer, 0, count);\n                    Name = Name.Replace(\"\\n\", \" \");\n                }\n            }\n        }\n\n        public Hue(int index, HueDataMul mulstruct)\n        {\n            Index = index;\n            Colors = new short[32];\n            unsafe\n            {\n                for (int i = 0; i < 32; ++i)\n                    Colors[i] = (short) (mulstruct.colors[i] | 0x8000);\n                TableStart = (short) (mulstruct.tablestart | 0x8000);\n                TableEnd = (short) (mulstruct.tableend | 0x8000);\n                Name = NativeMethods.ReadNameString(mulstruct.name, 20);\n                Name = Name.Replace(\"\\n\", \" \");\n            }\n        }\n\n        /// <summary>\n        /// Applies Hue to Bitmap\n        /// </summary>\n        /// <param name=\"bmp\"></param>\n        /// <param name=\"onlyHueGrayPixels\"></param>\n        public unsafe void ApplyTo(Bitmap bmp, bool onlyHueGrayPixels)\n        {\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite,\n                PixelFormat.Format16bppArgb1555);\n\n            int stride = bd.Stride >> 1;\n            int width = bd.Width;\n            int height = bd.Height;\n            int delta = stride - width;\n\n            ushort* pBuffer = (ushort*) bd.Scan0;\n            ushort* pLineEnd = pBuffer + width;\n            ushort* pImageEnd = pBuffer + (stride * height);\n\n            if (onlyHueGrayPixels)\n            {\n                int c;\n                int r;\n                int g;\n                int b;\n\n                while (pBuffer < pImageEnd)\n                {\n                    while (pBuffer < pLineEnd)\n                    {\n                        c = *pBuffer;\n                        if (c != 0)\n                        {\n                            r = (c >> 10) & 0x1F;\n                            g = (c >> 5) & 0x1F;\n                            b = c & 0x1F;\n                            if (r == g && r == b)\n                                *pBuffer = (ushort) Colors[(c >> 10) & 0x1F];\n                        }\n\n                        ++pBuffer;\n                    }\n\n                    pBuffer += delta;\n                    pLineEnd += stride;\n                }\n            }\n            else\n            {\n                while (pBuffer < pImageEnd)\n                {\n                    while (pBuffer < pLineEnd)\n                    {\n                        if (*pBuffer != 0)\n                            *pBuffer = (ushort) Colors[(*pBuffer >> 10) & 0x1F];\n                        ++pBuffer;\n                    }\n\n                    pBuffer += delta;\n                    pLineEnd += stride;\n                }\n            }\n\n            bmp.UnlockBits(bd);\n        }\n\n        public void Export(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.GetEncoding(1252)))\n            {\n                Tex.WriteLine(Name);\n                Tex.WriteLine(((short) (TableStart ^ 0x8000)).ToString());\n                Tex.WriteLine(((short) (TableEnd ^ 0x8000)).ToString());\n                for (int i = 0; i < Colors.Length; ++i)\n                {\n                    Tex.WriteLine(((short) (Colors[i] ^ 0x8000)).ToString());\n                }\n            }\n        }\n\n        public void Import(string FileName)\n        {\n            if (!File.Exists(FileName))\n                return;\n            using (StreamReader sr = new StreamReader(FileName))\n            {\n                string line;\n                int i = -3;\n                while ((line = sr.ReadLine()) != null)\n                {\n                    line = line.Trim();\n                    try\n                    {\n                        if (i >= Colors.Length)\n                            break;\n                        if (i == -3)\n                            Name = line;\n                        else if (i == -2)\n                            TableStart = (short) (ushort.Parse(line) | 0x8000);\n                        else if (i == -1)\n                            TableEnd = (short) (ushort.Parse(line) | 0x8000);\n                        else\n                        {\n                            Colors[i] = (short) (ushort.Parse(line) | 0x8000);\n                        }\n\n                        ++i;\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n        }\n    }\n\n    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public unsafe struct HueDataMul\n    {\n        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]\n        public ushort[] colors;\n\n        public ushort tablestart;\n        public ushort tableend;\n\n        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]\n        public byte[] name;\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Light.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\nnamespace Ultima\n{\n    public sealed class Light\n    {\n        private static FileIndex m_FileIndex = new FileIndex(\"lightidx.mul\", \"light.mul\", 100, -1);\n        private static Bitmap[] m_Cache = new Bitmap[100];\n        private static bool[] m_Removed = new bool[100];\n        private static byte[] m_StreamBuffer;\n\n        /// <summary>\n        /// ReReads light.mul\n        /// </summary>\n        public static void Reload()\n        {\n            m_FileIndex = new FileIndex(\"lightidx.mul\", \"light.mul\", 100, -1);\n            m_Cache = new Bitmap[100];\n            m_Removed = new bool[100];\n        }\n\n        /// <summary>\n        /// Gets count of definied lights\n        /// </summary>\n        /// <returns></returns>\n        public static int GetCount()\n        {\n            string idxPath = Files.GetFilePath(\"lightidx.mul\");\n            if (idxPath == null)\n                return 0;\n            using (FileStream index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n            {\n                return (int) (index.Length / 12);\n            }\n        }\n\n        /// <summary>\n        /// Tests if given index is valid\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static bool TestLight(int index)\n        {\n            if (m_Removed[index])\n                return false;\n            if (m_Cache[index] != null)\n                return true;\n\n            int length, extra;\n            bool patched;\n\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n\n            if (stream == null)\n                return false;\n            stream.Close();\n            int width = (extra & 0xFFFF);\n            int height = ((extra >> 16) & 0xFFFF);\n            if ((width > 0) && (height > 0))\n                return true;\n\n            return false;\n        }\n\n        /// <summary>\n        /// Removes Light <see cref=\"m_Removed\"/>\n        /// </summary>\n        /// <param name=\"index\"></param>\n        public static void Remove(int index)\n        {\n            m_Removed[index] = true;\n        }\n\n        /// <summary>\n        /// Replaces Light\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"bmp\"></param>\n        public static void Replace(int index, Bitmap bmp)\n        {\n            m_Cache[index] = bmp;\n            m_Removed[index] = false;\n        }\n\n        public unsafe static byte[] GetRawLight(int index, out int width, out int height)\n        {\n            width = 0;\n            height = 0;\n            if (m_Removed[index])\n                return null;\n            int length, extra;\n            bool patched;\n\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n\n            if (stream == null)\n                return null;\n\n            width = (extra & 0xFFFF);\n            height = ((extra >> 16) & 0xFFFF);\n            byte[] buffer = new byte[length];\n            stream.Read(buffer, 0, length);\n            stream.Close();\n            return buffer;\n        }\n\n        /// <summary>\n        /// Returns Bitmap of given index\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public unsafe static Bitmap GetLight(int index)\n        {\n            if (m_Removed[index])\n                return null;\n            if (m_Cache[index] != null)\n                return m_Cache[index];\n\n            int length, extra;\n            bool patched;\n\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n\n            if (stream == null)\n                return null;\n\n            int width = (extra & 0xFFFF);\n            int height = ((extra >> 16) & 0xFFFF);\n\n            if (m_StreamBuffer == null || m_StreamBuffer.Length < length)\n                m_StreamBuffer = new byte[length];\n            stream.Read(m_StreamBuffer, 0, length);\n\n            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format16bppArgb1555);\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,\n                PixelFormat.Format16bppArgb1555);\n\n            ushort* line = (ushort*) bd.Scan0;\n            int delta = bd.Stride >> 1;\n\n            fixed (byte* data = m_StreamBuffer)\n            {\n                sbyte* bindat = (sbyte*) data;\n                for (int y = 0; y < height; ++y, line += delta)\n                {\n                    ushort* cur = line;\n                    ushort* end = cur + width;\n\n                    while (cur < end)\n                    {\n                        sbyte value = *bindat++;\n                        *cur++ = (ushort) (((0x1f + value) << 10) + ((0x1F + value) << 5) + (0x1F + value));\n                    }\n                }\n            }\n\n            bmp.UnlockBits(bd);\n            stream.Close();\n            if (!Files.CacheData)\n                return m_Cache[index] = bmp;\n            else\n                return bmp;\n        }\n\n        public unsafe static void Save(string path)\n        {\n            string idx = Path.Combine(path, \"lightidx.mul\");\n            string mul = Path.Combine(path, \"light.mul\");\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter binidx = new BinaryWriter(fsidx),\n                    binmul = new BinaryWriter(fsmul))\n                {\n                    for (int index = 0; index < m_Cache.Length; index++)\n                    {\n                        if (m_Cache[index] == null)\n                            m_Cache[index] = GetLight(index);\n                        Bitmap bmp = m_Cache[index];\n\n                        if ((bmp == null) || (m_Removed[index]))\n                        {\n                            binidx.Write((int) -1); // lookup\n                            binidx.Write((int) -1); // length\n                            binidx.Write((int) -1); // extra\n                        }\n                        else\n                        {\n                            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),\n                                ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555);\n                            ushort* line = (ushort*) bd.Scan0;\n                            int delta = bd.Stride >> 1;\n\n                            binidx.Write((int) fsmul.Position); //lookup\n                            int length = (int) fsmul.Position;\n\n                            for (int Y = 0; Y < bmp.Height; ++Y, line += delta)\n                            {\n                                ushort* cur = line;\n                                ushort* end = cur + bmp.Width;\n                                while (cur < end)\n                                {\n                                    sbyte value = (sbyte) (((*cur++ >> 10) & 0xffff) - 0x1f);\n                                    if (value > 0) // wtf? but it works...\n                                        --value;\n                                    binmul.Write(value);\n                                }\n                            }\n\n                            length = (int) fsmul.Position - length;\n                            binidx.Write(length);\n                            binidx.Write((int) (bmp.Width << 16) + bmp.Height);\n                            bmp.UnlockBits(bd);\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/LocationPointer.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Ultima\n{\n    public sealed class LocationPointer\n    {\n        public int PointerX { get; set; }\n        public int PointerY { get; set; }\n        public int PointerZ { get; set; }\n        public int PointerF { get; set; }\n        public int SizeX { get; set; }\n        public int SizeY { get; set; }\n        public int SizeZ { get; set; }\n        public int SizeF { get; set; }\n\n        public LocationPointer(int ptrX, int ptrY, int ptrZ, int ptrF, int sizeX, int sizeY, int sizeZ, int sizeF)\n        {\n            PointerX = ptrX;\n            PointerY = ptrY;\n            PointerZ = ptrZ;\n            PointerF = ptrF;\n            SizeX = sizeX;\n            SizeY = sizeY;\n            SizeZ = sizeZ;\n            SizeF = sizeF;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Map.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\nnamespace Ultima\n{\n    public sealed class Map\n    {\n        private TileMatrix m_Tiles;\n        private int m_FileIndex, m_MapID;\n        private int m_Width, m_Height;\n        private string m_path;\n\n        private static bool m_UseDiff;\n\n        public static bool UseDiff\n        {\n            get { return m_UseDiff; }\n            set\n            {\n                m_UseDiff = value;\n                Reload();\n            }\n        }\n\n        public static Map Felucca = new Map(0, 0, 7168, 4096);\n        public static Map Trammel = new Map(1, 1, 7168, 4096);\n        public static readonly Map Ilshenar = new Map(2, 2, 2304, 1600);\n        public static readonly Map Malas = new Map(3, 3, 2560, 2048);\n        public static readonly Map Tokuno = new Map(4, 4, 1448, 1448);\n        public static readonly Map TerMur = new Map(5, 5, 1280, 4096);\n        public static Map Custom;\n\n        public static void StartUpSetDiff(bool value)\n        {\n            m_UseDiff = value;\n        }\n\n        public Map(int fileIndex, int mapID, int width, int height)\n        {\n            m_FileIndex = fileIndex;\n            m_MapID = mapID;\n            m_path = null;\n\n            m_Tiles = new TileMatrix(m_FileIndex, m_MapID, width, height, m_path);\n            m_Width = m_Tiles.Width;\n            m_Height = m_Tiles.Height;\n        }\n\n        public Map(string path, int fileIndex, int mapID, int width, int height)\n        {\n            m_FileIndex = fileIndex;\n            m_MapID = mapID;\n            m_Width = width;\n            m_Height = height;\n            m_path = path;\n        }\n\n        /// <summary>\n        /// Sets cache-vars to null\n        /// </summary>\n        public static void Reload()\n        {\n            Felucca.Tiles.Dispose();\n            Trammel.Tiles.Dispose();\n            Ilshenar.Tiles.Dispose();\n            Malas.Tiles.Dispose();\n            Tokuno.Tiles.Dispose();\n            TerMur.Tiles.Dispose();\n            Felucca.Tiles.StaticIndexInit = false;\n            Trammel.Tiles.StaticIndexInit = false;\n            Ilshenar.Tiles.StaticIndexInit = false;\n            Malas.Tiles.StaticIndexInit = false;\n            Tokuno.Tiles.StaticIndexInit = false;\n            TerMur.Tiles.StaticIndexInit = false;\n            Felucca.m_Cache =\n                Trammel.m_Cache = Ilshenar.m_Cache = Malas.m_Cache = Tokuno.m_Cache = TerMur.m_Cache = null;\n            Felucca.m_Tiles =\n                Trammel.m_Tiles = Ilshenar.m_Tiles = Malas.m_Tiles = Tokuno.m_Tiles = TerMur.m_Tiles = null;\n            Felucca.m_Cache_NoStatics = Trammel.m_Cache_NoStatics = Ilshenar.m_Cache_NoStatics =\n                Malas.m_Cache_NoStatics = Tokuno.m_Cache_NoStatics = TerMur.m_Cache_NoStatics = null;\n            Felucca.m_Cache_NoPatch = Trammel.m_Cache_NoPatch = Ilshenar.m_Cache_NoPatch =\n                Malas.m_Cache_NoPatch = Tokuno.m_Cache_NoPatch = TerMur.m_Cache_NoPatch = null;\n            Felucca.m_Cache_NoStatics_NoPatch = Trammel.m_Cache_NoStatics_NoPatch = Ilshenar.m_Cache_NoStatics_NoPatch =\n                Malas.m_Cache_NoStatics_NoPatch =\n                    Tokuno.m_Cache_NoStatics_NoPatch = TerMur.m_Cache_NoStatics_NoPatch = null;\n        }\n\n        public void ResetCache()\n        {\n            m_Cache = null;\n            m_Cache_NoPatch = null;\n            m_Cache_NoStatics = null;\n            m_Cache_NoStatics_NoPatch = null;\n            IsCached_Default = false;\n            IsCached_NoStatics = false;\n            IsCached_NoPatch = false;\n            IsCached_NoStatics_NoPatch = false;\n        }\n\n        public bool LoadedMatrix\n        {\n            get { return (m_Tiles != null); }\n        }\n\n        public TileMatrix Tiles\n        {\n            get\n            {\n                if (m_Tiles == null)\n                    m_Tiles = new TileMatrix(m_FileIndex, m_MapID, m_Width, m_Height, m_path);\n\n                return m_Tiles;\n            }\n        }\n\n        public int Width\n        {\n            get { return m_Width; }\n            set { m_Width = value; }\n        }\n\n        public int Height\n        {\n            get { return m_Height; }\n        }\n\n        public int FileIndex\n        {\n            get { return m_FileIndex; }\n        }\n\n        /// <summary>\n        /// Returns Bitmap with Statics\n        /// </summary>\n        /// <param name=\"x\">8x8 Block</param>\n        /// <param name=\"y\">8x8 Block</param>\n        /// <param name=\"width\">8x8 Block</param>\n        /// <param name=\"height\">8x8 Block</param>\n        /// <returns></returns>\n        public Bitmap GetImage(int x, int y, int width, int height)\n        {\n            return GetImage(x, y, width, height, true);\n        }\n\n        /// <summary>\n        /// Returns Bitmap\n        /// </summary>\n        /// <param name=\"x\">8x8 Block</param>\n        /// <param name=\"y\">8x8 Block</param>\n        /// <param name=\"width\">8x8 Block</param>\n        /// <param name=\"height\">8x8 Block</param>\n        /// <param name=\"statics\">8x8 Block</param>\n        /// <returns></returns>\n        public Bitmap GetImage(int x, int y, int width, int height, bool statics)\n        {\n            Bitmap bmp = new Bitmap(width << 3, height << 3, PixelFormat.Format32bppRgb);\n\n            GetImage(x, y, width, height, bmp, statics);\n\n            return bmp;\n        }\n\n        private bool IsCached_Default;\n        private bool IsCached_NoStatics;\n        private bool IsCached_NoPatch;\n        private bool IsCached_NoStatics_NoPatch;\n\n        private int[][][] m_Cache;\n        private int[][][] m_Cache_NoStatics;\n        private int[][][] m_Cache_NoPatch;\n        private int[][][] m_Cache_NoStatics_NoPatch;\n        private int[] m_Black;\n\n        public bool IsCached(bool statics)\n        {\n            if (Map.UseDiff)\n            {\n                if (!statics)\n                    return IsCached_NoStatics;\n                else\n                    return IsCached_Default;\n            }\n            else\n            {\n                if (!statics)\n                    return IsCached_NoStatics_NoPatch;\n                else\n                    return IsCached_NoPatch;\n            }\n        }\n\n        public void PreloadRenderedBlock(int x, int y, bool statics)\n        {\n            TileMatrix matrix = this.Tiles;\n\n            if (x < 0 || y < 0 || x >= matrix.BlockWidth || y >= matrix.BlockHeight)\n            {\n                if (m_Black == null)\n                    m_Black = new int[64];\n                return;\n            }\n\n            int[][][] cache;\n            if (Map.UseDiff)\n            {\n                if (statics)\n                    IsCached_Default = true;\n                else\n                    IsCached_NoStatics = true;\n                cache = (statics ? m_Cache : m_Cache_NoStatics);\n            }\n            else\n            {\n                if (statics)\n                    IsCached_NoPatch = true;\n                else\n                    IsCached_NoStatics_NoPatch = true;\n                cache = (statics ? m_Cache_NoPatch : m_Cache_NoStatics_NoPatch);\n            }\n\n            if (cache == null)\n            {\n                if (Map.UseDiff)\n                {\n                    if (statics)\n                        m_Cache = cache = new int[m_Tiles.BlockHeight][][];\n                    else\n                        m_Cache_NoStatics = cache = new int[m_Tiles.BlockHeight][][];\n                }\n                else\n                {\n                    if (statics)\n                        m_Cache_NoPatch = cache = new int[m_Tiles.BlockHeight][][];\n                    else\n                        m_Cache_NoStatics_NoPatch = cache = new int[m_Tiles.BlockHeight][][];\n                }\n            }\n\n            if (cache[y] == null)\n                cache[y] = new int[m_Tiles.BlockWidth][];\n\n            if (cache[y][x] == null)\n                cache[y][x] = RenderBlock(x, y, statics, Map.UseDiff);\n\n            m_Tiles.CloseStreams();\n        }\n\n        public int[] GetRenderedBlock(int x, int y, bool statics)\n        {\n            TileMatrix matrix = this.Tiles;\n\n            if (x < 0 || y < 0 || x >= matrix.BlockWidth || y >= matrix.BlockHeight)\n            {\n                if (m_Black == null)\n                    m_Black = new int[64];\n\n                return m_Black;\n            }\n\n            int[][][] cache;\n            if (Map.UseDiff)\n                cache = (statics ? m_Cache : m_Cache_NoStatics);\n            else\n                cache = (statics ? m_Cache_NoPatch : m_Cache_NoStatics_NoPatch);\n\n            if (cache == null)\n            {\n                if (Map.UseDiff)\n                {\n                    if (statics)\n                        m_Cache = cache = new int[m_Tiles.BlockHeight][][];\n                    else\n                        m_Cache_NoStatics = cache = new int[m_Tiles.BlockHeight][][];\n                }\n                else\n                {\n                    if (statics)\n                        m_Cache_NoPatch = cache = new int[m_Tiles.BlockHeight][][];\n                    else\n                        m_Cache_NoStatics_NoPatch = cache = new int[m_Tiles.BlockHeight][][];\n                }\n            }\n\n            if (cache[y] == null)\n                cache[y] = new int[m_Tiles.BlockWidth][];\n\n            int[] data = cache[y][x];\n\n            if (data == null)\n                cache[y][x] = data = RenderBlock(x, y, statics, Map.UseDiff);\n\n            return data;\n        }\n\n        public static Int32 u16Tou32(Int16 color)\n        {\n            Int32 red = (Int32) (((color >> 0xA) & 0x1F) * 8.225806f);\n            Int32 green = (Int32) (((color >> 0x5) & 0x1F) * 8.225806f);\n            Int32 blue = (Int32) ((color & 0x1F) * 8.225806f);\n\n            if (red < 0)\n                red = 0;\n            else if (red > 0xFF)\n                red = 0xFF;\n\n            if (green < 0)\n                green = 0;\n            else if (green > 0xFF)\n                green = 255;\n\n            if (blue < 0)\n                blue = 0;\n            else if (blue > 0xFF)\n                blue = 0xFF;\n\n            return ((red << 0x10) | (green << 0x8) | blue);\n        }\n\n        private unsafe int[] RenderBlock(int x, int y, bool drawStatics, bool diff)\n        {\n            int[] data = new int[64];\n\n            Tile[] tiles = m_Tiles.GetLandBlock(x, y, diff);\n\n            fixed (short* pColors = RadarCol.Colors)\n            {\n                fixed (int* pHeight = TileData.HeightTable)\n                {\n                    fixed (Tile* ptTiles = tiles)\n                    {\n                        Tile* pTiles = ptTiles;\n\n                        fixed (int* pData = data)\n                        {\n                            int* pvData = pData;\n\n                            if (drawStatics)\n                            {\n                                HuedTile[][][] statics = drawStatics ? m_Tiles.GetStaticBlock(x, y, diff) : null;\n\n                                for (int k = 0, v = 0; k < 8; ++k, v += 8)\n                                {\n                                    for (int p = 0; p < 8; ++p)\n                                    {\n                                        int highTop = -255;\n                                        int highZ = -255;\n                                        int highID = 0;\n                                        int highHue = 0;\n                                        int z, top;\n                                        bool highstatic = false;\n\n                                        HuedTile[] curStatics = statics[p][k];\n\n                                        if (curStatics.Length > 0)\n                                        {\n                                            fixed (HuedTile* phtStatics = curStatics)\n                                            {\n                                                HuedTile* pStatics = phtStatics;\n                                                HuedTile* pStaticsEnd = pStatics + curStatics.Length;\n\n                                                while (pStatics < pStaticsEnd)\n                                                {\n                                                    z = pStatics->m_Z;\n                                                    top = z + pHeight[pStatics->ID];\n\n                                                    if (top > highTop || (z > highZ && top >= highTop))\n                                                    {\n                                                        highTop = top;\n                                                        highZ = z;\n                                                        highID = pStatics->ID;\n                                                        highHue = pStatics->Hue;\n                                                        highstatic = true;\n                                                    }\n\n                                                    ++pStatics;\n                                                }\n                                            }\n                                        }\n\n                                        StaticTile[] pending = m_Tiles.GetPendingStatics(x, y);\n                                        if (pending != null)\n                                        {\n                                            foreach (StaticTile penS in pending)\n                                            {\n                                                if (penS.m_X == p)\n                                                {\n                                                    if (penS.m_Y == k)\n                                                    {\n                                                        z = penS.m_Z;\n                                                        top = z + pHeight[penS.m_ID];\n\n                                                        if (top > highTop || (z > highZ && top >= highTop))\n                                                        {\n                                                            highTop = top;\n                                                            highZ = z;\n                                                            highID = penS.m_ID;\n                                                            highHue = penS.m_Hue;\n                                                            highstatic = true;\n                                                        }\n                                                    }\n                                                }\n                                            }\n                                        }\n\n                                        top = pTiles->m_Z;\n\n                                        if (top > highTop)\n                                        {\n                                            highID = pTiles->m_ID;\n                                            highHue = 0;\n                                            highstatic = false;\n                                        }\n\n                                        if (highHue == 0)\n                                        {\n                                            try\n                                            {\n                                                if (highstatic)\n                                                    *pvData++ = u16Tou32(pColors[highID + 0x4000]);\n                                                else\n                                                    *pvData++ = u16Tou32(pColors[highID]);\n                                            }\n                                            catch\n                                            {\n                                            }\n                                        }\n                                        else\n                                            *pvData++ = u16Tou32(Hues.GetHue(highHue - 1)\n                                                .Colors[(pColors[highID + 0x4000] >> 10) & 0x1F]);\n\n                                        ++pTiles;\n                                    }\n                                }\n                            }\n                            else\n                            {\n                                Tile* pEnd = pTiles + 64;\n\n                                while (pTiles < pEnd)\n                                    *pvData++ = u16Tou32(pColors[(pTiles++)->m_ID]);\n                            }\n                        }\n                    }\n                }\n            }\n\n            return data;\n        }\n\n        /// <summary>\n        /// Draws in given Bitmap with Statics\n        /// </summary>\n        /// <param name=\"x\">8x8 Block</param>\n        /// <param name=\"y\">8x8 Block</param>\n        /// <param name=\"width\">8x8 Block</param>\n        /// <param name=\"height\">8x8 Block</param>\n        /// <param name=\"bmp\">8x8 Block</param>\n        public unsafe void GetImage(int x, int y, int width, int height, Bitmap bmp)\n        {\n            GetImage(x, y, width, height, bmp, true);\n        }\n\n        /// <summary>\n        /// Draws in given Bitmap\n        /// </summary>\n        /// <param name=\"x\">8x8 Block</param>\n        /// <param name=\"y\">8x8 Block</param>\n        /// <param name=\"width\">8x8 Block</param>\n        /// <param name=\"height\">8x8 Block</param>\n        /// <param name=\"bmp\"></param>\n        /// <param name=\"statics\"></param>\n        public unsafe void GetImage(int x, int y, int width, int height, Bitmap bmp, bool statics)\n        {\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width << 3, height << 3), ImageLockMode.WriteOnly,\n                PixelFormat.Format32bppRgb);\n            int stride = bd.Stride;\n            int blockStride = stride << 3;\n\n            byte* pStart = (byte*) bd.Scan0;\n\n            for (int oy = 0, by = y; oy < height; ++oy, ++by, pStart += blockStride)\n            {\n                int* pRow0 = (int*) (pStart + (0 * stride));\n                int* pRow1 = (int*) (pStart + (1 * stride));\n                int* pRow2 = (int*) (pStart + (2 * stride));\n                int* pRow3 = (int*) (pStart + (3 * stride));\n                int* pRow4 = (int*) (pStart + (4 * stride));\n                int* pRow5 = (int*) (pStart + (5 * stride));\n                int* pRow6 = (int*) (pStart + (6 * stride));\n                int* pRow7 = (int*) (pStart + (7 * stride));\n\n                for (int ox = 0, bx = x; ox < width; ++ox, ++bx)\n                {\n                    int[] data = GetRenderedBlock(bx, by, statics);\n\n                    fixed (int* pData = data)\n                    {\n                        int* pvData = (int*) pData;\n\n                        *pRow0++ = *pvData++;\n                        *pRow0++ = *pvData++;\n                        *pRow0++ = *pvData++;\n                        *pRow0++ = *pvData++;\n\n\n                        *pRow0++ = *pvData++;\n                        *pRow0++ = *pvData++;\n                        *pRow0++ = *pvData++;\n                        *pRow0++ = *pvData++;\n\n                        *pRow1++ = *pvData++;\n                        *pRow1++ = *pvData++;\n                        *pRow1++ = *pvData++;\n                        *pRow1++ = *pvData++;\n                        *pRow1++ = *pvData++;\n                        *pRow1++ = *pvData++;\n                        *pRow1++ = *pvData++;\n                        *pRow1++ = *pvData++;\n\n                        *pRow2++ = *pvData++;\n                        *pRow2++ = *pvData++;\n                        *pRow2++ = *pvData++;\n                        *pRow2++ = *pvData++;\n                        *pRow2++ = *pvData++;\n                        *pRow2++ = *pvData++;\n                        *pRow2++ = *pvData++;\n                        *pRow2++ = *pvData++;\n\n                        *pRow3++ = *pvData++;\n                        *pRow3++ = *pvData++;\n                        *pRow3++ = *pvData++;\n                        *pRow3++ = *pvData++;\n                        *pRow3++ = *pvData++;\n                        *pRow3++ = *pvData++;\n                        *pRow3++ = *pvData++;\n                        *pRow3++ = *pvData++;\n\n                        *pRow4++ = *pvData++;\n                        *pRow4++ = *pvData++;\n                        *pRow4++ = *pvData++;\n                        *pRow4++ = *pvData++;\n                        *pRow4++ = *pvData++;\n                        *pRow4++ = *pvData++;\n                        *pRow4++ = *pvData++;\n                        *pRow4++ = *pvData++;\n                        *pRow5++ = *pvData++;\n                        *pRow5++ = *pvData++;\n                        *pRow5++ = *pvData++;\n                        *pRow5++ = *pvData++;\n                        *pRow5++ = *pvData++;\n                        *pRow5++ = *pvData++;\n                        *pRow5++ = *pvData++;\n                        *pRow5++ = *pvData++;\n\n                        *pRow6++ = *pvData++;\n                        *pRow6++ = *pvData++;\n                        *pRow6++ = *pvData++;\n                        *pRow6++ = *pvData++;\n                        *pRow6++ = *pvData++;\n                        *pRow6++ = *pvData++;\n                        *pRow6++ = *pvData++;\n                        *pRow6++ = *pvData++;\n\n                        *pRow7++ = *pvData++;\n                        *pRow7++ = *pvData++;\n                        *pRow7++ = *pvData++;\n                        *pRow7++ = *pvData++;\n                        *pRow7++ = *pvData++;\n                        *pRow7++ = *pvData++;\n                        *pRow7++ = *pvData++;\n                        *pRow7++ = *pvData++;\n                    }\n                }\n            }\n\n            bmp.UnlockBits(bd);\n            m_Tiles.CloseStreams();\n        }\n\n        public static void DefragStatics(string path, Map map, int width, int height, bool remove)\n        {\n            string indexPath = Files.GetFilePath(\"staidx{0}.mul\", map.FileIndex);\n            FileStream m_Index;\n            BinaryReader m_IndexReader;\n            if (indexPath != null)\n            {\n                m_Index = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n                m_IndexReader = new BinaryReader(m_Index);\n            }\n            else\n                return;\n\n            string staticsPath = Files.GetFilePath(\"statics{0}.mul\", map.FileIndex);\n\n            FileStream m_Statics;\n            BinaryReader m_StaticsReader;\n            if (staticsPath != null)\n            {\n                m_Statics = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n                m_StaticsReader = new BinaryReader(m_Statics);\n            }\n            else\n                return;\n\n\n            int blockx = width >> 3;\n            int blocky = height >> 3;\n\n            string idx = Path.Combine(path, $\"staidx{map.FileIndex}.mul\");\n            string mul = Path.Combine(path, $\"statics{map.FileIndex}.mul\");\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                MemoryStream memidx = new MemoryStream();\n                MemoryStream memmul = new MemoryStream();\n                using (BinaryWriter binidx = new BinaryWriter(memidx),\n                    binmul = new BinaryWriter(memmul))\n                {\n                    for (int x = 0; x < blockx; ++x)\n                    {\n                        for (int y = 0; y < blocky; ++y)\n                        {\n                            try\n                            {\n                                m_IndexReader.BaseStream.Seek(((x * blocky) + y) * 12, SeekOrigin.Begin);\n                                int lookup = m_IndexReader.ReadInt32();\n                                int length = m_IndexReader.ReadInt32();\n                                int extra = m_IndexReader.ReadInt32();\n\n                                if (((lookup < 0 || length <= 0)\n                                     && (!map.Tiles.PendingStatic(x, y)))\n                                    || (map.Tiles.IsStaticBlockRemoved(x, y)))\n                                {\n                                    binidx.Write((int) -1); // lookup\n                                    binidx.Write((int) -1); // length\n                                    binidx.Write((int) -1); // extra\n                                }\n                                else\n                                {\n                                    if ((lookup >= 0) && (length > 0))\n                                        m_Statics.Seek(lookup, SeekOrigin.Begin);\n\n                                    int fsmullength = (int) binmul.BaseStream.Position;\n                                    int count = length / 7;\n                                    if (!remove) //without duplicate remove\n                                    {\n                                        bool firstitem = true;\n                                        for (int i = 0; i < count; ++i)\n                                        {\n                                            ushort graphic = m_StaticsReader.ReadUInt16();\n                                            byte sx = m_StaticsReader.ReadByte();\n                                            byte sy = m_StaticsReader.ReadByte();\n                                            sbyte sz = m_StaticsReader.ReadSByte();\n                                            short shue = m_StaticsReader.ReadInt16();\n                                            if ((graphic >= 0) && (graphic <= Art.GetMaxItemID()))\n                                            {\n                                                if (shue < 0)\n                                                    shue = 0;\n                                                if (firstitem)\n                                                {\n                                                    binidx.Write((int) binmul.BaseStream.Position); //lookup\n                                                    firstitem = false;\n                                                }\n\n                                                binmul.Write(graphic);\n                                                binmul.Write(sx);\n                                                binmul.Write(sy);\n                                                binmul.Write(sz);\n                                                binmul.Write(shue);\n                                            }\n                                        }\n\n                                        StaticTile[] tilelist = map.Tiles.GetPendingStatics(x, y);\n                                        if (tilelist != null)\n                                        {\n                                            for (int i = 0; i < tilelist.Length; ++i)\n                                            {\n                                                if ((tilelist[i].m_ID >= 0) && (tilelist[i].m_ID <= Art.GetMaxItemID()))\n                                                {\n                                                    if (tilelist[i].m_Hue < 0)\n                                                        tilelist[i].m_Hue = 0;\n                                                    if (firstitem)\n                                                    {\n                                                        binidx.Write((int) binmul.BaseStream.Position); //lookup\n                                                        firstitem = false;\n                                                    }\n\n                                                    binmul.Write(tilelist[i].m_ID);\n                                                    binmul.Write(tilelist[i].m_X);\n                                                    binmul.Write(tilelist[i].m_Y);\n                                                    binmul.Write(tilelist[i].m_Z);\n                                                    binmul.Write(tilelist[i].m_Hue);\n                                                }\n                                            }\n                                        }\n                                    }\n                                    else //with duplicate remove\n                                    {\n                                        StaticTile[] tilelist = new StaticTile[count];\n                                        int j = 0;\n                                        for (int i = 0; i < count; ++i)\n                                        {\n                                            StaticTile tile = new StaticTile();\n                                            tile.m_ID = m_StaticsReader.ReadUInt16();\n                                            tile.m_X = m_StaticsReader.ReadByte();\n                                            tile.m_Y = m_StaticsReader.ReadByte();\n                                            tile.m_Z = m_StaticsReader.ReadSByte();\n                                            tile.m_Hue = m_StaticsReader.ReadInt16();\n\n                                            if ((tile.m_ID >= 0) && (tile.m_ID <= Art.GetMaxItemID()))\n                                            {\n                                                if (tile.m_Hue < 0)\n                                                    tile.m_Hue = 0;\n                                                bool first = true;\n                                                for (int k = 0; k < j; ++k)\n                                                {\n                                                    if ((tilelist[k].m_ID == tile.m_ID)\n                                                        && ((tilelist[k].m_X == tile.m_X) &&\n                                                            (tilelist[k].m_Y == tile.m_Y))\n                                                        && (tilelist[k].m_Z == tile.m_Z)\n                                                        && (tilelist[k].m_Hue == tile.m_Hue))\n                                                    {\n                                                        first = false;\n                                                        break;\n                                                    }\n                                                }\n\n                                                if (first)\n                                                {\n                                                    tilelist[j] = tile;\n                                                    j++;\n                                                }\n                                            }\n                                        }\n\n                                        if (map.Tiles.PendingStatic(x, y))\n                                        {\n                                            StaticTile[] pending = map.Tiles.GetPendingStatics(x, y);\n                                            StaticTile[] old = tilelist;\n                                            tilelist = new StaticTile[old.Length + pending.Length];\n                                            old.CopyTo(tilelist, 0);\n                                            for (int i = 0; i < pending.Length; ++i)\n                                            {\n                                                if ((pending[i].m_ID >= 0) && (pending[i].m_ID <= Art.GetMaxItemID()))\n                                                {\n                                                    if (pending[i].m_Hue < 0)\n                                                        pending[i].m_Hue = 0;\n                                                    bool first = true;\n                                                    for (int k = 0; k < j; ++k)\n                                                    {\n                                                        if ((tilelist[k].m_ID == pending[i].m_ID)\n                                                            && ((tilelist[k].m_X == pending[i].m_X) &&\n                                                                (tilelist[k].m_Y == pending[i].m_Y))\n                                                            && (tilelist[k].m_Z == pending[i].m_Z)\n                                                            && (tilelist[k].m_Hue == pending[i].m_Hue))\n                                                        {\n                                                            first = false;\n                                                            break;\n                                                        }\n                                                    }\n\n                                                    if (first)\n                                                        tilelist[j++] = pending[i];\n                                                }\n                                            }\n                                        }\n\n                                        if (j > 0)\n                                        {\n                                            binidx.Write((int) binmul.BaseStream.Position); //lookup\n                                            for (int i = 0; i < j; ++i)\n                                            {\n                                                binmul.Write(tilelist[i].m_ID);\n                                                binmul.Write(tilelist[i].m_X);\n                                                binmul.Write(tilelist[i].m_Y);\n                                                binmul.Write(tilelist[i].m_Z);\n                                                binmul.Write(tilelist[i].m_Hue);\n                                            }\n                                        }\n                                    }\n\n                                    fsmullength = (int) binmul.BaseStream.Position - fsmullength;\n                                    if (fsmullength > 0)\n                                    {\n                                        binidx.Write(fsmullength); //length\n                                        if (extra == -1)\n                                            extra = 0;\n                                        binidx.Write(extra); //extra\n                                    }\n                                    else\n                                    {\n                                        binidx.Write((int) -1); //lookup\n                                        binidx.Write((int) -1); //length\n                                        binidx.Write((int) -1); //extra\n                                    }\n                                }\n                            }\n                            catch // fill the rest\n                            {\n                                binidx.BaseStream.Seek(((x * blocky) + y) * 12, SeekOrigin.Begin);\n                                for (; x < blockx; ++x)\n                                {\n                                    for (; y < blocky; ++y)\n                                    {\n                                        binidx.Write((int) -1); //lookup\n                                        binidx.Write((int) -1); //length\n                                        binidx.Write((int) -1); //extra\n                                    }\n\n                                    y = 0;\n                                }\n                            }\n                        }\n                    }\n\n                    memidx.WriteTo(fsidx);\n                    memmul.WriteTo(fsmul);\n                }\n            }\n\n            m_IndexReader.Close();\n            m_StaticsReader.Close();\n        }\n\n        public static void RewriteMap(string path, int map, int width, int height)\n        {\n            string mapPath = Files.GetFilePath(\"map{0}.mul\", map);\n            FileStream m_map;\n            BinaryReader m_mapReader;\n            if (mapPath != null)\n            {\n                m_map = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n                m_mapReader = new BinaryReader(m_map);\n            }\n            else\n                return;\n\n            int blockx = width >> 3;\n            int blocky = height >> 3;\n\n            string mul = Path.Combine(path, $\"map{map}.mul\");\n            using (FileStream fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                MemoryStream memmul = new MemoryStream();\n                using (BinaryWriter binmul = new BinaryWriter(memmul))\n                {\n                    for (int x = 0; x < blockx; ++x)\n                    {\n                        for (int y = 0; y < blocky; ++y)\n                        {\n                            try\n                            {\n                                m_mapReader.BaseStream.Seek(((x * blocky) + y) * 196, SeekOrigin.Begin);\n                                int header = m_mapReader.ReadInt32();\n                                binmul.Write(header);\n                                for (int i = 0; i < 64; ++i)\n                                {\n                                    short tileid = m_mapReader.ReadInt16();\n                                    sbyte z = m_mapReader.ReadSByte();\n                                    if ((tileid < 0) || (tileid >= 0x4000))\n                                        tileid = 0;\n                                    if (z < -128)\n                                        z = -128;\n                                    if (z > 127)\n                                        z = 127;\n                                    binmul.Write(tileid);\n                                    binmul.Write(z);\n                                }\n                            }\n                            catch //fill rest\n                            {\n                                binmul.BaseStream.Seek(((x * blocky) + y) * 196, SeekOrigin.Begin);\n                                for (; x < blockx; ++x)\n                                {\n                                    for (; y < blocky; ++y)\n                                    {\n                                        binmul.Write((int) 0);\n                                        for (int i = 0; i < 64; ++i)\n                                        {\n                                            binmul.Write((short) 0);\n                                            binmul.Write((sbyte) 0);\n                                        }\n                                    }\n\n                                    y = 0;\n                                }\n                            }\n                        }\n                    }\n\n                    memmul.WriteTo(fsmul);\n                }\n            }\n\n            m_mapReader.Close();\n        }\n\n        public void ReportInvisStatics(string reportfile)\n        {\n            reportfile = Path.Combine(reportfile, $\"staticReport-{m_MapID}.csv\");\n            using (StreamWriter Tex =\n                new StreamWriter(new FileStream(reportfile, FileMode.Create, FileAccess.ReadWrite),\n                    System.Text.Encoding.GetEncoding(1252)))\n            {\n                Tex.WriteLine(\"x;y;z;Static\");\n                for (int x = 0; x < m_Width; ++x)\n                {\n                    for (int y = 0; y < m_Height; ++y)\n                    {\n                        Tile currtile = Tiles.GetLandTile(x, y);\n                        foreach (HuedTile currstatic in Tiles.GetStaticTiles(x, y))\n                        {\n                            if (currstatic.Z < currtile.Z)\n                            {\n                                if (TileData.ItemTable[currstatic.ID].Height + currstatic.Z < currtile.Z)\n                                    Tex.WriteLine($\"{x};{y};{currstatic.Z};0x{currstatic.ID:X}\");\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        public void ReportInvalidMapIDs(string reportfile)\n        {\n            reportfile = Path.Combine(reportfile, $\"ReportInvalidMapIDs-{m_MapID}.csv\");\n            using (StreamWriter Tex =\n                new StreamWriter(new FileStream(reportfile, FileMode.Create, FileAccess.ReadWrite),\n                    System.Text.Encoding.GetEncoding(1252)))\n            {\n                Tex.WriteLine(\"x;y;z;Static;LandTile\");\n                for (int x = 0; x < m_Width; ++x)\n                {\n                    for (int y = 0; y < m_Height; ++y)\n                    {\n                        Tile currtile = Tiles.GetLandTile(x, y);\n                        if (!Art.IsValidLand(currtile.ID))\n                            Tex.WriteLine($\"{x};{y};{currtile.Z};0;0x{currtile.ID:X}\");\n                        foreach (HuedTile currstatic in Tiles.GetStaticTiles(x, y))\n                        {\n                            if (!Art.IsValidStatic(currstatic.ID))\n                                Tex.WriteLine($\"{x};{y};{currstatic.Z};0x{currstatic.ID:X};0\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/MultiMap.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\nusing System;\n\nnamespace Ultima\n{\n    public sealed class MultiMap\n    {\n        private static byte[] m_StreamBuffer;\n\n        static MultiMap()\n        {\n        }\n\n        /// <summary>\n        /// Returns Bitmap\n        /// </summary>\n        /// <returns></returns>\n        public static unsafe Bitmap GetMultiMap()\n        {\n            string path = Files.GetFilePath(\"Multimap.rle\");\n            if (path != null)\n            {\n                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    using (BinaryReader bin = new BinaryReader(fs))\n                    {\n                        int width, height;\n                        byte pixel;\n                        int count;\n                        int x, i;\n                        x = 0;\n                        ushort c = 0;\n                        width = bin.ReadInt32();\n                        height = bin.ReadInt32();\n                        Bitmap multimap = new Bitmap(width, height, PixelFormat.Format16bppArgb1555);\n                        BitmapData bd = multimap.LockBits(new Rectangle(0, 0, multimap.Width, multimap.Height),\n                            ImageLockMode.WriteOnly, PixelFormat.Format16bppArgb1555);\n                        ushort* line = (ushort*) bd.Scan0;\n                        int delta = bd.Stride >> 1;\n\n                        ushort* cur = line;\n                        int len = (int) (bin.BaseStream.Length - bin.BaseStream.Position);\n                        if (m_StreamBuffer == null || m_StreamBuffer.Length < len)\n                            m_StreamBuffer = new byte[len];\n                        bin.Read(m_StreamBuffer, 0, len);\n                        int j = 0;\n                        while (j != len)\n                        {\n                            pixel = m_StreamBuffer[j++];\n                            count = (pixel & 0x7f);\n\n                            if ((pixel & 0x80) != 0)\n                                c = 0x8000; //Color.Black;\n                            else\n                                c = 0xffff; //Color.White;\n                            for (i = 0; i < count; ++i)\n                            {\n                                cur[x++] = c;\n                                if (x >= width)\n                                {\n                                    cur += delta;\n                                    x = 0;\n                                }\n                            }\n                        }\n\n                        multimap.UnlockBits(bd);\n                        return multimap;\n                    }\n                }\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Saves Bitmap to rle Format\n        /// </summary>\n        /// <param name=\"image\"></param>\n        /// <param name=\"bin\"></param>\n        public static unsafe void SaveMultiMap(Bitmap image, BinaryWriter bin)\n        {\n            bin.Write(2560); // width\n            bin.Write(2048); // height\n            byte data = 1;\n            byte mask = 0x0;\n            ushort curcolor = 0;\n            BitmapData bd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly,\n                PixelFormat.Format16bppArgb1555);\n            ushort* line = (ushort*) bd.Scan0;\n            int delta = bd.Stride >> 1;\n            ushort* cur = line;\n            curcolor = cur[0]; //init\n            for (int y = 0; y < image.Height; ++y, line += delta)\n            {\n                cur = line;\n                for (int x = 0; x < image.Width; ++x)\n                {\n                    ushort c = cur[x];\n\n                    if (c == curcolor)\n                    {\n                        ++data;\n                        if (data == 0x7f)\n                        {\n                            if (curcolor == 0xffff)\n                                mask = 0x0;\n                            else\n                                mask = 0x80;\n                            data |= mask;\n                            bin.Write(data);\n                            data = 1;\n                        }\n                    }\n                    else\n                    {\n                        if (curcolor == 0xffff)\n                            mask = 0x0;\n                        else\n                            mask = 0x80;\n                        data |= mask;\n                        bin.Write(data);\n                        curcolor = c;\n                        data = 1;\n                    }\n                }\n            }\n\n            if (curcolor == 0xffff)\n                mask = 0x0;\n            else\n                mask = 0x80;\n            data |= mask;\n            bin.Write(data);\n            image.UnlockBits(bd);\n        }\n\n        /// <summary>\n        /// reads facet0*.mul into Bitmap\n        /// </summary>\n        /// <param name=\"id\">facet id</param>\n        /// <returns>Bitmap</returns>\n        public static unsafe Bitmap GetFacetImage(int id)\n        {\n            Bitmap bmp;\n            string path = Files.GetFilePath($\"facet0{id}.mul\");\n            if (path != null)\n            {\n                using (BinaryReader reader =\n                    new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)))\n                {\n                    int width = reader.ReadInt16();\n                    int height = reader.ReadInt16();\n\n                    bmp = new Bitmap(width, height);\n                    BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly,\n                        PixelFormat.Format16bppArgb1555);\n                    ushort* line = (ushort*) bd.Scan0;\n                    int delta = bd.Stride >> 1;\n\n                    for (int y = 0; y < height; y++, line += delta)\n                    {\n                        int colorsCount = reader.ReadInt32() / 3;\n                        ushort* endline = line + delta;\n                        ushort* cur = line;\n                        ushort* end;\n                        for (int c = 0; c < colorsCount; c++)\n                        {\n                            byte count = reader.ReadByte();\n                            short color = reader.ReadInt16();\n                            end = cur + count;\n                            while (cur < end)\n                            {\n                                if (cur > endline)\n                                    break;\n                                *cur++ = (ushort) (color ^ 0x8000);\n                            }\n                        }\n                    }\n\n                    bmp.UnlockBits(bd);\n                }\n\n                return bmp;\n            }\n\n            return null;\n        }\n\n        /// <summary>\n        /// Stores Image into facet.mul format\n        /// </summary>\n        /// <param name=\"path\"></param>\n        /// <param name=\"sourceBitmap\"></param>\n        public static unsafe void SaveFacetImage(string path, Bitmap sourceBitmap)\n        {\n            int width = sourceBitmap.Width;\n            int height = sourceBitmap.Height;\n\n            using (BinaryWriter writer =\n                new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)))\n            {\n                writer.Write((short) width);\n                writer.Write((short) height);\n                BitmapData bd = sourceBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly,\n                    PixelFormat.Format16bppArgb1555);\n                ushort* line = (ushort*) bd.Scan0;\n                int delta = bd.Stride >> 1;\n                for (int y = 0; y < height; y++, line += delta)\n                {\n                    long pos = writer.BaseStream.Position;\n                    writer.Write(0); //bytes count for current line\n\n                    int colorsAtLine = 0;\n                    int colorsCount = 0;\n                    int x = 0;\n\n                    while (x < width)\n                    {\n                        ushort hue = line[x];\n                        while (x < width && colorsCount < byte.MaxValue && hue == line[x])\n                        {\n                            ++colorsCount;\n                            ++x;\n                        }\n\n                        writer.Write((byte) colorsCount);\n                        writer.Write((ushort) (hue ^ 0x8000));\n\n                        colorsAtLine++;\n                        colorsCount = 0;\n                    }\n\n                    long currpos = writer.BaseStream.Position;\n                    writer.BaseStream.Seek(pos, SeekOrigin.Begin);\n                    writer.Write(colorsAtLine * 3); //byte count\n                    writer.BaseStream.Seek(currpos, SeekOrigin.Begin);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Multis.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.IO;\nusing System.Text.RegularExpressions;\n\nnamespace Ultima\n{\n    public sealed class Multis\n    {\n        private static MultiComponentList[] m_Components = new MultiComponentList[0x2000];\n        private static FileIndex m_FileIndex = new FileIndex(\"Multi.idx\", \"Multi.mul\", 0x2000, 14);\n\n        public enum ImportType\n        {\n            TXT,\n            UOA,\n            UOAB,\n            WSC,\n            MULTICACHE,\n            UOADESIGN\n        }\n\n        public static bool PostHSFormat { get; set; }\n\n        /// <summary>\n        /// ReReads multi.mul\n        /// </summary>\n        public static void Reload()\n        {\n            m_FileIndex = new FileIndex(\"Multi.idx\", \"Multi.mul\", 0x2000, 14);\n            m_Components = new MultiComponentList[0x2000];\n        }\n\n        /// <summary>\n        /// Gets <see cref=\"MultiComponentList\"/> of multi\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static MultiComponentList GetComponents(int index)\n        {\n            MultiComponentList mcl;\n\n            index &= 0x1FFF;\n\n            if (index >= 0 && index < m_Components.Length)\n            {\n                mcl = m_Components[index];\n\n                if (mcl == null)\n                    m_Components[index] = mcl = Load(index);\n            }\n            else\n                mcl = MultiComponentList.Empty;\n\n            return mcl;\n        }\n\n        public static MultiComponentList Load(int index)\n        {\n            try\n            {\n                int length, extra;\n                bool patched;\n                Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n\n                if (stream == null)\n                    return MultiComponentList.Empty;\n\n                if (PostHSFormat || Art.IsUOAHS())\n                    return new MultiComponentList(new BinaryReader(stream), length / 16);\n                else\n                    return new MultiComponentList(new BinaryReader(stream), length / 12);\n            }\n            catch\n            {\n                return MultiComponentList.Empty;\n            }\n        }\n\n        public static void Remove(int index)\n        {\n            m_Components[index] = MultiComponentList.Empty;\n        }\n\n        public static void Add(int index, MultiComponentList comp)\n        {\n            m_Components[index] = comp;\n        }\n\n        public static MultiComponentList ImportFromFile(int index, string FileName, Multis.ImportType type)\n        {\n            try\n            {\n                return m_Components[index] = new MultiComponentList(FileName, type);\n            }\n            catch\n            {\n                return m_Components[index] = MultiComponentList.Empty;\n            }\n        }\n\n        public static MultiComponentList LoadFromFile(string FileName, Multis.ImportType type)\n        {\n            try\n            {\n                return new MultiComponentList(FileName, type);\n            }\n            catch\n            {\n                return MultiComponentList.Empty;\n            }\n        }\n\n        public static List<MultiComponentList> LoadFromCache(string FileName)\n        {\n            List<MultiComponentList> multilist = new List<MultiComponentList>();\n            using (StreamReader ip = new StreamReader(FileName))\n            {\n                string line;\n                while ((line = ip.ReadLine()) != null)\n                {\n                    string[] split = Regex.Split(line, @\"\\s+\");\n                    if (split.Length == 7)\n                    {\n                        int count = Convert.ToInt32(split[2]);\n                        multilist.Add(new MultiComponentList(ip, count));\n                    }\n                }\n            }\n\n            return multilist;\n        }\n\n        public static string ReadUOAString(BinaryReader bin)\n        {\n            byte flag = bin.ReadByte();\n\n            if (flag == 0)\n                return null;\n            else\n                return bin.ReadString();\n        }\n\n        public static List<Object[]> LoadFromDesigner(string FileName)\n        {\n            List<Object[]> multilist = new List<Object[]>();\n            string root = Path.GetFileNameWithoutExtension(FileName);\n            string idx = $\"{root}.idx\";\n            string bin = $\"{root}.bin\";\n            if ((!File.Exists(idx)) || (!File.Exists(bin)))\n                return multilist;\n            using (FileStream idxfs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.Read),\n                binfs = new FileStream(bin, FileMode.Open, FileAccess.Read, FileShare.Read))\n            {\n                using (BinaryReader idxbin = new BinaryReader(idxfs),\n                    binbin = new BinaryReader(binfs))\n                {\n                    int count = idxbin.ReadInt32();\n                    int version = idxbin.ReadInt32();\n\n                    for (int i = 0; i < count; ++i)\n                    {\n                        Object[] data = new Object[2];\n                        switch (version)\n                        {\n                            case 0:\n                                data[0] = ReadUOAString(idxbin);\n                                List<MultiComponentList.MultiTileEntry> arr =\n                                    new List<MultiComponentList.MultiTileEntry>();\n                                data[0] += \"-\" + ReadUOAString(idxbin);\n                                data[0] += \"-\" + ReadUOAString(idxbin);\n                                int width = idxbin.ReadInt32();\n                                int height = idxbin.ReadInt32();\n                                int uwidth = idxbin.ReadInt32();\n                                int uheight = idxbin.ReadInt32();\n                                long filepos = idxbin.ReadInt64();\n                                int reccount = idxbin.ReadInt32();\n\n                                binbin.BaseStream.Seek(filepos, SeekOrigin.Begin);\n                                int index, x, y, z, level, hue;\n                                for (int j = 0; j < reccount; ++j)\n                                {\n                                    index = x = y = z = level = hue = 0;\n                                    int compVersion = binbin.ReadInt32();\n                                    switch (compVersion)\n                                    {\n                                        case 0:\n                                            index = binbin.ReadInt32();\n                                            x = binbin.ReadInt32();\n                                            y = binbin.ReadInt32();\n                                            z = binbin.ReadInt32();\n                                            level = binbin.ReadInt32();\n                                            break;\n\n                                        case 1:\n                                            index = binbin.ReadInt32();\n                                            x = binbin.ReadInt32();\n                                            y = binbin.ReadInt32();\n                                            z = binbin.ReadInt32();\n                                            level = binbin.ReadInt32();\n                                            hue = binbin.ReadInt32();\n                                            break;\n                                    }\n\n                                    MultiComponentList.MultiTileEntry\n                                        tempitem = new MultiComponentList.MultiTileEntry();\n                                    tempitem.m_ItemID = (ushort) index;\n                                    tempitem.m_Flags = 1;\n                                    tempitem.m_OffsetX = (short) x;\n                                    tempitem.m_OffsetY = (short) y;\n                                    tempitem.m_OffsetZ = (short) z;\n                                    tempitem.m_Unk1 = 0;\n                                    arr.Add(tempitem);\n                                }\n\n                                data[1] = new MultiComponentList(arr);\n                                break;\n                        }\n\n                        multilist.Add(data);\n                    }\n                }\n\n                return multilist;\n            }\n        }\n\n        public static List<MultiComponentList.MultiTileEntry> RebuildTiles(MultiComponentList.MultiTileEntry[] tiles)\n        {\n            List<MultiComponentList.MultiTileEntry> newtiles = new List<MultiComponentList.MultiTileEntry>();\n            newtiles.AddRange(tiles);\n\n            if (newtiles[0].m_OffsetX == 0 && newtiles[0].m_OffsetY == 0 && newtiles[0].m_OffsetZ == 0\n            ) // found a centeritem\n            {\n                if (newtiles[0].m_ItemID != 0x1) // its a \"good\" one\n                {\n                    for (int j = newtiles.Count - 1; j >= 0; --j) // remove all invis items\n                    {\n                        if (newtiles[j].m_ItemID == 0x1)\n                            newtiles.RemoveAt(j);\n                    }\n\n                    return newtiles;\n                }\n                else // a bad one\n                {\n                    for (int i = 1; i < newtiles.Count; ++i) // do we have a better one?\n                    {\n                        if (newtiles[i].m_OffsetX == 0 && newtiles[i].m_OffsetY == 0\n                                                       && newtiles[i].m_ItemID != 0x1 && newtiles[i].m_OffsetZ == 0)\n                        {\n                            MultiComponentList.MultiTileEntry centeritem = newtiles[i];\n                            newtiles.RemoveAt(i); // jep so save it\n                            for (int j = newtiles.Count - 1; j >= 0; --j) // and remove all invis\n                            {\n                                if (newtiles[j].m_ItemID == 0x1)\n                                    newtiles.RemoveAt(j);\n                            }\n\n                            newtiles.Insert(0, centeritem);\n                            return newtiles;\n                        }\n                    }\n\n                    for (int j = newtiles.Count - 1; j >= 1; --j) // nothing found so remove all invis exept the first\n                    {\n                        if (newtiles[j].m_ItemID == 0x1)\n                            newtiles.RemoveAt(j);\n                    }\n\n                    return newtiles;\n                }\n            }\n\n            for (int i = 0; i < newtiles.Count; ++i) // is there a good one\n            {\n                if (newtiles[i].m_OffsetX == 0 && newtiles[i].m_OffsetY == 0\n                                               && newtiles[i].m_ItemID != 0x1 && newtiles[i].m_OffsetZ == 0)\n                {\n                    MultiComponentList.MultiTileEntry centeritem = newtiles[i];\n                    newtiles.RemoveAt(i); // store it\n                    for (int j = newtiles.Count - 1; j >= 0; --j) // remove all invis\n                    {\n                        if (newtiles[j].m_ItemID == 0x1)\n                            newtiles.RemoveAt(j);\n                    }\n\n                    newtiles.Insert(0, centeritem);\n                    return newtiles;\n                }\n            }\n\n            for (int j = newtiles.Count - 1; j >= 0; --j) // nothing found so remove all invis\n            {\n                if (newtiles[j].m_ItemID == 0x1)\n                    newtiles.RemoveAt(j);\n            }\n\n            MultiComponentList.MultiTileEntry invisitem = new MultiComponentList.MultiTileEntry();\n            invisitem.m_ItemID = 0x1; // and create a new invis\n            invisitem.m_OffsetX = 0;\n            invisitem.m_OffsetY = 0;\n            invisitem.m_OffsetZ = 0;\n            invisitem.m_Flags = 0;\n            invisitem.m_Unk1 = 0;\n            newtiles.Insert(0, invisitem);\n            return newtiles;\n        }\n\n        public static void Save(string path)\n        {\n            bool isUOAHS = PostHSFormat || Art.IsUOAHS();\n            string idx = Path.Combine(path, \"multi.idx\");\n            string mul = Path.Combine(path, \"multi.mul\");\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter binidx = new BinaryWriter(fsidx),\n                    binmul = new BinaryWriter(fsmul))\n                {\n                    for (int index = 0; index < 0x2000; ++index)\n                    {\n                        MultiComponentList comp = GetComponents(index);\n\n                        if (comp == MultiComponentList.Empty)\n                        {\n                            binidx.Write((int) -1); // lookup\n                            binidx.Write((int) -1); // length\n                            binidx.Write((int) -1); // extra\n                        }\n                        else\n                        {\n                            List<MultiComponentList.MultiTileEntry> tiles = RebuildTiles(comp.SortedTiles);\n                            binidx.Write((int) fsmul.Position); //lookup\n                            if (isUOAHS)\n                                binidx.Write((int) (tiles.Count * 16)); //length\n                            else\n                                binidx.Write((int) (tiles.Count * 12)); //length\n                            binidx.Write((int) -1); //extra\n                            for (int i = 0; i < tiles.Count; ++i)\n                            {\n                                binmul.Write((ushort) tiles[i].m_ItemID);\n                                binmul.Write((short) tiles[i].m_OffsetX);\n                                binmul.Write((short) tiles[i].m_OffsetY);\n                                binmul.Write((short) tiles[i].m_OffsetZ);\n                                binmul.Write((int) tiles[i].m_Flags);\n                                if (isUOAHS)\n                                    binmul.Write((int) tiles[i].m_Unk1);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public sealed class MultiComponentList\n    {\n        private Point m_Min, m_Max, m_Center;\n        private int m_Width, m_Height, m_maxHeight, m_Surface;\n        private MTile[][][] m_Tiles;\n        private MultiTileEntry[] m_SortedTiles;\n\n        public static readonly MultiComponentList Empty = new MultiComponentList();\n\n        public Point Min\n        {\n            get { return m_Min; }\n        }\n\n        public Point Max\n        {\n            get { return m_Max; }\n        }\n\n        public Point Center\n        {\n            get { return m_Center; }\n        }\n\n        public int Width\n        {\n            get { return m_Width; }\n        }\n\n        public int Height\n        {\n            get { return m_Height; }\n        }\n\n        public MTile[][][] Tiles\n        {\n            get { return m_Tiles; }\n        }\n\n        public int maxHeight\n        {\n            get { return m_maxHeight; }\n        }\n\n        public MultiTileEntry[] SortedTiles\n        {\n            get { return m_SortedTiles; }\n        }\n\n        public int Surface\n        {\n            get { return m_Surface; }\n        }\n\n\n        public struct MultiTileEntry\n        {\n            public ushort m_ItemID;\n            public short m_OffsetX, m_OffsetY, m_OffsetZ;\n            public int m_Flags;\n            public int m_Unk1;\n        }\n\n        /// <summary>\n        /// Returns Bitmap of Multi\n        /// </summary>\n        /// <returns></returns>\n        public Bitmap GetImage()\n        {\n            return GetImage(300);\n        }\n\n        /// <summary>\n        /// Returns Bitmap of Multi to maxheight\n        /// </summary>\n        /// <param name=\"maxheight\"></param>\n        /// <returns></returns>\n        public Bitmap GetImage(int maxheight)\n        {\n            if (m_Width == 0 || m_Height == 0)\n                return null;\n\n            int xMin = 1000, yMin = 1000;\n            int xMax = -1000, yMax = -1000;\n\n            for (int x = 0; x < m_Width; ++x)\n            {\n                for (int y = 0; y < m_Height; ++y)\n                {\n                    MTile[] tiles = m_Tiles[x][y];\n\n                    for (int i = 0; i < tiles.Length; ++i)\n                    {\n                        Bitmap bmp = Art.GetStatic(tiles[i].ID);\n\n                        if (bmp == null)\n                            continue;\n\n                        int px = (x - y) * 22;\n                        int py = (x + y) * 22;\n\n                        px -= (bmp.Width / 2);\n                        py -= tiles[i].Z << 2;\n                        py -= bmp.Height;\n\n                        if (px < xMin)\n                            xMin = px;\n\n                        if (py < yMin)\n                            yMin = py;\n\n                        px += bmp.Width;\n                        py += bmp.Height;\n\n                        if (px > xMax)\n                            xMax = px;\n\n                        if (py > yMax)\n                            yMax = py;\n                    }\n                }\n            }\n\n            Bitmap canvas = new Bitmap(xMax - xMin, yMax - yMin);\n            Graphics gfx = Graphics.FromImage(canvas);\n            gfx.Clear(Color.White);\n            for (int x = 0; x < m_Width; ++x)\n            {\n                for (int y = 0; y < m_Height; ++y)\n                {\n                    MTile[] tiles = m_Tiles[x][y];\n\n                    for (int i = 0; i < tiles.Length; ++i)\n                    {\n                        Bitmap bmp = Art.GetStatic(tiles[i].ID);\n\n                        if (bmp == null)\n                            continue;\n                        if ((tiles[i].Z) > maxheight)\n                            continue;\n                        int px = (x - y) * 22;\n                        int py = (x + y) * 22;\n\n                        px -= (bmp.Width / 2);\n                        py -= tiles[i].Z << 2;\n                        py -= bmp.Height;\n                        px -= xMin;\n                        py -= yMin;\n\n                        gfx.DrawImageUnscaled(bmp, px, py, bmp.Width, bmp.Height);\n                    }\n\n                    int tx = (x - y) * 22;\n                    int ty = (x + y) * 22;\n                    tx -= xMin;\n                    ty -= yMin;\n                }\n            }\n\n            gfx.Dispose();\n\n            return canvas;\n        }\n\n        public MultiComponentList(BinaryReader reader, int count)\n        {\n            bool useNewMultiFormat = Multis.PostHSFormat || Art.IsUOAHS();\n            m_Min = m_Max = Point.Empty;\n            m_SortedTiles = new MultiTileEntry[count];\n            for (int i = 0; i < count; ++i)\n            {\n                m_SortedTiles[i].m_ItemID = Art.GetLegalItemID(reader.ReadUInt16());\n                m_SortedTiles[i].m_OffsetX = reader.ReadInt16();\n                m_SortedTiles[i].m_OffsetY = reader.ReadInt16();\n                m_SortedTiles[i].m_OffsetZ = reader.ReadInt16();\n                m_SortedTiles[i].m_Flags = reader.ReadInt32();\n                if (useNewMultiFormat)\n                    m_SortedTiles[i].m_Unk1 = reader.ReadInt32();\n                else\n                    m_SortedTiles[i].m_Unk1 = 0;\n\n                MultiTileEntry e = m_SortedTiles[i];\n\n                if (e.m_OffsetX < m_Min.X)\n                    m_Min.X = e.m_OffsetX;\n\n                if (e.m_OffsetY < m_Min.Y)\n                    m_Min.Y = e.m_OffsetY;\n\n                if (e.m_OffsetX > m_Max.X)\n                    m_Max.X = e.m_OffsetX;\n\n                if (e.m_OffsetY > m_Max.Y)\n                    m_Max.Y = e.m_OffsetY;\n\n                if (e.m_OffsetZ > m_maxHeight)\n                    m_maxHeight = e.m_OffsetZ;\n            }\n\n            ConvertList();\n            reader.Close();\n        }\n\n        public MultiComponentList(string FileName, Multis.ImportType Type)\n        {\n            m_Min = m_Max = Point.Empty;\n            int itemcount;\n            switch (Type)\n            {\n                case Multis.ImportType.TXT:\n                    itemcount = 0;\n                    using (StreamReader ip = new StreamReader(FileName))\n                    {\n                        string line;\n                        while ((line = ip.ReadLine()) != null)\n                        {\n                            itemcount++;\n                        }\n                    }\n\n                    m_SortedTiles = new MultiTileEntry[itemcount];\n                    itemcount = 0;\n                    m_Min.X = 10000;\n                    m_Min.Y = 10000;\n                    using (StreamReader ip = new StreamReader(FileName))\n                    {\n                        string line;\n                        while ((line = ip.ReadLine()) != null)\n                        {\n                            string[] split = line.Split(' ');\n\n                            string tmp = split[0];\n                            tmp = tmp.Replace(\"0x\", \"\");\n\n                            m_SortedTiles[itemcount].m_ItemID =\n                                ushort.Parse(tmp, System.Globalization.NumberStyles.HexNumber);\n                            m_SortedTiles[itemcount].m_OffsetX = Convert.ToInt16(split[1]);\n                            m_SortedTiles[itemcount].m_OffsetY = Convert.ToInt16(split[2]);\n                            m_SortedTiles[itemcount].m_OffsetZ = Convert.ToInt16(split[3]);\n                            m_SortedTiles[itemcount].m_Flags = Convert.ToInt32(split[4]);\n                            m_SortedTiles[itemcount].m_Unk1 = 0;\n\n                            MultiTileEntry e = m_SortedTiles[itemcount];\n\n                            if (e.m_OffsetX < m_Min.X)\n                                m_Min.X = e.m_OffsetX;\n\n                            if (e.m_OffsetY < m_Min.Y)\n                                m_Min.Y = e.m_OffsetY;\n\n                            if (e.m_OffsetX > m_Max.X)\n                                m_Max.X = e.m_OffsetX;\n\n                            if (e.m_OffsetY > m_Max.Y)\n                                m_Max.Y = e.m_OffsetY;\n\n                            if (e.m_OffsetZ > m_maxHeight)\n                                m_maxHeight = e.m_OffsetZ;\n\n                            itemcount++;\n                        }\n\n                        int centerx = m_Max.X - (int) (Math.Round((m_Max.X - m_Min.X) / 2.0));\n                        int centery = m_Max.Y - (int) (Math.Round((m_Max.Y - m_Min.Y) / 2.0));\n\n                        m_Min = m_Max = Point.Empty;\n                        int i = 0;\n                        for (; i < m_SortedTiles.Length; i++)\n                        {\n                            m_SortedTiles[i].m_OffsetX -= (short) centerx;\n                            m_SortedTiles[i].m_OffsetY -= (short) centery;\n                            if (m_SortedTiles[i].m_OffsetX < m_Min.X)\n                                m_Min.X = m_SortedTiles[i].m_OffsetX;\n                            if (m_SortedTiles[i].m_OffsetX > m_Max.X)\n                                m_Max.X = m_SortedTiles[i].m_OffsetX;\n\n                            if (m_SortedTiles[i].m_OffsetY < m_Min.Y)\n                                m_Min.Y = m_SortedTiles[i].m_OffsetY;\n                            if (m_SortedTiles[i].m_OffsetY > m_Max.Y)\n                                m_Max.Y = m_SortedTiles[i].m_OffsetY;\n                        }\n                    }\n\n                    break;\n                case Multis.ImportType.UOA:\n                    itemcount = 0;\n\n                    using (StreamReader ip = new StreamReader(FileName))\n                    {\n                        string line;\n                        while ((line = ip.ReadLine()) != null)\n                        {\n                            ++itemcount;\n                            if (itemcount == 4)\n                            {\n                                string[] split = line.Split(' ');\n                                itemcount = Convert.ToInt32(split[0]);\n                                break;\n                            }\n                        }\n                    }\n\n                    m_SortedTiles = new MultiTileEntry[itemcount];\n                    itemcount = 0;\n                    m_Min.X = 10000;\n                    m_Min.Y = 10000;\n                    using (StreamReader ip = new StreamReader(FileName))\n                    {\n                        string line;\n                        int i = -1;\n                        while ((line = ip.ReadLine()) != null)\n                        {\n                            ++i;\n                            if (i < 4)\n                                continue;\n                            string[] split = line.Split(' ');\n\n                            m_SortedTiles[itemcount].m_ItemID = Convert.ToUInt16(split[0]);\n                            m_SortedTiles[itemcount].m_OffsetX = Convert.ToInt16(split[1]);\n                            m_SortedTiles[itemcount].m_OffsetY = Convert.ToInt16(split[2]);\n                            m_SortedTiles[itemcount].m_OffsetZ = Convert.ToInt16(split[3]);\n                            m_SortedTiles[itemcount].m_Flags = Convert.ToInt32(split[4]);\n                            m_SortedTiles[itemcount].m_Unk1 = 0;\n\n                            MultiTileEntry e = m_SortedTiles[itemcount];\n\n                            if (e.m_OffsetX < m_Min.X)\n                                m_Min.X = e.m_OffsetX;\n\n                            if (e.m_OffsetY < m_Min.Y)\n                                m_Min.Y = e.m_OffsetY;\n\n                            if (e.m_OffsetX > m_Max.X)\n                                m_Max.X = e.m_OffsetX;\n\n                            if (e.m_OffsetY > m_Max.Y)\n                                m_Max.Y = e.m_OffsetY;\n\n                            if (e.m_OffsetZ > m_maxHeight)\n                                m_maxHeight = e.m_OffsetZ;\n\n                            ++itemcount;\n                        }\n\n                        int centerx = m_Max.X - (int) (Math.Round((m_Max.X - m_Min.X) / 2.0));\n                        int centery = m_Max.Y - (int) (Math.Round((m_Max.Y - m_Min.Y) / 2.0));\n\n                        m_Min = m_Max = Point.Empty;\n                        i = 0;\n                        for (; i < m_SortedTiles.Length; ++i)\n                        {\n                            m_SortedTiles[i].m_OffsetX -= (short) centerx;\n                            m_SortedTiles[i].m_OffsetY -= (short) centery;\n                            if (m_SortedTiles[i].m_OffsetX < m_Min.X)\n                                m_Min.X = m_SortedTiles[i].m_OffsetX;\n                            if (m_SortedTiles[i].m_OffsetX > m_Max.X)\n                                m_Max.X = m_SortedTiles[i].m_OffsetX;\n\n                            if (m_SortedTiles[i].m_OffsetY < m_Min.Y)\n                                m_Min.Y = m_SortedTiles[i].m_OffsetY;\n                            if (m_SortedTiles[i].m_OffsetY > m_Max.Y)\n                                m_Max.Y = m_SortedTiles[i].m_OffsetY;\n                        }\n                    }\n\n                    break;\n                case Multis.ImportType.UOAB:\n                    using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read))\n                    using (BinaryReader reader = new BinaryReader(fs))\n                    {\n                        if (reader.ReadInt16() != 1) //Version check\n                            return;\n                        string tmp;\n                        tmp = Multis.ReadUOAString(reader); //Name\n                        tmp = Multis.ReadUOAString(reader); //Category\n                        tmp = Multis.ReadUOAString(reader); //Subsection\n                        int width = reader.ReadInt32();\n                        int height = reader.ReadInt32();\n                        int uwidth = reader.ReadInt32();\n                        int uheight = reader.ReadInt32();\n\n                        int count = reader.ReadInt32();\n                        itemcount = count;\n                        m_SortedTiles = new MultiTileEntry[itemcount];\n                        itemcount = 0;\n                        m_Min.X = 10000;\n                        m_Min.Y = 10000;\n                        for (; itemcount < count; ++itemcount)\n                        {\n                            m_SortedTiles[itemcount].m_ItemID = (ushort) reader.ReadInt16();\n                            m_SortedTiles[itemcount].m_OffsetX = reader.ReadInt16();\n                            m_SortedTiles[itemcount].m_OffsetY = reader.ReadInt16();\n                            m_SortedTiles[itemcount].m_OffsetZ = reader.ReadInt16();\n                            reader.ReadInt16(); // level\n                            m_SortedTiles[itemcount].m_Flags = 1;\n                            reader.ReadInt16(); // hue\n                            m_SortedTiles[itemcount].m_Unk1 = 0;\n\n                            MultiTileEntry e = m_SortedTiles[itemcount];\n\n                            if (e.m_OffsetX < m_Min.X)\n                                m_Min.X = e.m_OffsetX;\n\n                            if (e.m_OffsetY < m_Min.Y)\n                                m_Min.Y = e.m_OffsetY;\n\n                            if (e.m_OffsetX > m_Max.X)\n                                m_Max.X = e.m_OffsetX;\n\n                            if (e.m_OffsetY > m_Max.Y)\n                                m_Max.Y = e.m_OffsetY;\n\n                            if (e.m_OffsetZ > m_maxHeight)\n                                m_maxHeight = e.m_OffsetZ;\n                        }\n\n                        int centerx = m_Max.X - (int) (Math.Round((m_Max.X - m_Min.X) / 2.0));\n                        int centery = m_Max.Y - (int) (Math.Round((m_Max.Y - m_Min.Y) / 2.0));\n\n                        m_Min = m_Max = Point.Empty;\n                        itemcount = 0;\n                        for (; itemcount < m_SortedTiles.Length; ++itemcount)\n                        {\n                            m_SortedTiles[itemcount].m_OffsetX -= (short) centerx;\n                            m_SortedTiles[itemcount].m_OffsetY -= (short) centery;\n                            if (m_SortedTiles[itemcount].m_OffsetX < m_Min.X)\n                                m_Min.X = m_SortedTiles[itemcount].m_OffsetX;\n                            if (m_SortedTiles[itemcount].m_OffsetX > m_Max.X)\n                                m_Max.X = m_SortedTiles[itemcount].m_OffsetX;\n\n                            if (m_SortedTiles[itemcount].m_OffsetY < m_Min.Y)\n                                m_Min.Y = m_SortedTiles[itemcount].m_OffsetY;\n                            if (m_SortedTiles[itemcount].m_OffsetY > m_Max.Y)\n                                m_Max.Y = m_SortedTiles[itemcount].m_OffsetY;\n                        }\n                    }\n\n                    break;\n\n                case Multis.ImportType.WSC:\n                    itemcount = 0;\n                    using (StreamReader ip = new StreamReader(FileName))\n                    {\n                        string line;\n                        while ((line = ip.ReadLine()) != null)\n                        {\n                            line = line.Trim();\n                            if (line.StartsWith(\"SECTION WORLDITEM\"))\n                                ++itemcount;\n                        }\n                    }\n\n                    m_SortedTiles = new MultiTileEntry[itemcount];\n                    itemcount = 0;\n                    m_Min.X = 10000;\n                    m_Min.Y = 10000;\n                    using (StreamReader ip = new StreamReader(FileName))\n                    {\n                        string line;\n                        MultiTileEntry tempitem = new MultiTileEntry();\n                        tempitem.m_ItemID = 0xFFFF;\n                        tempitem.m_Flags = 1;\n                        tempitem.m_Unk1 = 0;\n                        while ((line = ip.ReadLine()) != null)\n                        {\n                            line = line.Trim();\n                            if (line.StartsWith(\"SECTION WORLDITEM\"))\n                            {\n                                if (tempitem.m_ItemID != 0xFFFF)\n                                {\n                                    m_SortedTiles[itemcount] = tempitem;\n                                    ++itemcount;\n                                }\n\n                                tempitem.m_ItemID = 0xFFFF;\n                            }\n                            else if (line.StartsWith(\"ID\"))\n                            {\n                                line = line.Remove(0, 2);\n                                line = line.Trim();\n                                tempitem.m_ItemID = Convert.ToUInt16(line);\n                            }\n                            else if (line.StartsWith(\"X\"))\n                            {\n                                line = line.Remove(0, 1);\n                                line = line.Trim();\n                                tempitem.m_OffsetX = Convert.ToInt16(line);\n                                if (tempitem.m_OffsetX < m_Min.X)\n                                    m_Min.X = tempitem.m_OffsetX;\n                                if (tempitem.m_OffsetX > m_Max.X)\n                                    m_Max.X = tempitem.m_OffsetX;\n                            }\n                            else if (line.StartsWith(\"Y\"))\n                            {\n                                line = line.Remove(0, 1);\n                                line = line.Trim();\n                                tempitem.m_OffsetY = Convert.ToInt16(line);\n                                if (tempitem.m_OffsetY < m_Min.Y)\n                                    m_Min.Y = tempitem.m_OffsetY;\n                                if (tempitem.m_OffsetY > m_Max.Y)\n                                    m_Max.Y = tempitem.m_OffsetY;\n                            }\n                            else if (line.StartsWith(\"Z\"))\n                            {\n                                line = line.Remove(0, 1);\n                                line = line.Trim();\n                                tempitem.m_OffsetZ = Convert.ToInt16(line);\n                                if (tempitem.m_OffsetZ > m_maxHeight)\n                                    m_maxHeight = tempitem.m_OffsetZ;\n                            }\n                        }\n\n                        if (tempitem.m_ItemID != 0xFFFF)\n                            m_SortedTiles[itemcount] = tempitem;\n\n                        int centerx = m_Max.X - (int) (Math.Round((m_Max.X - m_Min.X) / 2.0));\n                        int centery = m_Max.Y - (int) (Math.Round((m_Max.Y - m_Min.Y) / 2.0));\n\n                        m_Min = m_Max = Point.Empty;\n                        int i = 0;\n                        for (; i < m_SortedTiles.Length; i++)\n                        {\n                            m_SortedTiles[i].m_OffsetX -= (short) centerx;\n                            m_SortedTiles[i].m_OffsetY -= (short) centery;\n                            if (m_SortedTiles[i].m_OffsetX < m_Min.X)\n                                m_Min.X = m_SortedTiles[i].m_OffsetX;\n                            if (m_SortedTiles[i].m_OffsetX > m_Max.X)\n                                m_Max.X = m_SortedTiles[i].m_OffsetX;\n\n                            if (m_SortedTiles[i].m_OffsetY < m_Min.Y)\n                                m_Min.Y = m_SortedTiles[i].m_OffsetY;\n                            if (m_SortedTiles[i].m_OffsetY > m_Max.Y)\n                                m_Max.Y = m_SortedTiles[i].m_OffsetY;\n                        }\n                    }\n\n                    break;\n            }\n\n            ConvertList();\n        }\n\n        public MultiComponentList(List<MultiTileEntry> arr)\n        {\n            m_Min = m_Max = Point.Empty;\n            int itemcount = arr.Count;\n            m_SortedTiles = new MultiTileEntry[itemcount];\n            m_Min.X = 10000;\n            m_Min.Y = 10000;\n            int i = 0;\n            foreach (MultiTileEntry entry in arr)\n            {\n                if (entry.m_OffsetX < m_Min.X)\n                    m_Min.X = entry.m_OffsetX;\n\n                if (entry.m_OffsetY < m_Min.Y)\n                    m_Min.Y = entry.m_OffsetY;\n\n                if (entry.m_OffsetX > m_Max.X)\n                    m_Max.X = entry.m_OffsetX;\n\n                if (entry.m_OffsetY > m_Max.Y)\n                    m_Max.Y = entry.m_OffsetY;\n\n                if (entry.m_OffsetZ > m_maxHeight)\n                    m_maxHeight = entry.m_OffsetZ;\n                m_SortedTiles[i] = entry;\n\n                ++i;\n            }\n\n            arr.Clear();\n            int centerx = m_Max.X - (int) (Math.Round((m_Max.X - m_Min.X) / 2.0));\n            int centery = m_Max.Y - (int) (Math.Round((m_Max.Y - m_Min.Y) / 2.0));\n\n            m_Min = m_Max = Point.Empty;\n            for (i = 0; i < m_SortedTiles.Length; ++i)\n            {\n                m_SortedTiles[i].m_OffsetX -= (short) centerx;\n                m_SortedTiles[i].m_OffsetY -= (short) centery;\n                if (m_SortedTiles[i].m_OffsetX < m_Min.X)\n                    m_Min.X = m_SortedTiles[i].m_OffsetX;\n                if (m_SortedTiles[i].m_OffsetX > m_Max.X)\n                    m_Max.X = m_SortedTiles[i].m_OffsetX;\n\n                if (m_SortedTiles[i].m_OffsetY < m_Min.Y)\n                    m_Min.Y = m_SortedTiles[i].m_OffsetY;\n                if (m_SortedTiles[i].m_OffsetY > m_Max.Y)\n                    m_Max.Y = m_SortedTiles[i].m_OffsetY;\n            }\n\n            ConvertList();\n        }\n\n        public MultiComponentList(StreamReader stream, int count)\n        {\n            string line;\n            int itemcount = 0;\n            m_Min = m_Max = Point.Empty;\n            m_SortedTiles = new MultiTileEntry[count];\n            m_Min.X = 10000;\n            m_Min.Y = 10000;\n\n            while ((line = stream.ReadLine()) != null)\n            {\n                string[] split = Regex.Split(line, @\"\\s+\");\n                m_SortedTiles[itemcount].m_ItemID = Convert.ToUInt16(split[0]);\n                m_SortedTiles[itemcount].m_Flags = Convert.ToInt32(split[1]);\n                m_SortedTiles[itemcount].m_OffsetX = Convert.ToInt16(split[2]);\n                m_SortedTiles[itemcount].m_OffsetY = Convert.ToInt16(split[3]);\n                m_SortedTiles[itemcount].m_OffsetZ = Convert.ToInt16(split[4]);\n                m_SortedTiles[itemcount].m_Unk1 = 0;\n\n                MultiTileEntry e = m_SortedTiles[itemcount];\n\n                if (e.m_OffsetX < m_Min.X)\n                    m_Min.X = e.m_OffsetX;\n                if (e.m_OffsetY < m_Min.Y)\n                    m_Min.Y = e.m_OffsetY;\n                if (e.m_OffsetX > m_Max.X)\n                    m_Max.X = e.m_OffsetX;\n                if (e.m_OffsetY > m_Max.Y)\n                    m_Max.Y = e.m_OffsetY;\n                if (e.m_OffsetZ > m_maxHeight)\n                    m_maxHeight = e.m_OffsetZ;\n\n                ++itemcount;\n                if (itemcount == count)\n                    break;\n            }\n\n            int centerx = m_Max.X - (int) (Math.Round((m_Max.X - m_Min.X) / 2.0));\n            int centery = m_Max.Y - (int) (Math.Round((m_Max.Y - m_Min.Y) / 2.0));\n\n            m_Min = m_Max = Point.Empty;\n            int i = 0;\n            for (; i < m_SortedTiles.Length; i++)\n            {\n                m_SortedTiles[i].m_OffsetX -= (short) centerx;\n                m_SortedTiles[i].m_OffsetY -= (short) centery;\n                if (m_SortedTiles[i].m_OffsetX < m_Min.X)\n                    m_Min.X = m_SortedTiles[i].m_OffsetX;\n                if (m_SortedTiles[i].m_OffsetX > m_Max.X)\n                    m_Max.X = m_SortedTiles[i].m_OffsetX;\n\n                if (m_SortedTiles[i].m_OffsetY < m_Min.Y)\n                    m_Min.Y = m_SortedTiles[i].m_OffsetY;\n                if (m_SortedTiles[i].m_OffsetY > m_Max.Y)\n                    m_Max.Y = m_SortedTiles[i].m_OffsetY;\n            }\n\n            ConvertList();\n        }\n\n        private void ConvertList()\n        {\n            m_Center = new Point(-m_Min.X, -m_Min.Y);\n            m_Width = (m_Max.X - m_Min.X) + 1;\n            m_Height = (m_Max.Y - m_Min.Y) + 1;\n\n            MTileList[][] tiles = new MTileList[m_Width][];\n            m_Tiles = new MTile[m_Width][][];\n\n            for (int x = 0; x < m_Width; ++x)\n            {\n                tiles[x] = new MTileList[m_Height];\n                m_Tiles[x] = new MTile[m_Height][];\n\n                for (int y = 0; y < m_Height; ++y)\n                    tiles[x][y] = new MTileList();\n            }\n\n            for (int i = 0; i < m_SortedTiles.Length; ++i)\n            {\n                int xOffset = m_SortedTiles[i].m_OffsetX + m_Center.X;\n                int yOffset = m_SortedTiles[i].m_OffsetY + m_Center.Y;\n\n                tiles[xOffset][yOffset].Add((ushort) (m_SortedTiles[i].m_ItemID), (sbyte) m_SortedTiles[i].m_OffsetZ,\n                    (sbyte) m_SortedTiles[i].m_Flags, m_SortedTiles[i].m_Unk1);\n            }\n\n            m_Surface = 0;\n\n            for (int x = 0; x < m_Width; ++x)\n            {\n                for (int y = 0; y < m_Height; ++y)\n                {\n                    m_Tiles[x][y] = tiles[x][y].ToArray();\n                    for (int i = 0; i < m_Tiles[x][y].Length; ++i)\n                        m_Tiles[x][y][i].Solver = i;\n                    if (m_Tiles[x][y].Length > 1)\n                        Array.Sort(m_Tiles[x][y]);\n                    if (m_Tiles[x][y].Length > 0)\n                        ++m_Surface;\n                }\n            }\n        }\n\n        public MultiComponentList(MTileList[][] newtiles, int count, int width, int height)\n        {\n            m_Min = m_Max = Point.Empty;\n            m_SortedTiles = new MultiTileEntry[count];\n            m_Center = new Point((int) (Math.Round((width / 2.0))) - 1, (int) (Math.Round((height / 2.0))) - 1);\n            if (m_Center.X < 0)\n                m_Center.X = width / 2;\n            if (m_Center.Y < 0)\n                m_Center.Y = height / 2;\n            m_maxHeight = -128;\n\n            int counter = 0;\n            for (int x = 0; x < width; ++x)\n            {\n                for (int y = 0; y < height; ++y)\n                {\n                    MTile[] tiles = newtiles[x][y].ToArray();\n                    for (int i = 0; i < tiles.Length; ++i)\n                    {\n                        m_SortedTiles[counter].m_ItemID = (ushort) (tiles[i].ID);\n                        m_SortedTiles[counter].m_OffsetX = (short) (x - m_Center.X);\n                        m_SortedTiles[counter].m_OffsetY = (short) (y - m_Center.Y);\n                        m_SortedTiles[counter].m_OffsetZ = (short) (tiles[i].Z);\n                        m_SortedTiles[counter].m_Flags = (int) tiles[i].Flag;\n                        m_SortedTiles[counter].m_Unk1 = 0;\n\n                        if (m_SortedTiles[counter].m_OffsetX < m_Min.X)\n                            m_Min.X = m_SortedTiles[counter].m_OffsetX;\n                        if (m_SortedTiles[counter].m_OffsetX > m_Max.X)\n                            m_Max.X = m_SortedTiles[counter].m_OffsetX;\n                        if (m_SortedTiles[counter].m_OffsetY < m_Min.Y)\n                            m_Min.Y = m_SortedTiles[counter].m_OffsetY;\n                        if (m_SortedTiles[counter].m_OffsetY > m_Max.Y)\n                            m_Max.Y = m_SortedTiles[counter].m_OffsetY;\n                        if (m_SortedTiles[counter].m_OffsetZ > m_maxHeight)\n                            m_maxHeight = m_SortedTiles[counter].m_OffsetZ;\n                        ++counter;\n                    }\n                }\n            }\n\n            ConvertList();\n        }\n\n        private MultiComponentList()\n        {\n            m_Tiles = new MTile[0][][];\n        }\n\n        public void ExportToTextFile(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.GetEncoding(1252)))\n            {\n                for (int i = 0; i < m_SortedTiles.Length; ++i)\n                {\n                    Tex.WriteLine(\n                        $\"0x{m_SortedTiles[i].m_ItemID:X} {m_SortedTiles[i].m_OffsetX} {m_SortedTiles[i].m_OffsetY} {m_SortedTiles[i].m_OffsetZ} {m_SortedTiles[i].m_Flags}\");\n                }\n            }\n        }\n\n        public void ExportToWscFile(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.GetEncoding(1252)))\n            {\n                for (int i = 0; i < m_SortedTiles.Length; ++i)\n                {\n                    Tex.WriteLine($\"SECTION WORLDITEM {i}\");\n                    Tex.WriteLine(\"{\");\n                    Tex.WriteLine($\"\\tID\\t{m_SortedTiles[i].m_ItemID}\");\n                    Tex.WriteLine($\"\\tX\\t{m_SortedTiles[i].m_OffsetX}\");\n                    Tex.WriteLine($\"\\tY\\t{m_SortedTiles[i].m_OffsetY}\");\n                    Tex.WriteLine($\"\\tZ\\t{m_SortedTiles[i].m_OffsetZ}\");\n                    Tex.WriteLine(\"\\tColor\\t0\");\n                    Tex.WriteLine(\"}\");\n                }\n            }\n        }\n\n        public void ExportToUOAFile(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.GetEncoding(1252)))\n            {\n                Tex.WriteLine(\"6 version\");\n                Tex.WriteLine(\"1 template id\");\n                Tex.WriteLine(\"-1 item version\");\n                Tex.WriteLine($\"{m_SortedTiles.Length} num components\");\n                for (int i = 0; i < m_SortedTiles.Length; ++i)\n                {\n                    Tex.WriteLine(\n                        $\"{m_SortedTiles[i].m_ItemID} {m_SortedTiles[i].m_OffsetX} {m_SortedTiles[i].m_OffsetY} {m_SortedTiles[i].m_OffsetZ} {m_SortedTiles[i].m_Flags}\");\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/NativeMethods.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Runtime.InteropServices;\nusing Microsoft.Win32.SafeHandles;\n\nnamespace Ultima\n{\n    public static class NativeMethods\n    {\n        [DllImport(\"User32\")]\n        public static extern int IsWindow(ClientWindowHandle window);\n\n        [DllImport(\"User32\")]\n        public static extern int GetWindowThreadProcessId(ClientWindowHandle window, ref ClientProcessHandle processID);\n\n        [DllImport(\"Kernel32\")]\n        public unsafe static extern int _lread(SafeFileHandle hFile, void* lpBuffer, int wBytes);\n\n        [DllImport(\"Kernel32\")]\n        public static extern ClientProcessHandle OpenProcess(int desiredAccess, int inheritClientHandle,\n            ClientProcessHandle processID);\n\n        [DllImport(\"Kernel32\")]\n        public static extern int CloseHandle(ClientProcessHandle handle);\n\n        [DllImport(\"Kernel32\")]\n        public static unsafe extern int ReadProcessMemory(ClientProcessHandle process, int baseAddress, void* buffer,\n            int size, ref int op);\n\n        [DllImport(\"Kernel32\")]\n        public static unsafe extern int WriteProcessMemory(ClientProcessHandle process, int baseAddress, void* buffer,\n            int size, int nullMe);\n\n        [DllImport(\"User32\")]\n        public static extern int SetForegroundWindow(ClientWindowHandle hWnd);\n\n        [DllImport(\"User32\")]\n        public static extern int SendMessage(ClientWindowHandle hWnd, int wMsg, int wParam, int lParam);\n\n        [DllImport(\"User32\")]\n        public static extern bool PostMessage(ClientWindowHandle hWnd, int wMsg, int wParam, int lParam);\n\n        [DllImport(\"User32\")]\n        public static extern int OemKeyScan(int wOemChar);\n\n        [DllImport(\"user32\")]\n        public static extern ClientWindowHandle FindWindowA(string lpClassName, string lpWindowName);\n\n        /// <summary>\n        /// Swaps from Big to LittleEndian and vise versa\n        /// </summary>\n        /// <param name=\"x\"></param>\n        /// <returns></returns>\n        public static short SwapEndian(short x)\n        {\n            ushort y = (ushort) x;\n            return (short) ((y >> 8) | (y << 8));\n        }\n\n        private static byte[] m_StringBuffer;\n\n        public unsafe static string ReadNameString(byte* buffer, int len)\n        {\n            if ((m_StringBuffer == null) || (m_StringBuffer.Length < len))\n                m_StringBuffer = new byte[20];\n            int count;\n            for (count = 0; count < len && *buffer != 0; ++count)\n                m_StringBuffer[count] = *buffer++;\n\n            return System.Text.Encoding.Default.GetString(m_StringBuffer, 0, count);\n        }\n\n        public unsafe static string ReadNameString(byte[] buffer, int len)\n        {\n            int count;\n            for (count = 0; count < 20 && buffer[count] != 0; ++count) ;\n            return System.Text.Encoding.Default.GetString(buffer, 0, count);\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/ProcessStream.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.IO;\n\nnamespace Ultima\n{\n    public unsafe abstract class ProcessStream : Stream\n    {\n        private const int ProcessAllAccess = 0x1F0FFF;\n\n        protected bool m_Open;\n        protected ClientProcessHandle m_Process;\n\n        protected int m_Position;\n\n        public abstract ClientProcessHandle ProcessID { get; }\n\n        public ProcessStream()\n        {\n        }\n\n        public virtual bool BeginAccess()\n        {\n            if (m_Open)\n                return false;\n\n            m_Process = NativeMethods.OpenProcess(ProcessAllAccess, 0, ProcessID);\n            m_Open = true;\n\n            return true;\n        }\n\n        public virtual void EndAccess()\n        {\n            if (!m_Open)\n                return;\n\n            m_Process.Close();\n            m_Open = false;\n        }\n\n        public override void Flush()\n        {\n        }\n\n        public override int Read(byte[] buffer, int offset, int count)\n        {\n            bool end = !BeginAccess();\n\n            int res = 0;\n\n            fixed (byte* p = buffer)\n                NativeMethods.ReadProcessMemory(m_Process, m_Position, p + offset, count, ref res);\n\n            m_Position += count;\n\n            if (end)\n                EndAccess();\n\n            return res;\n        }\n\n        public override void Write(byte[] buffer, int offset, int count)\n        {\n            bool end = !BeginAccess();\n\n            fixed (byte* p = buffer)\n                NativeMethods.WriteProcessMemory(m_Process, m_Position, p + offset, count, 0);\n\n            m_Position += count;\n\n            if (end)\n                EndAccess();\n        }\n\n        public override bool CanRead\n        {\n            get { return true; }\n        }\n\n        public override bool CanWrite\n        {\n            get { return true; }\n        }\n\n        public override bool CanSeek\n        {\n            get { return true; }\n        }\n\n        public override long Length\n        {\n            get { throw new NotSupportedException(); }\n        }\n\n        public override long Position\n        {\n            get { return m_Position; }\n            set { m_Position = (int) value; }\n        }\n\n        public override void SetLength(long value)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override long Seek(long offset, SeekOrigin origin)\n        {\n            switch (origin)\n            {\n                case SeekOrigin.Begin:\n                    m_Position = (int) offset;\n                    break;\n                case SeekOrigin.Current:\n                    m_Position += (int) offset;\n                    break;\n                case SeekOrigin.End: throw new NotSupportedException();\n            }\n\n            return m_Position;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/RadarCol.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\nnamespace Ultima\n{\n    public sealed class RadarCol\n    {\n        static RadarCol()\n        {\n            Initialize();\n        }\n\n        private static short[] m_Colors;\n\n        public static short[] Colors\n        {\n            get { return m_Colors; }\n        }\n\n        public static short GetItemColor(int index)\n        {\n            if (index + 0x4000 < m_Colors.Length)\n                return m_Colors[index + 0x4000];\n            return 0;\n        }\n\n        public static short GetLandColor(int index)\n        {\n            if (index < m_Colors.Length)\n                return m_Colors[index];\n            return 0;\n        }\n\n        public static void SetItemColor(int index, short value)\n        {\n            m_Colors[index + 0x4000] = value;\n        }\n\n        public static void SetLandColor(int index, short value)\n        {\n            m_Colors[index] = value;\n        }\n\n        public static void Initialize()\n        {\n            string path = Files.GetFilePath(\"radarcol.mul\");\n            if (path != null)\n            {\n                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    m_Colors = new short[fs.Length / 2];\n                    GCHandle gc = GCHandle.Alloc(m_Colors, GCHandleType.Pinned);\n                    byte[] buffer = new byte[(int) fs.Length];\n                    fs.Read(buffer, 0, (int) fs.Length);\n                    Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(), (int) fs.Length);\n                    gc.Free();\n                }\n            }\n            else\n                m_Colors = new short[0x8000];\n        }\n\n        public static void Save(string FileName)\n        {\n            using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    for (int i = 0; i < m_Colors.Length; ++i)\n                    {\n                        bin.Write(m_Colors[i]);\n                    }\n                }\n            }\n        }\n\n        public static void ExportToCSV(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.GetEncoding(1252)))\n            {\n                Tex.WriteLine(\"ID;Color\");\n\n                for (int i = 0; i < m_Colors.Length; ++i)\n                {\n                    Tex.WriteLine($\"0x{i:X4};{m_Colors[i]}\");\n                }\n            }\n        }\n\n        public static void ImportFromCSV(string FileName)\n        {\n            if (!File.Exists(FileName))\n                return;\n            using (StreamReader sr = new StreamReader(FileName))\n            {\n                string line;\n                int count = 0;\n                while ((line = sr.ReadLine()) != null)\n                {\n                    if ((line = line.Trim()).Length == 0 || line.StartsWith(\"#\"))\n                        continue;\n                    if (line.StartsWith(\"ID;\"))\n                        continue;\n                    ++count;\n                }\n\n                m_Colors = new short[count];\n            }\n\n            using (StreamReader sr = new StreamReader(FileName))\n            {\n                string line;\n                while ((line = sr.ReadLine()) != null)\n                {\n                    if ((line = line.Trim()).Length == 0 || line.StartsWith(\"#\"))\n                        continue;\n                    if (line.StartsWith(\"ID;\"))\n                        continue;\n                    try\n                    {\n                        string[] split = line.Split(';');\n                        if (split.Length < 2)\n                            continue;\n\n                        int id = ConvertStringToInt(split[0]);\n                        int color = ConvertStringToInt(split[1]);\n                        m_Colors[id] = (short) color;\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n        }\n\n        private static int ConvertStringToInt(string text)\n        {\n            int result;\n            if (text.Contains(\"0x\"))\n            {\n                string convert = text.Replace(\"0x\", \"\");\n                int.TryParse(convert, System.Globalization.NumberStyles.HexNumber, null, out result);\n            }\n            else\n                int.TryParse(text, System.Globalization.NumberStyles.Integer, null, out result);\n\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/SkillGroups.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text;\n\nnamespace Ultima\n{\n    public sealed class SkillGroup\n    {\n        public string Name { get; set; }\n\n        public SkillGroup(string name)\n        {\n            Name = name;\n        }\n    }\n\n    public sealed class SkillGroups\n    {\n        public static List<SkillGroup> List { get; private set; }\n        public static List<int> SkillList { get; private set; }\n        private static bool unicode = false;\n\n        static SkillGroups()\n        {\n            Initialize();\n        }\n\n        public static void Initialize()\n        {\n            string path = Files.GetFilePath(\"skillgrp.mul\");\n\n            List = new List<SkillGroup>();\n            SkillList = new List<int>();\n\n            if (path != null)\n            {\n                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    using (BinaryReader bin = new BinaryReader(fs))\n                    {\n                        int start = 4;\n                        int strlen = 17;\n                        int count = bin.ReadInt32();\n                        if (count == -1)\n                        {\n                            unicode = true;\n                            count = bin.ReadInt32();\n                            start *= 2;\n                            strlen *= 2;\n                        }\n\n                        List.Add(new SkillGroup(\"Misc\"));\n                        for (int i = 0; i < count - 1; ++i)\n                        {\n                            int strbuild;\n                            fs.Seek((long) (start + (i * strlen)), SeekOrigin.Begin);\n                            StringBuilder builder2 = new StringBuilder(17);\n                            if (unicode)\n                            {\n                                while ((strbuild = bin.ReadInt16()) != 0)\n                                    builder2.Append((char) strbuild);\n                            }\n                            else\n                            {\n                                while ((strbuild = bin.ReadByte()) != 0)\n                                    builder2.Append((char) strbuild);\n                            }\n\n                            List.Add(new SkillGroup(builder2.ToString()));\n                        }\n\n                        fs.Seek((long) (start + ((count - 1) * strlen)), SeekOrigin.Begin);\n                        try\n                        {\n                            while (bin.BaseStream.Length != bin.BaseStream.Position)\n                                SkillList.Add(bin.ReadInt32());\n                        }\n                        catch // just for safety\n                        {\n                        }\n                    }\n                }\n            }\n        }\n\n        public static void Save(string path)\n        {\n            string mul = Path.Combine(path, \"skillgrp.mul\");\n            using (FileStream fs = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    if (unicode)\n                        bin.Write((int) -1);\n                    bin.Write((int) List.Count);\n\n                    foreach (SkillGroup group in List)\n                    {\n                        if (group.Name == \"Misc\")\n                            continue;\n                        byte[] name;\n                        if (unicode)\n                            name = new byte[34];\n                        else\n                            name = new byte[17];\n                        if (group.Name != null)\n                        {\n                            if (unicode)\n                            {\n                                byte[] bb = Encoding.Unicode.GetBytes(group.Name);\n                                if (bb.Length > 34)\n                                    Array.Resize(ref bb, 34);\n                                bb.CopyTo(name, 0);\n                            }\n                            else\n                            {\n                                byte[] bb = Encoding.Default.GetBytes(group.Name);\n                                if (bb.Length > 17)\n                                    Array.Resize(ref bb, 17);\n                                bb.CopyTo(name, 0);\n                            }\n                        }\n\n                        bin.Write(name);\n                    }\n\n                    foreach (int group in SkillList)\n                        bin.Write(group);\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Skills.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text;\nusing Assistant;\n\nnamespace Ultima\n{\n    public sealed class Skills\n    {\n        private static FileIndex _fileIndex = new FileIndex(\"skills.idx\", \"skills.mul\", 16);\n        public static Dictionary<string, SkillInfo> SkillsByName { get; private set; }\n        public static Dictionary<int, SkillInfo> SkillsByIndex { get; private set; }\n\n        public static int StealthIndex { get; private set; }\n        public static int MageryIndex { get; private set; }\n\n        public static void Initialize()\n        {\n            Load();\n        }\n        \n        public Skills()\n        {\n        }\n\n        /// <summary>\n        /// ReReads skills.mul\n        /// </summary>\n        private static void Load()\n        {\n            _fileIndex = new FileIndex(\"skills.idx\", \"skills.mul\", 16);\n\n            SkillsByIndex = new Dictionary<int, SkillInfo>();\n            SkillsByName = new Dictionary<string, SkillInfo>(StringComparer.OrdinalIgnoreCase);\n\n            for (int i = 0; i < _fileIndex.Index.Length; ++i)\n            {\n                SkillInfo info = GetSkill(i);\n\n                if (info == null)\n                    break;\n\n                SkillsByIndex.Add(i, info);\n                SkillsByName.Add(info.Name.Replace(\" \", string.Empty), info);\n                \n                switch (info.Name)\n                {\n                    case \"Magery\":\n                        MageryIndex = i;\n                        break;\n                    case \"Stealth\":\n                        StealthIndex = i;\n                        break;\n                    case \"Item Identification\":\n                        SkillsByName.Add(\"itemid\", info);\n                        break;\n                    case \"Evaluating Intelligence\":\n                        SkillsByName.Add(\"evalint\", info);\n                        break;\n                    case \"Forensic Evaluation\":\n                        SkillsByName.Add(\"forensiceval\", info);\n                        SkillsByName.Add(\"forensic\", info);\n                        break;\n                    case \"Provocation\":\n                        SkillsByName.Add(\"provo\", info);\n                        break;\n                    case \"Spirit Speak\":\n                        SkillsByName.Add(\"spirit\", info);\n                        break;\n                    case \"Taste Identification\":\n                        SkillsByName.Add(\"tasteid\", info);\n                        break;\n                }\n            }\n        }\n\n        public static List<int> GetUsableSkillIndexes()\n        {\n            if (SkillsByIndex == null)\n            {\n                Load();\n            }\n\n            List<int> indexes = new List<int>();\n\n            foreach (KeyValuePair<int, SkillInfo> keyValuePair in SkillsByIndex)\n            {\n                if (keyValuePair.Value.IsAction)\n                {\n                    indexes.Add(keyValuePair.Key);\n                }\n            }\n\n            return indexes;\n        }\n\n        public static List<string> GetUsableSkillNames()\n        {\n            if (SkillsByName == null)\n            {\n                Load();\n            }\n\n            List<string> names = new List<string>();\n\n            foreach (KeyValuePair<string, SkillInfo> keyValuePair in SkillsByName)\n            {\n                if (keyValuePair.Value.IsAction)\n                {\n                    names.Add(keyValuePair.Key);\n                }\n            }\n\n            return names;\n        }\n\n        public static string GetSkillDisplayName(int index)\n        {\n            if (SkillsByIndex.TryGetValue(index, out SkillInfo skill))\n            {\n                return skill.DisplayName;\n            }\n\n            return string.Empty;\n        }\n\n        public static int TotalSkills()\n        {\n            return SkillsByIndex.Count;\n        }\n\n        /// <summary>\n        /// Returns <see cref=\"SkillInfo\"/> of index\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        private static SkillInfo GetSkill(int index)\n        {\n            Stream stream = _fileIndex.Seek(index, out int length, out int extra, out bool patched);\n            \n            if (stream != null)\n            {\n                if (length == 0)\n                    return null;\n\n                using (BinaryReader bin = new BinaryReader(stream))\n                {\n                    bool action = bin.ReadBoolean();\n                    string name = ReadNameString(bin, length - 1);\n                    string displayName = Language.GetSkillCliloc(index);\n                    return new SkillInfo(index, name, displayName, action, extra);\n                }\n            }\n\n            return null;\n        }\n\n        private static readonly byte[] StringBuffer = new byte[1024];\n\n        private static string ReadNameString(BinaryReader bin, int length)\n        {\n            bin.Read(StringBuffer, 0, length);\n            int count;\n            for (count = 0; count < length && StringBuffer[count] != 0; ++count) ;\n\n            return Encoding.Default.GetString(StringBuffer, 0, count);\n        }\n\n        public static void Save(string path)\n        {\n            string idx = Path.Combine(path, \"skills.idx\");\n            string mul = Path.Combine(path, \"skills.mul\");\n\n            using (FileStream fsSkillsIndex = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write), fsSkillsMul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter binSkillsIndex = new BinaryWriter(fsSkillsIndex), binSkillsMul = new BinaryWriter(fsSkillsMul))\n                {\n                    for (int i = 0; i < _fileIndex.Index.Length; ++i)\n                    {\n                        if (SkillsByIndex.TryGetValue(i, out SkillInfo skill))\n                        {\n                            binSkillsIndex.Write((int)fsSkillsMul.Position); //lookup\n                            int length = (int)fsSkillsMul.Position;\n                            binSkillsMul.Write(skill.IsAction);\n\n                            byte[] namebytes = Encoding.Default.GetBytes(skill.Name);\n                            binSkillsMul.Write(namebytes);\n                            binSkillsMul.Write((byte)0); //nullterminated\n\n                            length = (int)fsSkillsMul.Position - length;\n                            binSkillsIndex.Write(length);\n                            binSkillsIndex.Write(skill.Extra);\n                        }\n                        else\n                        {\n                            binSkillsIndex.Write((int)-1); // lookup\n                            binSkillsIndex.Write((int)0); // length\n                            binSkillsIndex.Write((int)0); // extra\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public sealed class SkillInfo\n    {\n        public int Index { get; set; }\n        public bool IsAction { get; set; }\n\n        public string Name { get; set; }\n        public string DisplayName { get; set; }\n\n        public int Extra { get; private set; }\n\n\n        public SkillInfo(int nr, string name, string displayName, bool action, int extra)\n        {\n            Index = nr;\n            Name = name;\n            DisplayName = displayName;\n            IsAction = action;\n            Extra = extra;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Sound.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Ultima\n{\n    public sealed class UOSound\n    {\n        public string Name;\n        public int ID;\n        public byte[] buffer;\n\n        public UOSound(string name, int id, byte[] buff)\n        {\n            Name = name;\n            ID = id;\n            buffer = buff;\n        }\n    };\n\n    public static class Sounds\n    {\n        private static Dictionary<int, int> m_Translations;\n        private static FileIndex m_FileIndex;\n        private static UOSound[] m_Cache;\n        private static bool[] m_Removed;\n\n        static Sounds()\n        {\n            Initialize();\n        }\n\n        /// <summary>\n        /// Reads Sounds and def\n        /// </summary>\n        public static void Initialize()\n        {\n            m_Cache = new UOSound[0xFFF];\n            m_Removed = new bool[0xFFF];\n            m_FileIndex = new FileIndex(\"soundidx.mul\", \"sound.mul\", \"soundLegacyMUL.uop\", 0xFFF, 8, \".dat\", -1, false);\n            Regex reg = new Regex(@\"(\\d{1,3}) \\x7B(\\d{1,3})\\x7D (\\d{1,3})\", RegexOptions.Compiled);\n\n            m_Translations = new Dictionary<int, int>();\n\n            string line;\n            string path = Files.GetFilePath(\"Sound.def\");\n            if (path == null)\n                return;\n            using (StreamReader reader = new StreamReader(path))\n            {\n                while ((line = reader.ReadLine()) != null)\n                {\n                    if (((line = line.Trim()).Length != 0) && !line.StartsWith(\"#\"))\n                    {\n                        Match match = reg.Match(line);\n\n                        if (match.Success)\n                            m_Translations.Add(int.Parse(match.Groups[1].Value), int.Parse(match.Groups[2].Value));\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Returns <see cref=\"UOSound\"/> of ID\n        /// </summary>\n        /// <param name=\"soundID\"></param>\n        /// <returns></returns>\n        public static UOSound GetSound(int soundID)\n        {\n            bool translated;\n            return GetSound(soundID, out translated);\n        }\n\n        /// <summary>\n        /// Returns <see cref=\"UOSound\"/> of ID with bool translated in .def\n        /// </summary>\n        /// <param name=\"soundID\"></param>\n        /// <param name=\"translated\"></param>\n        /// <returns></returns>\n        public static UOSound GetSound(int soundID, out bool translated)\n        {\n            translated = false;\n            if (soundID < 0)\n                return null;\n            if (m_Cache[soundID] != null)\n                return m_Cache[soundID];\n\n            int length, extra;\n            bool patched;\n            Stream stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);\n\n            if ((m_FileIndex.Index[soundID].lookup < 0) || (length <= 0))\n            {\n                if (!m_Translations.TryGetValue(soundID, out soundID))\n                    return null;\n\n                translated = true;\n                stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);\n            }\n\n            if (stream == null)\n                return null;\n\n            length -= 32;\n            int[] waveHeader = WaveHeader(length);\n\n            byte[] stringBuffer = new byte[32];\n            byte[] buffer = new byte[length];\n\n            stream.Read(stringBuffer, 0, 32);\n            stream.Read(buffer, 0, length);\n            stream.Close();\n\n            byte[] resultBuffer = new byte[buffer.Length + (waveHeader.Length << 2)];\n\n            Buffer.BlockCopy(waveHeader, 0, resultBuffer, 0, (waveHeader.Length << 2));\n            Buffer.BlockCopy(buffer, 0, resultBuffer, (waveHeader.Length << 2), buffer.Length);\n\n            string\n                str = Encoding.ASCII\n                    .GetString(stringBuffer); // seems that the null terminator's not being properly recognized :/\n            if (str.IndexOf('\\0') > 0)\n                str = str.Substring(0, str.IndexOf('\\0'));\n            UOSound sound = new UOSound(str, soundID, resultBuffer);\n\n            if (Files.CacheData)\n            {\n                if (!translated) // no .def definition\n                    m_Cache[soundID] = sound;\n            }\n\n            return sound;\n        }\n\n        private static int[] WaveHeader(int length)\n        {\n            /* ====================\n             * = WAVE File layout =\n             * ====================\n             * char[4] = 'RIFF' \\\n             * int - chunk size |- Riff Header\n             * char[4] = 'WAVE' /\n             * char[4] = 'fmt ' \\\n             * int - chunk size |\n             * short - format\t|\n             * short - channels\t|\n             * int - samples p/s|- Format header\n             * int - avg bytes\t|\n             * short - align\t|\n             * short - bits p/s /\n             * char[4] - data\t\\\n             * int - chunk size | - Data header\n             * short[..] - data /\n             * ====================\n             * */\n            return new int[]\n            {\n                0x46464952, (length + 36), 0x45564157, 0x20746D66, 0x10, 0x010001, 0x5622, 0xAC44, 0x100002, 0x61746164,\n                length\n            };\n        }\n\n        /// <summary>\n        /// Returns Soundname and tests if valid\n        /// </summary>\n        /// <param name=\"soundID\"></param>\n        /// <returns></returns>\n        public static bool IsValidSound(int soundID, out string name)\n        {\n            name = \"\";\n            if (soundID < 0)\n                return false;\n            int length, extra;\n            bool patched;\n            Stream stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);\n\n            if ((m_FileIndex.Index[soundID].lookup < 0) || (length <= 0))\n            {\n                if (!m_Translations.TryGetValue(soundID, out soundID))\n                    return false;\n\n                stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);\n            }\n\n            if (stream == null)\n                return false;\n\n            byte[] stringBuffer = new byte[32];\n            stream.Read(stringBuffer, 0, 32);\n            stream.Close();\n            name = Encoding.ASCII\n                .GetString(stringBuffer); // seems that the null terminator's not being properly recognized :/\n            if (name.IndexOf('\\0') > 0)\n                name = name.Substring(0, name.IndexOf('\\0'));\n            return true;\n        }\n\n        /// <summary>\n        /// Returns length of SoundID\n        /// </summary>\n        /// <param name=\"soundID\"></param>\n        /// <returns></returns>\n        public static double GetSoundLength(int soundID)\n        {\n            if (soundID < 0)\n                return 0;\n            double len;\n            if (m_Cache[soundID] != null)\n            {\n                len = (double) m_Cache[soundID].buffer.Length;\n                len -= 44; //wavheaderlength\n            }\n            else\n            {\n                int length, extra;\n                bool patched;\n                Stream stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);\n                if ((m_FileIndex.Index[soundID].lookup < 0) || (length <= 0))\n                {\n                    if (!m_Translations.TryGetValue(soundID, out soundID))\n                        return 0;\n\n                    stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);\n                }\n\n                if (stream == null)\n                    return 0;\n                stream.Close();\n                length -= 32; //mulheaderlength\n                len = (double) length;\n            }\n\n            len /= 0x5622; // Sample Rate\n            len /= 2;\n            return len;\n        }\n\n        public static void Add(int id, string name, string file)\n        {\n            using (FileStream wav = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))\n            {\n                byte[] resultBuffer = new byte[wav.Length];\n                wav.Seek(0, SeekOrigin.Begin);\n                wav.Read(resultBuffer, 0, (int) wav.Length);\n\n                m_Cache[id] = new UOSound(name, id, resultBuffer);\n                m_Removed[id] = false;\n            }\n        }\n\n        public static void Remove(int id)\n        {\n            m_Removed[id] = true;\n            m_Cache[id] = null;\n        }\n\n        public static void Save(string path)\n        {\n            string idx = Path.Combine(path, \"soundidx.mul\");\n            string mul = Path.Combine(path, \"sound.mul\");\n            int Headerlength = 44;\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter binidx = new BinaryWriter(fsidx),\n                    binmul = new BinaryWriter(fsmul))\n                {\n                    for (int i = 0; i < m_Cache.Length; ++i)\n                    {\n                        UOSound sound = m_Cache[i];\n                        if ((sound == null) && (!m_Removed[i]))\n                        {\n                            bool trans;\n                            sound = GetSound(i, out trans);\n                            if (!trans)\n                                m_Cache[i] = sound;\n                            else\n                                sound = null;\n                        }\n\n                        if ((sound == null) || (m_Removed[i]))\n                        {\n                            binidx.Write((int) -1); // lookup\n                            binidx.Write((int) -1); // length\n                            binidx.Write((int) -1); // extra\n                        }\n                        else\n                        {\n                            binidx.Write((int) fsmul.Position); //lookup\n                            int length = (int) fsmul.Position;\n\n                            byte[] b = new byte[32];\n                            if (sound.Name != null)\n                            {\n                                byte[] bb = Encoding.Default.GetBytes(sound.Name);\n                                if (bb.Length > 32)\n                                    Array.Resize(ref bb, 32);\n                                bb.CopyTo(b, 0);\n                            }\n\n                            binmul.Write(b);\n                            using (MemoryStream m = new MemoryStream(sound.buffer))\n                            {\n                                m.Seek(Headerlength, SeekOrigin.Begin);\n                                byte[] resultBuffer = new byte[m.Length - Headerlength];\n                                m.Read(resultBuffer, 0, (int) m.Length - Headerlength);\n                                binmul.Write(resultBuffer);\n                            }\n\n                            length = (int) fsmul.Position - length;\n                            binidx.Write(length);\n                            binidx.Write(i + 1);\n                        }\n                    }\n                }\n            }\n        }\n\n        public static void SaveSoundListToCSV(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.GetEncoding(1252)))\n            {\n                Tex.WriteLine(\"ID;Name;Length\");\n                string name = \"\";\n                for (int i = 1; i <= 0xFFF; ++i)\n                {\n                    if (IsValidSound(i - 1, out name))\n                    {\n                        Tex.Write($\"0x{i:X3}\");\n                        Tex.Write($\";{name}\");\n                        Tex.WriteLine($\";{GetSoundLength(i - 1):f}\");\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/SpeechList.cs",
    "content": "﻿#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Ultima\n{\n    public sealed class SpeechList\n    {\n        public static List<SpeechEntry> Entries { get; set; }\n\n        private static byte[] m_Buffer = new byte[128];\n\n        static SpeechList()\n        {\n            Initialize();\n        }\n\n        /// <summary>\n        /// Loads speech.mul in <see cref=\"SpeechList.Entries\"/>\n        /// </summary>\n        public static void Initialize()\n        {\n            string path = Files.GetFilePath(\"speech.mul\");\n            if (path == null)\n            {\n                Entries = new List<SpeechEntry>(0);\n                return;\n            }\n\n            Entries = new List<SpeechEntry>();\n            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n            {\n                byte[] buffer = new byte[fs.Length];\n                unsafe\n                {\n                    int order = 0;\n                    fs.Read(buffer, 0, buffer.Length);\n                    fixed (byte* data = buffer)\n                    {\n                        byte* bindat = (byte*) data;\n                        byte* bindatend = bindat + buffer.Length;\n\n                        while (bindat != bindatend)\n                        {\n                            short id = (short) ((*bindat++ >> 8) | (*bindat++)); //Swapped Endian\n                            short length = (short) ((*bindat++ >> 8) | (*bindat++));\n                            if (length > 128)\n                                length = 128;\n                            for (int i = 0; i < length; ++i)\n                                m_Buffer[i] = *bindat++;\n                            string keyword = Encoding.UTF8.GetString(m_Buffer, 0, length);\n                            Entries.Add(new SpeechEntry(id, keyword, order));\n                            ++order;\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Saves speech.mul to <see cref=\"FileName\"/>\n        /// </summary>\n        /// <param name=\"FileName\"></param>\n        public static void SaveSpeechList(string FileName)\n        {\n            Entries.Sort(new OrderComparer());\n            using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    foreach (SpeechEntry entry in Entries)\n                    {\n                        bin.Write(NativeMethods.SwapEndian(entry.ID));\n                        byte[] utf8String = Encoding.UTF8.GetBytes(entry.KeyWord);\n                        short length = (short) utf8String.Length;\n                        bin.Write(NativeMethods.SwapEndian(length));\n                        bin.Write(utf8String);\n                    }\n                }\n            }\n        }\n\n        public static void ExportToCSV(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.Unicode))\n            {\n                Tex.WriteLine(\"Order;ID;KeyWord\");\n                foreach (SpeechEntry entry in Entries)\n                {\n                    Tex.WriteLine($\"{entry.Order};{entry.ID};{entry.KeyWord}\");\n                }\n            }\n        }\n\n        public static void ImportFromCSV(string FileName)\n        {\n            Entries = new List<SpeechEntry>(0);\n            if (!File.Exists(FileName))\n                return;\n            using (StreamReader sr = new StreamReader(FileName))\n            {\n                string line;\n                while ((line = sr.ReadLine()) != null)\n                {\n                    if ((line = line.Trim()).Length == 0 || line.StartsWith(\"#\"))\n                        continue;\n                    if ((line.Contains(\"Order\")) && (line.Contains(\"KeyWord\")))\n                        continue;\n                    try\n                    {\n                        string[] split = line.Split(';');\n                        if (split.Length < 3)\n                            continue;\n\n                        int order = ConvertStringToInt(split[0]);\n                        int id = ConvertStringToInt(split[1]);\n                        string word = split[2];\n                        word = word.Replace(\"\\\"\", \"\");\n                        Entries.Add(new SpeechEntry((short) id, word, order));\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n        }\n\n        public static int ConvertStringToInt(string text)\n        {\n            int result;\n            if (text.Contains(\"0x\"))\n            {\n                string convert = text.Replace(\"0x\", \"\");\n                int.TryParse(convert, System.Globalization.NumberStyles.HexNumber, null, out result);\n            }\n            else\n                int.TryParse(text, System.Globalization.NumberStyles.Integer, null, out result);\n\n            return result;\n        }\n\n        #region SortComparer\n\n        public class IDComparer : IComparer<SpeechEntry>\n        {\n            private bool m_desc;\n\n            public IDComparer(bool desc)\n            {\n                m_desc = desc;\n            }\n\n            public int Compare(SpeechEntry objA, SpeechEntry objB)\n            {\n                if (objA.ID == objB.ID)\n                    return 0;\n                else if (m_desc)\n                    return (objA.ID < objB.ID) ? 1 : -1;\n                else\n                    return (objA.ID < objB.ID) ? -1 : 1;\n            }\n        }\n\n        public class KeyWordComparer : IComparer<SpeechEntry>\n        {\n            private bool m_desc;\n\n            public KeyWordComparer(bool desc)\n            {\n                m_desc = desc;\n            }\n\n            public int Compare(SpeechEntry objA, SpeechEntry objB)\n            {\n                if (m_desc)\n                    return String.Compare(objB.KeyWord, objA.KeyWord);\n                else\n                    return String.Compare(objA.KeyWord, objB.KeyWord);\n            }\n        }\n\n        public class OrderComparer : IComparer<SpeechEntry>\n        {\n            public int Compare(SpeechEntry objA, SpeechEntry objB)\n            {\n                if (objA.Order == objB.Order)\n                    return 0;\n                else\n                    return (objA.Order < objB.Order) ? -1 : 1;\n            }\n        }\n\n        #endregion\n    }\n\n    public sealed class SpeechEntry\n    {\n        public short ID { get; set; }\n        public string KeyWord { get; set; }\n\n        [Browsable(false)] public int Order { get; private set; }\n\n        public SpeechEntry(short id, string keyword, int order)\n        {\n            ID = id;\n            KeyWord = keyword;\n            Order = order;\n        }\n    }\n\n    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public unsafe struct SpeechMul\n    {\n        public short id;\n        public short length;\n        public byte[] keyword;\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/StackDataReader.cs",
    "content": "#region license\n\n// Copyright (c) 2024, andreakarasho\n// All rights reserved.\n// \n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n// 3. All advertising materials mentioning features or use of this software\n//    must display the following acknowledgement:\n//    This product includes software developed by andreakarasho - https://github.com/andreakarasho\n// 4. Neither the name of the copyright holder nor the\n//    names of its contributors may be used to endorse or promote products\n//    derived from this software without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY\n// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY\n// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#endregion\nusing System;\nusing System.Buffers.Binary;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Ultima\n{\n    unsafe ref struct StackDataReader\n    {\n        private readonly ReadOnlySpan<byte> _data;\n        public StackDataReader(ReadOnlySpan<byte> data)\n        {\n            _data = data;\n            Length = data.Length;\n            Position = 0;\n        }\n\n        public int Position { get; private set; }\n        public long Length { get; }\n        public int Remaining => (int)(Length - Position);\n\n        public byte this[int index] => _data[0];\n\n        public ReadOnlySpan<byte> Buffer => _data;\n\n\n        public ref byte GetPinnableReference()\n        {\n            return ref MemoryMarshal.GetReference(_data);\n        }\n\n        public void Release()\n        {\n            // do nothing right now.\n        }\n\n        public void Seek(long p)\n        {\n            Position = (int)p;\n        }\n\n        public void Skip(int count)\n        {\n            Position += count;\n        }\n\n        public byte ReadUInt8()\n        {\n            if (Position + 1 > Length)\n            {\n                return 0;\n            }\n\n            return _data[Position++];\n        }\n\n        public sbyte ReadInt8()\n        {\n            if (Position + 1 > Length)\n            {\n                return 0;\n            }\n\n            return (sbyte)_data[Position++];\n        }\n\n        public bool ReadBool() => ReadUInt8() != 0;\n\n        public ushort ReadUInt16LE()\n        {\n            if (Position + 2 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadUInt16LittleEndian(_data.Slice(Position), out ushort v);\n\n            Skip(2);\n\n            return v;\n        }\n\n        public short ReadInt16LE()\n        {\n            if (Position + 2 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadInt16LittleEndian(_data.Slice(Position), out short v);\n\n            Skip(2);\n\n            return v;\n        }\n\n        public uint ReadUInt32LE()\n        {\n            if (Position + 4 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadUInt32LittleEndian(_data.Slice(Position), out uint v);\n\n            Skip(4);\n\n            return v;\n        }\n\n        public int ReadInt32LE()\n        {\n            if (Position + 4 > Length)\n            {\n                return 0;\n            }\n\n            int v = BinaryPrimitives.ReadInt32LittleEndian(_data.Slice(Position));\n\n            Skip(4);\n\n            return v;\n        }\n\n        public ulong ReadUInt64LE()\n        {\n            if (Position + 8 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadUInt64LittleEndian(_data.Slice(Position), out ulong v);\n\n            Skip(8);\n\n            return v;\n        }\n\n        public long ReadInt64LE()\n        {\n            if (Position + 8 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadInt64LittleEndian(_data.Slice(Position), out long v);\n\n            Skip(8);\n\n            return v;\n        }\n\n\n\n\n\n        public ushort ReadUInt16BE()\n        {\n            if (Position + 2 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadUInt16BigEndian(_data.Slice(Position), out ushort v);\n\n            Skip(2);\n\n            return v;\n        }\n\n        public short ReadInt16BE()\n        {\n            if (Position + 2 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadInt16BigEndian(_data.Slice(Position), out short v);\n\n            Skip(2);\n\n            return v;\n        }\n\n        public uint ReadUInt32BE()\n        {\n            if (Position + 4 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadUInt32BigEndian(_data.Slice(Position), out uint v);\n\n            Skip(4);\n\n            return v;\n        }\n\n        public int ReadInt32BE()\n        {\n            if (Position + 4 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadInt32BigEndian(_data.Slice(Position), out int v);\n\n            Skip(4);\n\n            return v;\n        }\n\n        public ulong ReadUInt64BE()\n        {\n            if (Position + 8 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadUInt64BigEndian(_data.Slice(Position), out ulong v);\n\n            Skip(8);\n\n            return v;\n        }\n\n        public long ReadInt64BE()\n        {\n            if (Position + 8 > Length)\n            {\n                return 0;\n            }\n\n            BinaryPrimitives.TryReadInt64BigEndian(_data.Slice(Position), out long v);\n\n            Skip(8);\n\n            return v;\n        }\n\n        private string ReadRawString(int length, int sizeT, bool safe)\n        {\n            if (length == 0 || Position + sizeT > Length)\n            {\n                return string.Empty;\n            }\n\n            bool fixedLength = length > 0;\n            int remaining = Remaining;\n            int size;\n\n            if (fixedLength)\n            {\n                size = length * sizeT;\n\n                if (size > remaining)\n                {\n                    size = remaining;\n                }\n            }\n            else\n            {\n                size = remaining - (remaining & (sizeT - 1));\n            }\n\n            ReadOnlySpan<byte> slice = _data.Slice(Position, size);\n\n            int index = GetIndexOfZero(slice, sizeT);\n            size = index < 0 ? size : index;\n\n            string result;\n\n            if (size <= 0)\n            {\n                result = String.Empty;\n            }\n            else\n            {\n                result = StringHelper.Cp1252ToString(slice.Slice(0, size));\n\n                if (safe)\n                {\n                    Span<char> buff = stackalloc char[256];\n                    ReadOnlySpan<char> chars = result.AsSpan();\n\n                    ValueStringBuilder sb = new ValueStringBuilder(buff);\n\n                    bool hasDoneAnyReplacements = false;\n                    int last = 0;\n                    for (int i = 0; i < chars.Length; i++)\n                    {\n                        if (!StringHelper.IsSafeChar(chars[i]))\n                        {\n                            hasDoneAnyReplacements = true;\n                            sb.Append(chars.Slice(last, i - last));\n                            last = i + 1; // Skip the unsafe char\n                        }\n                    }\n\n                    if (hasDoneAnyReplacements)\n                    {\n                        // append the rest of the string\n                        if (last < chars.Length)\n                        {\n                            sb.Append(chars.Slice(last, chars.Length - last));\n                        }\n\n                        result = sb.ToString();\n                    }\n\n                    sb.Dispose();\n                }\n            }\n\n            Position += Math.Max(size + (!fixedLength && index >= 0 ? sizeT : 0), length * sizeT);\n\n            return result;\n        }\n\n        public string ReadASCII(bool safe = false)\n        {\n            return ReadRawString(-1, 1, safe);\n            //return ReadString(StringHelper.Cp1252Encoding, -1, 1, safe);\n        }\n\n        public string ReadASCII(int length, bool safe = false)\n        {\n            return ReadRawString(length, 1, safe);\n\n            //return ReadString(StringHelper.Cp1252Encoding, length, 1, safe);\n        }\n\n        public string ReadUnicodeBE(bool safe = false)\n        {\n            return ReadString(Encoding.BigEndianUnicode, -1, 2, safe);\n        }\n\n        public string ReadUnicodeBE(int length, bool safe = false)\n        {\n            return ReadString(Encoding.BigEndianUnicode, length, 2, safe);\n        }\n\n        public string ReadUnicodeLE(bool safe = false)\n        {\n            return ReadString(Encoding.Unicode, -1, 2, safe);\n        }\n\n        public string ReadUnicodeLE(int length, bool safe = false)\n        {\n            return ReadString(Encoding.Unicode, length, 2, safe);\n        }\n\n        public string ReadUTF8(bool safe = false)\n        {\n            return ReadString(Encoding.UTF8, -1, 1, safe);\n        }\n\n        public string ReadUTF8(int length, bool safe = false)\n        {\n            return ReadString(Encoding.UTF8, length, 1, safe);\n        }\n\n        public void Read(Span<byte> data, int offset, int count)\n        {\n            _data.Slice(Position + offset, count).CopyTo(data);\n        }\n\n        // from modernuo <3\n        private string ReadString(Encoding encoding, int length, int sizeT, bool safe)\n        {\n            if (length == 0 || Position + sizeT > Length)\n            {\n                return string.Empty;\n            }\n\n            bool fixedLength = length > 0;\n            int remaining = Remaining;\n            int size;\n\n            if (fixedLength)\n            {\n                size = length * sizeT;\n\n                if (size > remaining)\n                {\n                    size = remaining;\n                }\n            }\n            else\n            {\n                size = remaining - (remaining & (sizeT - 1));\n            }\n\n            ReadOnlySpan<byte> slice = _data.Slice(Position, size);\n\n            int index = GetIndexOfZero(slice, sizeT);\n            size = index < 0 ? size : index;\n\n            string result;\n\n            fixed (byte* ptr = slice)\n            {\n                result = encoding.GetString(ptr, size);\n            }\n\n            if (safe)\n            {\n                Span<char> buff = stackalloc char[256];\n                ReadOnlySpan<char> chars = result.AsSpan();\n\n                ValueStringBuilder sb = new ValueStringBuilder(buff);\n\n                bool hasDoneAnyReplacements = false;\n                int last = 0;\n                for (int i = 0; i < chars.Length; i++)\n                {\n                    if (!StringHelper.IsSafeChar(chars[i]))\n                    {\n                        hasDoneAnyReplacements = true;\n                        sb.Append(chars.Slice(last, i - last));\n                        last = i + 1; // Skip the unsafe char\n                    }\n                }\n\n                if (hasDoneAnyReplacements)\n                {\n                    // append the rest of the string\n                    if (last < chars.Length)\n                    {\n                        sb.Append(chars.Slice(last, chars.Length - last));\n                    }\n\n                    result = sb.ToString();\n                }\n\n                sb.Dispose();\n            }\n\n            Position += Math.Max(size + (!fixedLength && index >= 0 ? sizeT : 0), length * sizeT);\n\n            return result;\n        }\n\n        private static int GetIndexOfZero(ReadOnlySpan<byte> span, int sizeT)\n        {\n            switch (sizeT)\n            {\n                case 2: return MemoryMarshal.Cast<byte, char>(span).IndexOf('\\0') * 2;\n                case 4: return MemoryMarshal.Cast<byte, uint>(span).IndexOf((uint)0) * 4;\n                default: return span.IndexOf((byte)0);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Razor/UltimaSDK/StringEntry.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Text.RegularExpressions;\n\nnamespace Ultima\n{\n    public sealed class StringEntry\n    {\n        [Flags]\n        public enum CliLocFlag\n        {\n            Original = 0x0,\n            Custom = 0x1,\n            Modified = 0x2\n        }\n\n        private string m_Text;\n\n        public int Number { get; private set; }\n\n        public string Text\n        {\n            get { return m_Text; }\n            set\n            {\n                if (value == null)\n                    m_Text = \"\";\n                else\n                    m_Text = value;\n            }\n        }\n\n        public CliLocFlag Flag { get; set; }\n\n        public StringEntry(int number, string text, byte flag)\n        {\n            Number = number;\n            m_Text = text;\n            Flag = (CliLocFlag) flag;\n        }\n\n        public StringEntry(int number, string text, CliLocFlag flag)\n        {\n            Number = number;\n            m_Text = text;\n            Flag = flag;\n        }\n\n        // Razor\n        private static Regex m_RegEx = new Regex(@\"~(\\d+)[_\\w]+~\",\n            RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant);\n\n        private string m_FmtTxt;\n        private static object[] m_Args = new object[] {\"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\", \"\"};\n\n        public string Format(params object[] args)\n        {\n            if (m_FmtTxt == null)\n                m_FmtTxt = m_RegEx.Replace(m_Text, @\"{$1}\");\n            for (int i = 0; i < args.Length && i < 10; i++)\n                m_Args[i + 1] = args[i];\n            return String.Format(m_FmtTxt, m_Args);\n        }\n\n        public string SplitFormat(string argstr)\n        {\n            if (m_FmtTxt == null)\n                m_FmtTxt = m_RegEx.Replace(m_Text, @\"{$1}\");\n            string[] args = argstr.Split('\\t'); // adds an extra on to the args array\n            for (int i = 0; i < args.Length && i < 10; i++)\n                m_Args[i + 1] = args[i];\n            return String.Format(m_FmtTxt, m_Args);\n            /*\n            {\n                 StringBuilder sb = new StringBuilder();\n                 sb.Append( m_FmtTxt );\n                 for(int i=0;i<args.Length;i++)\n                 {\n                      sb.Append( \"|\" );\n                      sb.Append( args[i] == null ? \"-null-\" : args[i] );\n                 }\n                 throw new Exception( sb.ToString() );\n            }*/\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/StringHelper.cs",
    "content": "#region license\n\n// Copyright (c) 2021, andreakarasho\n// All rights reserved.\n// \n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n// 1. Redistributions of source code must retain the above copyright\n//    notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n//    notice, this list of conditions and the following disclaimer in the\n//    documentation and/or other materials provided with the distribution.\n// 3. All advertising materials mentioning features or use of this software\n//    must display the following acknowledgement:\n//    This product includes software developed by andreakarasho - https://github.com/andreakarasho\n// 4. Neither the name of the copyright holder nor the\n//    names of its contributors may be used to endorse or promote products\n//    derived from this software without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY\n// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY\n// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\n\nnamespace Ultima\n{\n    internal static class StringHelper\n    {\n        private static readonly char[] _dots = { '.', ',', ';', '!' };\n\n        public static IEnumerable<byte> StringToCp1252Bytes(string s, int length = -1)\n        {\n            length = length > 0 ? Math.Min(length, s.Length) : s.Length;\n\n            for (int i = 0; i < length; i += char.IsSurrogatePair(s, i) ? 2 : 1)\n            {\n                yield return UnicodeToCp1252(char.ConvertToUtf32(s, i));\n            }\n        }\n\n        public static string Cp1252ToString(ReadOnlySpan<byte> strCp1252)\n        {\n            var sb = new ValueStringBuilder(strCp1252.Length);\n\n            for (int i = 0; i < strCp1252.Length; ++i)\n            {\n                sb.Append(char.ConvertFromUtf32(Cp1252ToUnicode(strCp1252[i])));\n            }\n\n            var str = sb.ToString();\n\n            sb.Dispose();\n\n            return str;\n        }\n\n        /// <summary>\n        /// Converts a unicode code point into a cp1252 code point\n        /// </summary>\n        private static byte UnicodeToCp1252(int codepoint)\n        {\n            if (codepoint >= 0x80 && codepoint <= 0x9f)\n                return (byte)'?';\n            else if (codepoint <= 0xff)\n                return (byte)codepoint;\n            else\n            {\n                switch (codepoint)\n                {\n                    case 0x20AC: return 128; //€\n                    case 0x201A: return 130; //‚\n                    case 0x0192: return 131; //ƒ\n                    case 0x201E: return 132; //„\n                    case 0x2026: return 133; //…\n                    case 0x2020: return 134; //†\n                    case 0x2021: return 135; //‡\n                    case 0x02C6: return 136; //ˆ\n                    case 0x2030: return 137; //‰\n                    case 0x0160: return 138; //Š\n                    case 0x2039: return 139; //‹\n                    case 0x0152: return 140; //Œ\n                    case 0x017D: return 142; //Ž\n                    case 0x2018: return 145; //‘\n                    case 0x2019: return 146; //’\n                    case 0x201C: return 147; //“\n                    case 0x201D: return 148; //”\n                    case 0x2022: return 149; //•\n                    case 0x2013: return 150; //–\n                    case 0x2014: return 151; //—\n                    case 0x02DC: return 152; //˜\n                    case 0x2122: return 153; //™\n                    case 0x0161: return 154; //š\n                    case 0x203A: return 155; //›\n                    case 0x0153: return 156; //œ\n                    case 0x017E: return 158; //ž\n                    case 0x0178: return 159; //Ÿ\n                    default: return (byte)'?';\n                }\n            }\n        }\n\n        /// <summary>\n        /// Converts a cp1252 code point into a unicode code point\n        /// </summary>\n        private static int Cp1252ToUnicode(byte codepoint)\n        {\n            switch (codepoint)\n            {\n                case 128: return 0x20AC; //€\n                case 130: return 0x201A; //‚\n                case 131: return 0x0192; //ƒ\n                case 132: return 0x201E; //„\n                case 133: return 0x2026; //…\n                case 134: return 0x2020; //†\n                case 135: return 0x2021; //‡\n                case 136: return 0x02C6; //ˆ\n                case 137: return 0x2030; //‰\n                case 138: return 0x0160; //Š\n                case 139: return 0x2039; //‹\n                case 140: return 0x0152; //Œ\n                case 142: return 0x017D; //Ž\n                case 145: return 0x2018; //‘\n                case 146: return 0x2019; //’\n                case 147: return 0x201C; //“\n                case 148: return 0x201D; //”\n                case 149: return 0x2022; //•\n                case 150: return 0x2013; //–\n                case 151: return 0x2014; //—\n                case 152: return 0x02DC; //˜\n                case 153: return 0x2122; //™\n                case 154: return 0x0161; //š\n                case 155: return 0x203A; //›\n                case 156: return 0x0153; //œ\n                case 158: return 0x017E; //ž\n                case 159: return 0x0178; //Ÿ\n                default: return codepoint;\n            }\n        }\n\n        public static string CapitalizeFirstCharacter(string str)\n        {\n            if (string.IsNullOrEmpty(str))\n            {\n                return string.Empty;\n            }\n\n            if (str.Length == 1)\n            {\n                return char.ToUpper(str[0]).ToString();\n            }\n\n            return char.ToUpper(str[0]) + str.Substring(1);\n        }\n\n\n        public static string CapitalizeAllWords(string str)\n        {\n            if (string.IsNullOrEmpty(str))\n            {\n                return string.Empty;\n            }\n\n            Span<char> span = stackalloc char[str.Length];\n            ValueStringBuilder sb = new ValueStringBuilder(span);\n            bool capitalizeNext = true;\n\n            for (int i = 0; i < str.Length; i++)\n            {\n                sb.Append(capitalizeNext ? char.ToUpper(str[i]) : str[i]);\n\n                if (!char.IsWhiteSpace(str[i]))\n                {\n                    capitalizeNext = i + 1 < str.Length && char.IsWhiteSpace(str[i + 1]);\n                }\n            }\n\n            string ss = sb.ToString();\n\n            sb.Dispose();\n\n            return ss;\n        }\n\n        public static string CapitalizeWordsByLimitator(string str)\n        {\n            if (string.IsNullOrEmpty(str))\n            {\n                return string.Empty;\n            }\n\n            Span<char> span = stackalloc char[str.Length];\n            ValueStringBuilder sb = new ValueStringBuilder(span);\n\n            bool capitalizeNext = true;\n\n            for (int i = 0; i < str.Length; i++)\n            {\n                sb.Append(capitalizeNext ? char.ToUpper(str[i]) : str[i]);\n                capitalizeNext = false;\n\n                for (int j = 0; j < _dots.Length; j++)\n                {\n                    if (str[i] == _dots[j])\n                    {\n                        capitalizeNext = true;\n\n                        break;\n                    }\n                }\n            }\n\n            string ss = sb.ToString();\n\n            sb.Dispose();\n\n            return ss;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static bool IsSafeChar(int c)\n        {\n            return c >= 0x20 && c < 0xFFFE;\n        }\n\n        public static void AddSpaceBeforeCapital(string[] str, bool checkAcronyms = true)\n        {\n            for (int i = 0; i < str.Length; i++)\n            {\n                str[i] = AddSpaceBeforeCapital(str[i], checkAcronyms);\n            }\n        }\n\n        public static string AddSpaceBeforeCapital(string str, bool checkAcronyms = true)\n        {\n            if (string.IsNullOrWhiteSpace(str))\n            {\n                return \"\";\n            }\n\n            ValueStringBuilder sb = new ValueStringBuilder(str.Length * 2);\n            sb.Append(str[0]);\n\n            for (int i = 1, len = str.Length - 1; i <= len; i++)\n            {\n                if (char.IsUpper(str[i]))\n                {\n                    if (str[i - 1] != ' ' && !char.IsUpper(str[i - 1]) || checkAcronyms && char.IsUpper(str[i - 1]) && i < len && !char.IsUpper(str[i + 1]))\n                    {\n                        sb.Append(' ');\n                    }\n                }\n\n                sb.Append(str[i]);\n            }\n\n            string s = sb.ToString();\n\n            sb.Dispose();\n\n            return s;\n        }\n\n        public static string RemoveUpperLowerChars(string str, bool removelower = true)\n        {\n            if (string.IsNullOrWhiteSpace(str))\n            {\n                return \"\";\n            }\n\n            Span<char> span = stackalloc char[str.Length];\n            ValueStringBuilder sb = new ValueStringBuilder(span);\n\n            for (int i = 0; i < str.Length; i++)\n            {\n                if (char.IsUpper(str[i]) == removelower || str[i] == ' ')\n                {\n                    sb.Append(str[i]);\n                }\n            }\n\n            string ss = sb.ToString();\n\n            sb.Dispose();\n\n            return ss;\n        }\n\n        public static string IntToAbbreviatedString(int num)\n        {\n            if (num > 999999)\n            {\n                return string.Format(\"{0}M+\", num / 1000000);\n            }\n\n            if (num > 999)\n            {\n                return string.Format(\"{0}K+\", num / 1000);\n            }\n\n            return num.ToString();\n        }\n\n\n        public static string GetPluralAdjustedString(string str, bool plural = false)\n        {\n            if (str.Contains(\"%\"))\n            {\n                string[] parts = str.Split(new[] { '%' }, System.StringSplitOptions.RemoveEmptyEntries);\n\n                if (parts.Length < 2)\n                {\n                    return str;\n                }\n\n                Span<char> span = stackalloc char[str.Length];\n                ValueStringBuilder sb = new ValueStringBuilder(span);\n\n                sb.Append(parts[0]);\n\n                if (parts[1].Contains(\"/\"))\n                {\n                    string[] pluralparts = parts[1].Split('/');\n\n                    if (plural)\n                    {\n                        sb.Append(pluralparts[0]);\n                    }\n                    else if (pluralparts.Length > 1)\n                    {\n                        sb.Append(pluralparts[1]);\n                    }\n                }\n                else if (plural)\n                {\n                    sb.Append(parts[1]);\n                }\n\n                if (parts.Length == 3)\n                {\n                    sb.Append(parts[2]);\n                }\n\n                string ss = sb.ToString();\n\n                sb.Dispose();\n\n                return ss;\n            }\n\n            return str;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public static unsafe bool UnsafeCompare(char* buffer, string str, int length)\n        {\n            for (int i = 0; i < length && i < str.Length; ++i)\n            {\n                if (buffer[i] != str[i])\n                {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/StringList.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text;\nusing Assistant;\n\nnamespace Ultima\n{\n    public sealed class StringList\n    {\n        private int m_Header1;\n        private short m_Header2;\n\n        public List<StringEntry> Entries { get; set; }\n        public string Language { get; private set; }\n\n        private Dictionary<int, string> m_StringTable;\n        private Dictionary<int, StringEntry> m_EntryTable;\n\n        private static byte[] m_Buffer = new byte[1024];\n\n        /// <summary>\n        /// Initialize <see cref=\"StringList\"/> of Language\n        /// </summary>\n        /// <param name=\"language\"></param>\n        public StringList(string language)\n        {\n            Language = language;\n            LoadEntry(Files.GetFilePath($\"cliloc.{language}\"));\n        }\n\n        /// <summary>\n        /// Initialize <see cref=\"StringList\"/> of Language from path\n        /// </summary>\n        /// <param name=\"language\"></param>\n        /// <param name=\"path\"></param>\n        public StringList(string language, string path)\n        {\n            Language = language;\n            \n            LoadEntry(path);\n        }\n\n        private void LoadEntry(string path)\n        {\n            if (Engine.ClientVersion.Major >= 7 && Engine.ClientVersion.Build >= 105)\n            {\n                LoadNewEntryFormat(path);\n            }\n            else\n            {\n                LoadOldEntryFormat(path);\n            }\n        }\n\n        private void LoadOldEntryFormat(string path)\n        {\n            if (path == null)\n            {\n                Entries = new List<StringEntry>(0);\n                return;\n            }\n\n            Entries = new List<StringEntry>();\n            m_StringTable = new Dictionary<int, string>();\n            m_EntryTable = new Dictionary<int, StringEntry>();\n\n            using (BinaryReader bin =\n                new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)))\n            {\n                m_Header1 = bin.ReadInt32();\n                m_Header2 = bin.ReadInt16();\n\n                while (bin.BaseStream.Length != bin.BaseStream.Position)\n                {\n                    int number = bin.ReadInt32();\n                    byte flag = bin.ReadByte();\n                    int length = bin.ReadInt16();\n\n                    if (length > m_Buffer.Length)\n                        m_Buffer = new byte[(length + 1023) & ~1023];\n\n                    bin.Read(m_Buffer, 0, length);\n                    string text = Encoding.UTF8.GetString(m_Buffer, 0, length);\n\n                    StringEntry se = new StringEntry(number, text, flag);\n                    Entries.Add(se);\n\n                    m_StringTable[number] = text;\n                    m_EntryTable[number] = se;\n                }\n            }\n        }\n        \n        // Based on the implementation from Karasho @ ClassicUO\n        private void LoadNewEntryFormat(string path)\n        {\n            if (path == null)\n            {\n                Entries = new List<StringEntry>(0);\n                return;\n            }\n\n            Entries = new List<StringEntry>();\n            m_StringTable = new Dictionary<int, string>();\n            m_EntryTable = new Dictionary<int, StringEntry>();\n\n            using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))\n            {\n                int bytesRead;\n                var totalRead = 0;\n                var buf = new byte[fileStream.Length];\n                while ((bytesRead = fileStream.Read(buf, totalRead, Math.Min(4096, buf.Length - totalRead))) > 0)\n                    totalRead += bytesRead;\n\n                var output = buf[3] == 0x8E ? BwtDecompress.Decompress(buf) : buf;\n\n                var reader = new StackDataReader(output);\n                m_Header1 = reader.ReadInt32LE();\n                m_Header2 = reader.ReadInt16LE();\n\n                while (reader.Remaining > 0)\n                {\n                    var number = reader.ReadInt32LE();\n                    var flag = reader.ReadUInt8();\n                    var length = reader.ReadInt16LE();\n                    var text = string.Intern(reader.ReadUTF8(length));\n\n                    m_StringTable[number] = text;\n                    StringEntry se = new StringEntry(number, text, flag);\n                    Entries.Add(se);\n                    m_EntryTable[number] = se;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Saves <see cref=\"SaveStringList\"/> to FileName\n        /// </summary>\n        /// <param name=\"FileName\"></param>\n        public void SaveStringList(string FileName)\n        {\n            using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    bin.Write(m_Header1);\n                    bin.Write(m_Header2);\n                    Entries.Sort(new StringList.NumberComparer(false));\n                    foreach (StringEntry entry in Entries)\n                    {\n                        bin.Write(entry.Number);\n                        bin.Write((byte) entry.Flag);\n                        byte[] utf8String = Encoding.UTF8.GetBytes(entry.Text);\n                        ushort length = (ushort) utf8String.Length;\n                        bin.Write(length);\n                        bin.Write(utf8String);\n                    }\n                }\n            }\n        }\n\n        public string GetString(int number)\n        {\n            if (m_StringTable == null || !m_StringTable.ContainsKey(number))\n                return null;\n\n            return m_StringTable[number];\n        }\n\n        public StringEntry GetEntry(int number)\n        {\n            if (m_EntryTable == null || !m_EntryTable.ContainsKey(number))\n                return null;\n\n            return m_EntryTable[number];\n        }\n\n        #region SortComparer\n\n        public class NumberComparer : IComparer<StringEntry>\n        {\n            private bool m_desc;\n\n            public NumberComparer(bool desc)\n            {\n                m_desc = desc;\n            }\n\n            public int Compare(StringEntry objA, StringEntry objB)\n            {\n                if (objA.Number == objB.Number)\n                    return 0;\n                else if (m_desc)\n                    return (objA.Number < objB.Number) ? 1 : -1;\n                else\n                    return (objA.Number < objB.Number) ? -1 : 1;\n            }\n        }\n\n        public class FlagComparer : IComparer<StringEntry>\n        {\n            private bool m_desc;\n\n            public FlagComparer(bool desc)\n            {\n                m_desc = desc;\n            }\n\n            public int Compare(StringEntry objA, StringEntry objB)\n            {\n                if ((byte) objA.Flag == (byte) objB.Flag)\n                {\n                    if (objA.Number == objB.Number)\n                        return 0;\n                    else if (m_desc)\n                        return (objA.Number < objB.Number) ? 1 : -1;\n                    else\n                        return (objA.Number < objB.Number) ? -1 : 1;\n                }\n                else if (m_desc)\n                    return ((byte) objA.Flag < (byte) objB.Flag) ? 1 : -1;\n                else\n                    return ((byte) objA.Flag < (byte) objB.Flag) ? -1 : 1;\n            }\n        }\n\n        public class TextComparer : IComparer<StringEntry>\n        {\n            private bool m_desc;\n\n            public TextComparer(bool desc)\n            {\n                m_desc = desc;\n            }\n\n            public int Compare(StringEntry objA, StringEntry objB)\n            {\n                if (m_desc)\n                    return String.Compare(objB.Text, objA.Text);\n                else\n                    return String.Compare(objA.Text, objB.Text);\n            }\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Textures.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\nusing System.Security.Cryptography;\nusing System.Collections.Generic;\n\nnamespace Ultima\n{\n    public sealed class Textures\n    {\n        private static FileIndex m_FileIndex = new FileIndex(\"Texidx.mul\", \"Texmaps.mul\", 0x4000, 10);\n        private static Bitmap[] m_Cache = new Bitmap[0x4000];\n        private static bool[] m_Removed = new bool[0x4000];\n        private static Hashtable m_patched = new Hashtable();\n\n        private static byte[] m_StreamBuffer;\n\n        struct CheckSums\n        {\n            public byte[] checksum;\n            public int pos;\n            public int length;\n            public int index;\n        }\n\n        private static List<CheckSums> checksums;\n\n        /// <summary>\n        /// ReReads texmaps\n        /// </summary>\n        public static void Reload()\n        {\n            m_FileIndex = new FileIndex(\"Texidx.mul\", \"Texmaps.mul\", 0x4000, 10);\n            m_Cache = new Bitmap[0x4000];\n            m_Removed = new bool[0x4000];\n            m_patched.Clear();\n        }\n\n        public static int GetIdxLength()\n        {\n            return (int) (m_FileIndex.IdxLength / 12);\n        }\n\n        /// <summary>\n        /// Removes Texture <see cref=\"m_Removed\"/>\n        /// </summary>\n        /// <param name=\"index\"></param>\n        public static void Remove(int index)\n        {\n            m_Removed[index] = true;\n        }\n\n        /// <summary>\n        /// Replaces Texture\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"bmp\"></param>\n        public static void Replace(int index, Bitmap bmp)\n        {\n            m_Cache[index] = bmp;\n            m_Removed[index] = false;\n            if (m_patched.Contains(index))\n                m_patched.Remove(index);\n        }\n\n        /// <summary>\n        /// Tests if index is valid Texture\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public static bool TestTexture(int index)\n        {\n            int length, extra;\n            bool patched;\n            if (m_Removed[index])\n                return false;\n            if (m_Cache[index] != null)\n                return true;\n            bool valid = m_FileIndex.Valid(index, out length, out extra, out patched);\n            if ((!valid) || (length == 0))\n                return false;\n            return true;\n        }\n\n        /// <summary>\n        /// Returns Bitmap of Texture\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <returns></returns>\n        public unsafe static Bitmap GetTexture(int index)\n        {\n            bool patched;\n            return GetTexture(index, out patched);\n        }\n\n        /// <summary>\n        /// Returns Bitmap of Texture with verdata bool\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"patched\"></param>\n        /// <returns></returns>\n        public unsafe static Bitmap GetTexture(int index, out bool patched)\n        {\n            if (m_patched.Contains(index))\n                patched = (bool) m_patched[index];\n            else\n                patched = false;\n            if (m_Removed[index])\n                return null;\n            if (m_Cache[index] != null)\n                return m_Cache[index];\n\n            int length, extra;\n            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);\n            if (stream == null)\n                return null;\n            if (length == 0)\n                return null;\n            if (patched)\n                m_patched[index] = true;\n\n            int size = extra == 0 ? 64 : 128;\n\n            Bitmap bmp = new Bitmap(size, size, PixelFormat.Format16bppArgb1555);\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, size, size), ImageLockMode.WriteOnly,\n                PixelFormat.Format16bppArgb1555);\n\n            ushort* line = (ushort*) bd.Scan0;\n            int delta = bd.Stride >> 1;\n\n            int max = size * size * 2;\n\n            if (m_StreamBuffer == null || m_StreamBuffer.Length < max)\n                m_StreamBuffer = new byte[max];\n            stream.Read(m_StreamBuffer, 0, max);\n\n            fixed (byte* data = m_StreamBuffer)\n            {\n                ushort* bindat = (ushort*) data;\n                for (int y = 0; y < size; ++y, line += delta)\n                {\n                    ushort* cur = line;\n                    ushort* end = cur + size;\n\n                    while (cur < end)\n                        *cur++ = (ushort) (*bindat++ ^ 0x8000);\n                }\n            }\n\n            bmp.UnlockBits(bd);\n\n            stream.Close();\n            if (!Files.CacheData)\n                return m_Cache[index] = bmp;\n            else\n                return bmp;\n        }\n\n        public unsafe static void Save(string path)\n        {\n            string idx = Path.Combine(path, \"texidx.mul\");\n            string mul = Path.Combine(path, \"texmaps.mul\");\n            checksums = new List<CheckSums>();\n            using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),\n                fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                MemoryStream memidx = new MemoryStream();\n                MemoryStream memmul = new MemoryStream();\n                using (BinaryWriter binidx = new BinaryWriter(memidx),\n                    binmul = new BinaryWriter(memmul))\n                {\n                    SHA256Managed sha = new SHA256Managed();\n                    //StreamWriter Tex = new StreamWriter(new FileStream(\"d:/texlog.txt\", FileMode.Create, FileAccess.ReadWrite));\n                    for (int index = 0; index < GetIdxLength(); ++index)\n                    {\n                        if (m_Cache[index] == null)\n                            m_Cache[index] = GetTexture(index);\n\n                        Bitmap bmp = m_Cache[index];\n                        if ((bmp == null) || (m_Removed[index]))\n                        {\n                            binidx.Write((int) -1); // lookup\n                            binidx.Write((int) 0); // length\n                            binidx.Write((int) -1); // extra\n                        }\n                        else\n                        {\n                            MemoryStream ms = new MemoryStream();\n                            bmp.Save(ms, ImageFormat.Bmp);\n                            byte[] checksum = sha.ComputeHash(ms.ToArray());\n                            CheckSums sum;\n                            if (compareSaveImages(checksum, out sum))\n                            {\n                                binidx.Write((int) sum.pos); //lookup\n                                binidx.Write((int) sum.length);\n                                binidx.Write((int) 0);\n                                //Tex.WriteLine(System.String.Format(\"0x{0:X4} : 0x{1:X4} 0x{2:X4}\", index, (int)sum.pos, (int)sum.length));\n                                //Tex.WriteLine(System.String.Format(\"0x{0:X4} -> 0x{1:X4}\", sum.index, index));\n                                continue;\n                            }\n\n                            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),\n                                ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555);\n                            ushort* line = (ushort*) bd.Scan0;\n                            int delta = bd.Stride >> 1;\n\n                            binidx.Write((int) binmul.BaseStream.Position); //lookup\n                            int length = (int) binmul.BaseStream.Position;\n\n                            for (int Y = 0; Y < bmp.Height; ++Y, line += delta)\n                            {\n                                ushort* cur = line;\n                                for (int X = 0; X < bmp.Width; ++X)\n                                {\n                                    binmul.Write((ushort) (cur[X] ^ 0x8000));\n                                }\n                            }\n\n                            int start = length;\n                            length = (int) binmul.BaseStream.Position - length;\n                            binidx.Write(length);\n                            binidx.Write((int) (bmp.Width == 64 ? 0 : 1));\n                            bmp.UnlockBits(bd);\n                            CheckSums s = new CheckSums()\n                                {pos = start, length = length, checksum = checksum, index = index};\n                            //Tex.WriteLine(System.String.Format(\"0x{0:X4} : 0x{1:X4} 0x{2:X4}\", index, start, length));\n                            checksums.Add(s);\n                        }\n                    }\n\n                    memidx.WriteTo(fsidx);\n                    memmul.WriteTo(fsmul);\n                }\n            }\n        }\n\n        private static bool compareSaveImages(byte[] newchecksum, out CheckSums sum)\n        {\n            sum = new CheckSums();\n            for (int i = 0; i < checksums.Count; ++i)\n            {\n                byte[] cmp = checksums[i].checksum;\n                if (((cmp == null) || (newchecksum == null))\n                    || (cmp.Length != newchecksum.Length))\n                {\n                    return false;\n                }\n\n                bool valid = true;\n                for (int j = 0; j < cmp.Length; ++j)\n                {\n                    if (cmp[j] != newchecksum[j])\n                    {\n                        valid = false;\n                        break;\n                    }\n                }\n\n                if (valid)\n                {\n                    sum = checksums[i];\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/TileData.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\nnamespace Ultima\n{\n    /// <summary>\n    /// Represents land tile data.\n    /// <seealso cref=\"ItemData\" />\n    /// <seealso cref=\"LandData\" />\n    /// </summary>\n    public struct LandData\n    {\n        private string m_Name;\n        private short m_TexID;\n        private TileFlag m_Flags;\n        private int m_Unk1;\n\n        public LandData(string name, int TexID, TileFlag flags, int unk1)\n        {\n            m_Name = name;\n            m_TexID = (short) TexID;\n            m_Flags = flags;\n            m_Unk1 = unk1;\n        }\n\n        public unsafe LandData(NewLandTileDataMul mulstruct)\n        {\n            m_TexID = mulstruct.texID;\n            m_Flags = (TileFlag) mulstruct.flags;\n            m_Unk1 = mulstruct.unk1;\n            m_Name = TileData.ReadNameString(mulstruct.name);\n        }\n\n        public unsafe LandData(OldLandTileDataMul mulstruct)\n        {\n            m_TexID = mulstruct.texID;\n            m_Flags = (TileFlag) mulstruct.flags;\n            m_Unk1 = 0;\n            m_Name = TileData.ReadNameString(mulstruct.name);\n        }\n\n        /// <summary>\n        /// Gets the name of this land tile.\n        /// </summary>\n        public string Name\n        {\n            get { return m_Name; }\n            set { m_Name = value; }\n        }\n\n        /// <summary>\n        /// Gets the Texture ID of this land tile.\n        /// </summary>\n        public short TextureID\n        {\n            get { return m_TexID; }\n            set { m_TexID = value; }\n        }\n\n        /// <summary>\n        /// Gets a bitfield representing the 32 individual flags of this land tile.\n        /// </summary>\n        public TileFlag Flags\n        {\n            get { return m_Flags; }\n            set { m_Flags = value; }\n        }\n\n        /// <summary>\n        /// Gets a new UOHSA Unknown Int\n        /// </summary>\n        public int Unk1\n        {\n            get { return m_Unk1; }\n            set { m_Unk1 = value; }\n        }\n\n        public void ReadData(string[] split)\n        {\n            int i = 1;\n            m_Name = split[i++];\n            m_TexID = (short) TileData.ConvertStringToInt(split[i++]);\n            m_Unk1 = TileData.ConvertStringToInt(split[i++]);\n            m_Flags = 0;\n            int temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Background;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Weapon;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Transparent;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Translucent;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Wall;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Damaging;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Impassable;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Wet;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Unknown1;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Surface;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Bridge;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Generic;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Window;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.NoShoot;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.ArticleA;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.ArticleAn;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Internal;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Foliage;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.PartialHue;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Unknown2;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Map;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Container;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Wearable;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.LightSource;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Animation;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.HoverOver;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Unknown3;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Armor;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Roof;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Door;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.StairBack;\n            temp = System.Convert.ToByte(split[i++]);\n            if (temp != 0)\n                m_Flags |= TileFlag.StairRight;\n        }\n    }\n\n    /// <summary>\n    /// Represents item tile data.\n    /// <seealso cref=\"TileData\" />\n    /// <seealso cref=\"LandData\" />\n    /// </summary>\n    public struct ItemData\n    {\n        internal string m_Name;\n        internal TileFlag m_Flags;\n        internal int m_Unk1;\n        internal byte m_Weight;\n        internal byte m_Quality;\n        internal byte m_Quantity;\n        internal byte m_Value;\n        internal byte m_Height;\n        internal short m_Animation;\n        internal byte m_Hue;\n        internal byte m_StackOffset;\n        internal short m_MiscData;\n        internal byte m_Unk2;\n        internal byte m_Unk3;\n\n        public ItemData(string name, TileFlag flags, int unk1, int weight, int quality, int quantity, int value,\n            int height, int anim, int hue, int stackingoffset, int MiscData, int unk2, int unk3)\n        {\n            m_Name = name;\n            m_Flags = flags;\n            m_Unk1 = unk1;\n            m_Weight = (byte) weight;\n            m_Quality = (byte) quality;\n            m_Quantity = (byte) quantity;\n            m_Value = (byte) value;\n            m_Height = (byte) height;\n            m_Animation = (short) anim;\n            m_Hue = (byte) hue;\n            m_StackOffset = (byte) stackingoffset;\n            m_MiscData = (short) MiscData;\n            m_Unk2 = (byte) unk2;\n            m_Unk3 = (byte) unk3;\n        }\n\n        public unsafe ItemData(NewItemTileDataMul mulstruct)\n        {\n            m_Name = TileData.ReadNameString(mulstruct.name);\n            m_Flags = (TileFlag) mulstruct.flags;\n            m_Unk1 = mulstruct.unk1;\n            m_Weight = mulstruct.weight;\n            m_Quality = mulstruct.quality;\n            m_Quantity = mulstruct.quantity;\n            m_Value = mulstruct.value;\n            m_Height = mulstruct.height;\n            m_Animation = mulstruct.anim;\n            m_Hue = mulstruct.hue;\n            m_StackOffset = mulstruct.stackingoffset;\n            m_MiscData = mulstruct.miscdata;\n            m_Unk2 = mulstruct.unk2;\n            m_Unk3 = mulstruct.unk3;\n        }\n\n        public unsafe ItemData(OldItemTileDataMul mulstruct)\n        {\n            m_Name = TileData.ReadNameString(mulstruct.name);\n            m_Flags = (TileFlag) mulstruct.flags;\n            m_Unk1 = 0;\n            m_Weight = mulstruct.weight;\n            m_Quality = mulstruct.quality;\n            m_Quantity = mulstruct.quantity;\n            m_Value = mulstruct.value;\n            m_Height = mulstruct.height;\n            m_Animation = mulstruct.anim;\n            m_Hue = mulstruct.hue;\n            m_StackOffset = mulstruct.stackingoffset;\n            m_MiscData = mulstruct.miscdata;\n            m_Unk2 = mulstruct.unk2;\n            m_Unk3 = mulstruct.unk3;\n        }\n\n        /// <summary>\n        /// Gets the name of this item.\n        /// </summary>\n        public string Name\n        {\n            get { return m_Name; }\n            set { m_Name = value; }\n        }\n\n        /// <summary>\n        /// Gets the animation body index of this item.\n        /// <seealso cref=\"Animations\" />\n        /// </summary>\n        public short Animation\n        {\n            get { return m_Animation; }\n            set { m_Animation = value; }\n        }\n\n        /// <summary>\n        /// Gets a bitfield representing the 32 individual flags of this item.\n        /// <seealso cref=\"TileFlag\" />\n        /// </summary>\n        public TileFlag Flags\n        {\n            get { return m_Flags; }\n            set { m_Flags = value; }\n        }\n\n        /// <summary>\n        /// Gets an unknown new UOAHS int\n        /// </summary>\n        public int Unk1\n        {\n            get { return m_Unk1; }\n            set { m_Unk1 = value; }\n        }\n\n        /// <summary>\n        /// Whether or not this item is flagged as '<see cref=\"TileFlag.Background\" />'.\n        /// <seealso cref=\"TileFlag\" />\n        /// </summary>\n        public bool Background\n        {\n            get { return ((m_Flags & TileFlag.Background) != 0); }\n        }\n\n        /// <summary>\n        /// Whether or not this item is flagged as '<see cref=\"TileFlag.Bridge\" />'.\n        /// <seealso cref=\"TileFlag\" />\n        /// </summary>\n        public bool Bridge\n        {\n            get { return ((m_Flags & TileFlag.Bridge) != 0); }\n        }\n\n        /// <summary>\n        /// Whether or not this item is flagged as '<see cref=\"TileFlag.Impassable\" />'.\n        /// <seealso cref=\"TileFlag\" />\n        /// </summary>\n        public bool Impassable\n        {\n            get { return ((m_Flags & TileFlag.Impassable) != 0); }\n        }\n\n        /// <summary>\n        /// Whether or not this item is flagged as '<see cref=\"TileFlag.Surface\" />'.\n        /// <seealso cref=\"TileFlag\" />\n        /// </summary>\n        public bool Surface\n        {\n            get { return ((m_Flags & TileFlag.Surface) != 0); }\n        }\n\n        /// <summary>\n        /// Gets the weight of this item.\n        /// </summary>\n        public byte Weight\n        {\n            get { return m_Weight; }\n            set { m_Weight = value; }\n        }\n\n        /// <summary>\n        /// Gets the 'quality' of this item. For wearable items, this will be the layer.\n        /// </summary>\n        public byte Quality\n        {\n            get { return m_Quality; }\n            set { m_Quality = value; }\n        }\n\n        /// <summary>\n        /// Gets the 'quantity' of this item.\n        /// </summary>\n        public byte Quantity\n        {\n            get { return m_Quantity; }\n            set { m_Quantity = value; }\n        }\n\n        /// <summary>\n        /// Gets the 'value' of this item.\n        /// </summary>\n        public byte Value\n        {\n            get { return m_Value; }\n            set { m_Value = value; }\n        }\n\n        /// <summary>\n        /// Gets the Hue of this item.\n        /// </summary>\n        public byte Hue\n        {\n            get { return m_Hue; }\n            set { m_Hue = value; }\n        }\n\n        /// <summary>\n        /// Gets the stackingoffset of this item. (If flag Generic)\n        /// </summary>\n        public byte StackingOffset\n        {\n            get { return m_StackOffset; }\n            set { m_StackOffset = value; }\n        }\n\n        /// <summary>\n        /// Gets the height of this item.\n        /// </summary>\n        public byte Height\n        {\n            get { return m_Height; }\n            set { m_Height = value; }\n        }\n\n        /// <summary>\n        /// Gets the MiscData of this item. (old UO Demo weapontemplate definition) (Unk1)\n        /// </summary>\n        public short MiscData\n        {\n            get { return m_MiscData; }\n            set { m_MiscData = value; }\n        }\n\n        /// <summary>\n        /// Gets the unk2 of this item.\n        /// </summary>\n        public byte Unk2\n        {\n            get { return m_Unk2; }\n            set { m_Unk2 = value; }\n        }\n\n        /// <summary>\n        /// Gets the unk3 of this item.\n        /// </summary>\n        public byte Unk3\n        {\n            get { return m_Unk3; }\n            set { m_Unk3 = value; }\n        }\n\n        /// <summary>\n        /// Gets the 'calculated height' of this item. For <see cref=\"Bridge\">bridges</see>, this will be: <c>(<see cref=\"Height\" /> / 2)</c>.\n        /// </summary>\n        public int CalcHeight\n        {\n            get\n            {\n                if ((m_Flags & TileFlag.Bridge) != 0)\n                    return m_Height / 2;\n                else\n                    return m_Height;\n            }\n        }\n\n        /// <summary>\n        /// Whether or not this item is wearable as '<see cref=\"TileFlag.Wearable\" />'.\n        /// <seealso cref=\"TileFlag\" />\n        /// </summary>\n        public bool Wearable\n        {\n            get { return ((m_Flags & TileFlag.Wearable) != 0); }\n        }\n\n        public void ReadData(string[] split)\n        {\n            m_Name = split[1];\n            m_Weight = System.Convert.ToByte(split[2]);\n            m_Quality = System.Convert.ToByte(split[3]);\n            m_Animation = (short) TileData.ConvertStringToInt(split[4]);\n            m_Height = System.Convert.ToByte(split[5]);\n            m_Hue = System.Convert.ToByte(split[6]);\n            m_Quantity = System.Convert.ToByte(split[7]);\n            m_StackOffset = System.Convert.ToByte(split[8]);\n            m_MiscData = System.Convert.ToInt16(split[9]);\n            m_Unk1 = System.Convert.ToInt32(split[10]);\n            m_Unk2 = System.Convert.ToByte(split[11]);\n            m_Unk3 = System.Convert.ToByte(split[12]);\n\n            m_Flags = 0;\n            int temp = System.Convert.ToByte(split[13]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Background;\n            temp = System.Convert.ToByte(split[14]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Weapon;\n            temp = System.Convert.ToByte(split[15]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Transparent;\n            temp = System.Convert.ToByte(split[16]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Translucent;\n            temp = System.Convert.ToByte(split[17]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Wall;\n            temp = System.Convert.ToByte(split[18]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Damaging;\n            temp = System.Convert.ToByte(split[19]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Impassable;\n            temp = System.Convert.ToByte(split[20]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Wet;\n            temp = System.Convert.ToByte(split[21]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Unknown1;\n            temp = System.Convert.ToByte(split[22]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Surface;\n            temp = System.Convert.ToByte(split[23]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Bridge;\n            temp = System.Convert.ToByte(split[24]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Generic;\n            temp = System.Convert.ToByte(split[25]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Window;\n            temp = System.Convert.ToByte(split[26]);\n            if (temp != 0)\n                m_Flags |= TileFlag.NoShoot;\n            temp = System.Convert.ToByte(split[27]);\n            if (temp != 0)\n                m_Flags |= TileFlag.ArticleA;\n            temp = System.Convert.ToByte(split[28]);\n            if (temp != 0)\n                m_Flags |= TileFlag.ArticleAn;\n            temp = System.Convert.ToByte(split[29]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Internal;\n            temp = System.Convert.ToByte(split[30]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Foliage;\n            temp = System.Convert.ToByte(split[31]);\n            if (temp != 0)\n                m_Flags |= TileFlag.PartialHue;\n            temp = System.Convert.ToByte(split[32]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Unknown2;\n            temp = System.Convert.ToByte(split[33]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Map;\n            temp = System.Convert.ToByte(split[34]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Container;\n            temp = System.Convert.ToByte(split[35]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Wearable;\n            temp = System.Convert.ToByte(split[36]);\n            if (temp != 0)\n                m_Flags |= TileFlag.LightSource;\n            temp = System.Convert.ToByte(split[37]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Animation;\n            temp = System.Convert.ToByte(split[38]);\n            if (temp != 0)\n                m_Flags |= TileFlag.HoverOver;\n            temp = System.Convert.ToByte(split[39]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Unknown3;\n            temp = System.Convert.ToByte(split[40]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Armor;\n            temp = System.Convert.ToByte(split[41]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Roof;\n            temp = System.Convert.ToByte(split[42]);\n            if (temp != 0)\n                m_Flags |= TileFlag.Door;\n            temp = System.Convert.ToByte(split[43]);\n            if (temp != 0)\n                m_Flags |= TileFlag.StairBack;\n            temp = System.Convert.ToByte(split[44]);\n            if (temp != 0)\n                m_Flags |= TileFlag.StairRight;\n        }\n    }\n\n    /// <summary>\n    /// An enumeration of 32 different tile flags.\n    /// <seealso cref=\"ItemData\" />\n    /// <seealso cref=\"LandData\" />\n    /// </summary>\n    [Flags]\n    public enum TileFlag\n    {\n        /// <summary>\n        /// Nothing is flagged.\n        /// </summary>\n        None = 0x00000000,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        Background = 0x00000001,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        Weapon = 0x00000002,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        Transparent = 0x00000004,\n\n        /// <summary>\n        /// The tile is rendered with partial alpha-transparency.\n        /// </summary>\n        Translucent = 0x00000008,\n\n        /// <summary>\n        /// The tile is a wall.\n        /// </summary>\n        Wall = 0x00000010,\n\n        /// <summary>\n        /// The tile can cause damage when moved over.\n        /// </summary>\n        Damaging = 0x00000020,\n\n        /// <summary>\n        /// The tile may not be moved over or through.\n        /// </summary>\n        Impassable = 0x00000040,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        Wet = 0x00000080,\n\n        /// <summary>\n        /// Unknown.\n        /// </summary>\n        Unknown1 = 0x00000100,\n\n        /// <summary>\n        /// The tile is a surface. It may be moved over, but not through.\n        /// </summary>\n        Surface = 0x00000200,\n\n        /// <summary>\n        /// The tile is a stair, ramp, or ladder.\n        /// </summary>\n        Bridge = 0x00000400,\n\n        /// <summary>\n        /// The tile is stackable\n        /// </summary>\n        Generic = 0x00000800,\n\n        /// <summary>\n        /// The tile is a window. Like <see cref=\"TileFlag.NoShoot\" />, tiles with this flag block line of sight.\n        /// </summary>\n        Window = 0x00001000,\n\n        /// <summary>\n        /// The tile blocks line of sight.\n        /// </summary>\n        NoShoot = 0x00002000,\n\n        /// <summary>\n        /// For single-amount tiles, the string \"a \" should be prepended to the tile name.\n        /// </summary>\n        ArticleA = 0x00004000,\n\n        /// <summary>\n        /// For single-amount tiles, the string \"an \" should be prepended to the tile name.\n        /// </summary>\n        ArticleAn = 0x00008000,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        Internal = 0x00010000,\n\n        /// <summary>\n        /// The tile becomes translucent when walked behind. Boat masts also have this flag.\n        /// </summary>\n        Foliage = 0x00020000,\n\n        /// <summary>\n        /// Only gray pixels will be hued\n        /// </summary>\n        PartialHue = 0x00040000,\n\n        /// <summary>\n        /// Unknown.\n        /// </summary>\n        Unknown2 = 0x00080000,\n\n        /// <summary>\n        /// The tile is a map--in the cartography sense. Unknown usage.\n        /// </summary>\n        Map = 0x00100000,\n\n        /// <summary>\n        /// The tile is a container.\n        /// </summary>\n        Container = 0x00200000,\n\n        /// <summary>\n        /// The tile may be equiped.\n        /// </summary>\n        Wearable = 0x00400000,\n\n        /// <summary>\n        /// The tile gives off light.\n        /// </summary>\n        LightSource = 0x00800000,\n\n        /// <summary>\n        /// The tile is animated.\n        /// </summary>\n        Animation = 0x01000000,\n\n        /// <summary>\n        /// Gargoyles can fly over\n        /// </summary>\n        HoverOver = 0x02000000,\n\n        /// <summary>\n        /// Unknown.\n        /// </summary>\n        Unknown3 = 0x04000000,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        Armor = 0x08000000,\n\n        /// <summary>\n        /// The tile is a slanted roof.\n        /// </summary>\n        Roof = 0x10000000,\n\n        /// <summary>\n        /// The tile is a door. Tiles with this flag can be moved through by ghosts and GMs.\n        /// </summary>\n        Door = 0x20000000,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        StairBack = 0x40000000,\n\n        /// <summary>\n        /// Not yet documented.\n        /// </summary>\n        StairRight = unchecked((int) 0x80000000)\n    }\n\n    /// <summary>\n    /// Contains lists of <see cref=\"LandData\">land</see> and <see cref=\"ItemData\">item</see> tile data.\n    /// <seealso cref=\"LandData\" />\n    /// <seealso cref=\"ItemData\" />\n    /// </summary>\n    public sealed class TileData\n    {\n        private static LandData[] m_LandData;\n        private static ItemData[] m_ItemData;\n        private static int[] m_HeightTable;\n\n        /// <summary>\n        /// Gets the list of <see cref=\"LandData\">land tile data</see>.\n        /// </summary>\n        public static LandData[] LandTable\n        {\n            get { return m_LandData; }\n            set { m_LandData = value; }\n        }\n\n        /// <summary>\n        /// Gets the list of <see cref=\"ItemData\">item tile data</see>.\n        /// </summary>\n        public static ItemData[] ItemTable\n        {\n            get { return m_ItemData; }\n            set { m_ItemData = value; }\n        }\n\n        public static int[] HeightTable\n        {\n            get { return m_HeightTable; }\n        }\n\n        private static byte[] m_StringBuffer = new byte[20];\n\n        private static string ReadNameString(BinaryReader bin)\n        {\n            bin.Read(m_StringBuffer, 0, 20);\n\n            int count;\n\n            for (count = 0; count < 20 && m_StringBuffer[count] != 0; ++count) ;\n\n            return Encoding.Default.GetString(m_StringBuffer, 0, count);\n        }\n\n        public unsafe static string ReadNameString(byte* buffer)\n        {\n            int count;\n            for (count = 0; count < 20 && *buffer != 0; ++count)\n                m_StringBuffer[count] = *buffer++;\n\n            return Encoding.Default.GetString(m_StringBuffer, 0, count);\n        }\n\n        private TileData()\n        {\n        }\n\n        private static int[] landheader;\n        private static int[] itemheader;\n\n        static TileData()\n        {\n            Initialize();\n        }\n\n        public unsafe static void Initialize()\n        {\n            string filePath = Files.GetFilePath(\"tiledata.mul\");\n\n            if (filePath != null)\n            {\n                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    bool useNeWTileDataFormat = Art.IsUOAHS();\n                    landheader = new int[512];\n                    int j = 0;\n                    m_LandData = new LandData[0x4000];\n\n                    byte[] buffer = new byte[fs.Length];\n                    GCHandle gc = GCHandle.Alloc(buffer, GCHandleType.Pinned);\n                    long currpos = 0;\n                    try\n                    {\n                        fs.Read(buffer, 0, buffer.Length);\n                        for (int i = 0; i < 0x4000; i += 32)\n                        {\n                            IntPtr ptrheader = new IntPtr((long) gc.AddrOfPinnedObject() + currpos);\n                            currpos += 4;\n                            landheader[j++] = (int) Marshal.PtrToStructure(ptrheader, typeof(int));\n                            for (int count = 0; count < 32; ++count)\n                            {\n                                IntPtr ptr = new IntPtr((long) gc.AddrOfPinnedObject() + currpos);\n                                if (useNeWTileDataFormat)\n                                {\n                                    currpos += sizeof(NewLandTileDataMul);\n                                    NewLandTileDataMul cur =\n                                        (NewLandTileDataMul) Marshal.PtrToStructure(ptr, typeof(NewLandTileDataMul));\n                                    m_LandData[i + count] = new LandData(cur);\n                                }\n                                else\n                                {\n                                    currpos += sizeof(OldLandTileDataMul);\n                                    OldLandTileDataMul cur =\n                                        (OldLandTileDataMul) Marshal.PtrToStructure(ptr, typeof(OldLandTileDataMul));\n                                    m_LandData[i + count] = new LandData(cur);\n                                }\n                            }\n                        }\n\n                        long remaining = buffer.Length - currpos;\n                        int structsize = useNeWTileDataFormat ? sizeof(NewItemTileDataMul) : sizeof(OldItemTileDataMul);\n                        itemheader = new int[(remaining / ((structsize * 32) + 4))];\n                        int itemlength = itemheader.Length * 32;\n\n                        m_ItemData = new ItemData[itemlength];\n                        m_HeightTable = new int[itemlength];\n\n                        j = 0;\n                        for (int i = 0; i < itemlength; i += 32)\n                        {\n                            IntPtr ptrheader = new IntPtr((long) gc.AddrOfPinnedObject() + currpos);\n                            currpos += 4;\n                            itemheader[j++] = (int) Marshal.PtrToStructure(ptrheader, typeof(int));\n                            for (int count = 0; count < 32; ++count)\n                            {\n                                IntPtr ptr = new IntPtr((long) gc.AddrOfPinnedObject() + currpos);\n                                if (useNeWTileDataFormat)\n                                {\n                                    currpos += sizeof(NewItemTileDataMul);\n                                    NewItemTileDataMul cur =\n                                        (NewItemTileDataMul) Marshal.PtrToStructure(ptr, typeof(NewItemTileDataMul));\n                                    m_ItemData[i + count] = new ItemData(cur);\n                                    m_HeightTable[i + count] = cur.height;\n                                }\n                                else\n                                {\n                                    currpos += sizeof(OldItemTileDataMul);\n                                    OldItemTileDataMul cur =\n                                        (OldItemTileDataMul) Marshal.PtrToStructure(ptr, typeof(OldItemTileDataMul));\n                                    m_ItemData[i + count] = new ItemData(cur);\n                                    m_HeightTable[i + count] = cur.height;\n                                }\n                            }\n                        }\n                    }\n                    finally\n                    {\n                        gc.Free();\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Saves <see cref=\"LandData\"/> and <see cref=\"ItemData\"/> to tiledata.mul\n        /// </summary>\n        /// <param name=\"FileName\"></param>\n        public static void SaveTileData(string FileName)\n        {\n            using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    int j = 0;\n                    bool useNewTileDataFormat = Art.IsUOAHS();\n                    for (int i = 0; i < 0x4000; ++i)\n                    {\n                        if ((i & 0x1F) == 0)\n                            bin.Write(landheader[j++]); //header\n\n                        bin.Write((int) m_LandData[i].Flags);\n                        if (useNewTileDataFormat)\n                            bin.Write((int) m_LandData[i].Unk1);\n\n                        bin.Write(m_LandData[i].TextureID);\n                        byte[] b = new byte[20];\n                        if (m_LandData[i].Name != null)\n                        {\n                            byte[] bb = Encoding.Default.GetBytes(m_LandData[i].Name);\n                            if (bb.Length > 20)\n                                Array.Resize(ref bb, 20);\n                            bb.CopyTo(b, 0);\n                        }\n\n                        bin.Write(b);\n                    }\n\n                    j = 0;\n                    for (int i = 0; i < m_ItemData.Length; ++i)\n                    {\n                        if ((i & 0x1F) == 0)\n                            bin.Write(itemheader[j++]); // header\n\n                        bin.Write((int) m_ItemData[i].Flags);\n                        if (useNewTileDataFormat)\n                            bin.Write((int) m_ItemData[i].Unk1);\n\n                        bin.Write(m_ItemData[i].Weight);\n                        bin.Write(m_ItemData[i].Quality);\n                        bin.Write(m_ItemData[i].MiscData);\n                        bin.Write(m_ItemData[i].Unk2);\n                        bin.Write(m_ItemData[i].Quantity);\n                        bin.Write(m_ItemData[i].Animation);\n                        bin.Write(m_ItemData[i].Unk3);\n                        bin.Write(m_ItemData[i].Hue);\n                        bin.Write(m_ItemData[i].StackingOffset); //unk4\n                        bin.Write(m_ItemData[i].Value); //unk5\n                        bin.Write(m_ItemData[i].Height);\n                        byte[] b = new byte[20];\n                        if (m_ItemData[i].Name != null)\n                        {\n                            byte[] bb = Encoding.Default.GetBytes(m_ItemData[i].Name);\n                            if (bb.Length > 20)\n                                Array.Resize(ref bb, 20);\n                            bb.CopyTo(b, 0);\n                        }\n\n                        bin.Write(b);\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Exports <see cref=\"ItemData\"/> to csv file\n        /// </summary>\n        /// <param name=\"FileName\"></param>\n        public static void ExportItemDataToCSV(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite),\n                System.Text.Encoding.GetEncoding(1252)))\n            {\n                Tex.Write(\n                    \"ID;Name;Weight/Quantity;Layer/Quality;Gump/AnimID;Height;Hue;Class/Quantity;StackingOffset;MiscData;Unknown1;Unknown2;Unknown3\");\n                Tex.Write(\";Background;Weapon;Transparent;Translucent;Wall;Damage;Impassible;Wet;Unknow1\");\n                Tex.Write(\";Surface;Bridge;Generic;Window;NoShoot;PrefixA;PrefixAn;Internal;Foliage;PartialHue\");\n                Tex.Write(\";Unknow2;Map;Container/Height;Wearable;Lightsource;Animation;HoverOver\");\n                Tex.WriteLine(\";Unknow3;Armor;Roof;Door;StairBack;StairRight\");\n\n                for (int i = 0; i < m_ItemData.Length; ++i)\n                {\n                    ItemData tile = m_ItemData[i];\n                    Tex.Write($\"0x{i:X4}\");\n                    Tex.Write($\";{tile.Name}\");\n                    Tex.Write(\";\" + tile.Weight);\n                    Tex.Write(\";\" + tile.Quality);\n                    Tex.Write($\";0x{tile.Animation:X4}\");\n                    Tex.Write(\";\" + tile.Height);\n                    Tex.Write(\";\" + tile.Hue);\n                    Tex.Write(\";\" + tile.Quantity);\n                    Tex.Write(\";\" + tile.StackingOffset);\n                    Tex.Write(\";\" + tile.MiscData);\n                    Tex.Write(\";\" + tile.Unk1);\n                    Tex.Write(\";\" + tile.Unk2);\n                    Tex.Write(\";\" + tile.Unk3);\n\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Background) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Weapon) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Transparent) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Translucent) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Wall) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Damaging) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Impassable) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Wet) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Unknown1) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Surface) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Bridge) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Generic) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Window) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.NoShoot) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.ArticleA) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.ArticleAn) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Internal) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Foliage) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.PartialHue) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Unknown2) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Map) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Container) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Wearable) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.LightSource) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Animation) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.HoverOver) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Unknown3) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Armor) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Roof) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Door) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.StairBack) != 0) ? \"1\" : \"0\"));\n                    Tex.WriteLine(\";\" + (((tile.Flags & TileFlag.StairRight) != 0) ? \"1\" : \"0\"));\n                }\n            }\n        }\n\n        /// <summary>\n        /// Exports <see cref=\"LandData\"/> to csv file\n        /// </summary>\n        /// <param name=\"FileName\"></param>\n        public static void ExportLandDataToCSV(string FileName)\n        {\n            using (StreamWriter Tex = new StreamWriter(new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite)))\n            {\n                Tex.Write(\"ID;Name;TextureID;HSAUnk1\");\n                Tex.Write(\";Background;Weapon;Transparent;Translucent;Wall;Damage;Impassible;Wet;Unknow1\");\n                Tex.Write(\";Surface;Bridge;Generic;Window;NoShoot;PrefixA;PrefixAn;Internal;Foliage;PartialHue\");\n                Tex.Write(\";Unknow2;Map;Container/Height;Wearable;Lightsource;Animation;HoverOver\");\n                Tex.WriteLine(\";Unknow3;Armor;Roof;Door;StairBack;StairRight\");\n\n                for (int i = 0; i < m_LandData.Length; ++i)\n                {\n                    LandData tile = m_LandData[i];\n                    Tex.Write($\"0x{i:X4}\");\n                    Tex.Write(\";\" + tile.Name);\n                    Tex.Write(\";\" + $\"0x{tile.TextureID:X4}\");\n                    Tex.Write(\";\" + tile.Unk1);\n\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Background) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Weapon) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Transparent) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Translucent) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Wall) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Damaging) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Impassable) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Wet) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Unknown1) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Surface) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Bridge) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Generic) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Window) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.NoShoot) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.ArticleA) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.ArticleAn) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Internal) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Foliage) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.PartialHue) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Unknown2) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Map) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Container) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Wearable) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.LightSource) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Animation) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.HoverOver) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Unknown3) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Armor) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Roof) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.Door) != 0) ? \"1\" : \"0\"));\n                    Tex.Write(\";\" + (((tile.Flags & TileFlag.StairBack) != 0) ? \"1\" : \"0\"));\n                    Tex.WriteLine(\";\" + (((tile.Flags & TileFlag.StairRight) != 0) ? \"1\" : \"0\"));\n                }\n            }\n        }\n\n        public static int ConvertStringToInt(string text)\n        {\n            int result;\n            if (text.Contains(\"0x\"))\n            {\n                string convert = text.Replace(\"0x\", \"\");\n                int.TryParse(convert, System.Globalization.NumberStyles.HexNumber, null, out result);\n            }\n            else\n                int.TryParse(text, System.Globalization.NumberStyles.Integer, null, out result);\n\n            return result;\n        }\n\n        public static void ImportItemDataFromCSV(string FileName)\n        {\n            if (!File.Exists(FileName))\n                return;\n            using (StreamReader sr = new StreamReader(FileName))\n            {\n                string line;\n                while ((line = sr.ReadLine()) != null)\n                {\n                    if ((line = line.Trim()).Length == 0 || line.StartsWith(\"#\"))\n                        continue;\n                    if (line.StartsWith(\"ID;\"))\n                        continue;\n                    try\n                    {\n                        string[] split = line.Split(';');\n                        if (split.Length < 45)\n                            continue;\n\n                        int id = ConvertStringToInt(split[0]);\n                        m_ItemData[id].ReadData(split);\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n        }\n\n        public static void ImportLandDataFromCSV(string FileName)\n        {\n            if (!File.Exists(FileName))\n                return;\n            using (StreamReader sr = new StreamReader(FileName))\n            {\n                string line;\n                while ((line = sr.ReadLine()) != null)\n                {\n                    if ((line = line.Trim()).Length == 0 || line.StartsWith(\"#\"))\n                        continue;\n                    if (line.StartsWith(\"ID;\"))\n                        continue;\n                    try\n                    {\n                        string[] split = line.Split(';');\n                        if (split.Length < 36)\n                            continue;\n\n                        int id = ConvertStringToInt(split[0]);\n                        m_LandData[id].ReadData(split);\n                    }\n                    catch\n                    {\n                    }\n                }\n            }\n        }\n    }\n\n    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public unsafe struct OldLandTileDataMul\n    {\n        public int flags;\n        public short texID;\n        public fixed byte name[20];\n    }\n\n    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public unsafe struct NewLandTileDataMul\n    {\n        public int flags;\n        public int unk1;\n        public short texID;\n        public fixed byte name[20];\n    }\n\n    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public unsafe struct OldItemTileDataMul\n    {\n        public int flags;\n        public byte weight;\n        public byte quality;\n        public short miscdata;\n        public byte unk2;\n        public byte quantity;\n        public short anim;\n        public byte unk3;\n        public byte hue;\n        public byte stackingoffset;\n        public byte value;\n        public byte height;\n        public fixed byte name[20];\n    }\n\n    [StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public unsafe struct NewItemTileDataMul\n    {\n        public int flags;\n        public int unk1;\n        public byte weight;\n        public byte quality;\n        public short miscdata;\n        public byte unk2;\n        public byte quantity;\n        public short anim;\n        public byte unk3;\n        public byte hue;\n        public byte stackingoffset;\n        public byte value;\n        public byte height;\n        public fixed byte name[20];\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/TileList.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.Collections.Generic;\n\nnamespace Ultima\n{\n    public sealed class HuedTileList\n    {\n        private List<HuedTile> m_Tiles;\n\n        public HuedTileList()\n        {\n            m_Tiles = new List<HuedTile>();\n        }\n\n        public int Count\n        {\n            get { return m_Tiles.Count; }\n        }\n\n        public void Add(ushort id, short hue, sbyte z)\n        {\n            m_Tiles.Add(new HuedTile(id, hue, z));\n        }\n\n        public HuedTile[] ToArray()\n        {\n            HuedTile[] tiles = new HuedTile[Count];\n\n            if (m_Tiles.Count > 0)\n                m_Tiles.CopyTo(tiles);\n            m_Tiles.Clear();\n\n            return tiles;\n        }\n    }\n\n    public sealed class TileList\n    {\n        private List<Tile> m_Tiles;\n\n        public TileList()\n        {\n            m_Tiles = new List<Tile>();\n        }\n\n        public int Count\n        {\n            get { return m_Tiles.Count; }\n        }\n\n        public void Add(ushort id, sbyte z)\n        {\n            m_Tiles.Add(new Tile(id, z));\n        }\n\n        public void Add(ushort id, sbyte z, sbyte flag)\n        {\n            m_Tiles.Add(new Tile(id, z, flag));\n        }\n\n        public Tile[] ToArray()\n        {\n            Tile[] tiles = new Tile[Count];\n            if (m_Tiles.Count > 0)\n                m_Tiles.CopyTo(tiles);\n            m_Tiles.Clear();\n\n            return tiles;\n        }\n\n        public Tile Get(int i)\n        {\n            return m_Tiles[i];\n        }\n    }\n\n    public sealed class MTileList\n    {\n        private List<MTile> m_Tiles;\n\n        public MTileList()\n        {\n            m_Tiles = new List<MTile>();\n        }\n\n        public int Count\n        {\n            get { return m_Tiles.Count; }\n        }\n\n        public void Add(ushort id, sbyte z)\n        {\n            m_Tiles.Add(new MTile(id, z));\n        }\n\n        public void Add(ushort id, sbyte z, sbyte flag)\n        {\n            m_Tiles.Add(new MTile(id, z, flag));\n        }\n\n        public void Add(ushort id, sbyte z, sbyte flag, int unk1)\n        {\n            m_Tiles.Add(new MTile(id, z, flag, unk1));\n        }\n\n        public MTile[] ToArray()\n        {\n            MTile[] tiles = new MTile[Count];\n\n            if (m_Tiles.Count > 0)\n                m_Tiles.CopyTo(tiles);\n            m_Tiles.Clear();\n\n            return tiles;\n        }\n\n        public MTile Get(int i)\n        {\n            return m_Tiles[i];\n        }\n\n        public void Set(int i, ushort id, sbyte z)\n        {\n            if (i < Count)\n                m_Tiles[i].Set(id, z);\n        }\n\n        public void Set(int i, ushort id, sbyte z, sbyte flag)\n        {\n            if (i < Count)\n                m_Tiles[i].Set(id, z, flag);\n        }\n\n        public void Set(int i, ushort id, sbyte z, sbyte flag, int unk1)\n        {\n            if (i < Count)\n                m_Tiles[i].Set(id, z, flag, unk1);\n        }\n\n        public void Remove(int i)\n        {\n            if (i < Count)\n                m_Tiles.RemoveAt(i);\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/TileMatrix.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\nnamespace Ultima\n{\n    public sealed class TileMatrix\n    {\n        private HuedTile[][][][][] m_StaticTiles;\n        private Tile[][][] m_LandTiles;\n        private bool[][] m_RemovedStaticBlock;\n        private List<StaticTile>[][] m_StaticTiles_ToAdd;\n\n        public static Tile[] InvalidLandBlock { get; private set; }\n        public static HuedTile[][][] EmptyStaticBlock { get; private set; }\n\n        private FileStream m_Map;\n        private BinaryReader m_UOPReader;\n        private FileStream m_Statics;\n        private Entry3D[] m_StaticIndex;\n\n        public Entry3D[] StaticIndex\n        {\n            get\n            {\n                if (!StaticIndexInit) InitStatics();\n                return m_StaticIndex;\n            }\n        }\n\n        public bool StaticIndexInit;\n\n        public TileMatrixPatch Patch { get; private set; }\n\n        public int BlockWidth { get; private set; }\n\n        public int BlockHeight { get; private set; }\n\n        public int Width { get; private set; }\n\n        public int Height { get; private set; }\n\n        private string mapPath;\n        private string indexPath;\n        private string staticsPath;\n\n        public void CloseStreams()\n        {\n            if (m_Map != null)\n                m_Map.Close();\n\n            if (m_UOPReader != null)\n                m_UOPReader.Close();\n\n            if (m_Statics != null)\n                m_Statics.Close();\n        }\n\n        public TileMatrix(int fileIndex, int mapID, int width, int height, string path)\n        {\n            Width = width;\n            Height = height;\n            BlockWidth = width >> 3;\n            BlockHeight = height >> 3;\n\n\n            if (path == null)\n            {\n                mapPath = Files.GetFilePath(\"map{0}.mul\", fileIndex);\n\n                if (String.IsNullOrEmpty(mapPath) || !File.Exists(mapPath))\n                    mapPath = Files.GetFilePath(\"map{0}LegacyMUL.uop\", fileIndex);\n\n                if (mapPath != null && mapPath.EndsWith(\".uop\"))\n                    IsUOPFormat = true;\n\n                // For shards that use Fel and Tram before the split\n                if (String.IsNullOrEmpty(mapPath) || (!File.Exists(mapPath) && fileIndex == 1))\n                {\n                    fileIndex = 0;\n                    mapPath = Files.GetFilePath(\"map{0}.mul\", fileIndex);\n                }\n            }\n            else\n            {\n                mapPath = Path.Combine(path, $\"map{fileIndex}.mul\");\n\n                if (!File.Exists(mapPath))\n                    mapPath = Path.Combine(path, $\"map{fileIndex}LegacyMUL.uop\");\n\n                if (!File.Exists(mapPath))\n                    mapPath = null;\n                else if (mapPath != null && mapPath.EndsWith(\".uop\"))\n                    IsUOPFormat = true;\n            }\n\n            if (mapPath != null && fileIndex == 0)\n            {\n                FileInfo fi = new FileInfo(mapPath);\n                if (fi.Length < 89915392)\n                {\n                    // Old map size.\n                    Width = 6144;\n                }\n            }\n\n            if (path == null)\n                indexPath = Files.GetFilePath(\"staidx{0}.mul\", fileIndex);\n            else\n            {\n                indexPath = Path.Combine(path, $\"staidx{fileIndex}.mul\");\n                if (!File.Exists(indexPath))\n                    indexPath = null;\n            }\n\n            if (path == null)\n                staticsPath = Files.GetFilePath(\"statics{0}.mul\", fileIndex);\n            else\n            {\n                staticsPath = Path.Combine(path, $\"statics{fileIndex}.mul\");\n                if (!File.Exists(staticsPath))\n                    staticsPath = null;\n            }\n\n            EmptyStaticBlock = new HuedTile[8][][];\n\n            for (int i = 0; i < 8; ++i)\n            {\n                EmptyStaticBlock[i] = new HuedTile[8][];\n\n                for (int j = 0; j < 8; ++j)\n                {\n                    EmptyStaticBlock[i][j] = new HuedTile[0];\n                }\n            }\n\n            InvalidLandBlock = new Tile[196];\n\n            m_LandTiles = new Tile[BlockWidth][][];\n            m_StaticTiles = new HuedTile[BlockWidth][][][][];\n\n            Patch = new TileMatrixPatch(this, mapID, path);\n        }\n\n\n        public void SetStaticBlock(int x, int y, HuedTile[][][] value)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return;\n\n            if (m_StaticTiles[x] == null)\n                m_StaticTiles[x] = new HuedTile[BlockHeight][][][];\n\n            m_StaticTiles[x][y] = value;\n        }\n\n        public HuedTile[][][] GetStaticBlock(int x, int y)\n        {\n            return GetStaticBlock(x, y, true);\n        }\n\n        public HuedTile[][][] GetStaticBlock(int x, int y, bool patch)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return EmptyStaticBlock;\n\n            if (m_StaticTiles[x] == null)\n                m_StaticTiles[x] = new HuedTile[BlockHeight][][][];\n\n            HuedTile[][][] tiles = m_StaticTiles[x][y];\n\n            if (tiles == null)\n                tiles = m_StaticTiles[x][y] = ReadStaticBlock(x, y);\n\n            if ((Map.UseDiff) && (patch))\n            {\n                if (Patch.StaticBlocksCount > 0)\n                {\n                    if (Patch.StaticBlocks[x] != null)\n                    {\n                        if (Patch.StaticBlocks[x][y] != null)\n                            tiles = Patch.StaticBlocks[x][y];\n                    }\n                }\n            }\n\n            return tiles;\n        }\n\n        public HuedTile[] GetStaticTiles(int x, int y, bool patch)\n        {\n            return GetStaticBlock(x >> 3, y >> 3, patch)[x & 0x7][y & 0x7];\n        }\n\n        public HuedTile[] GetStaticTiles(int x, int y)\n        {\n            return GetStaticBlock(x >> 3, y >> 3)[x & 0x7][y & 0x7];\n        }\n\n        public void SetLandBlock(int x, int y, Tile[] value)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return;\n\n            if (m_LandTiles[x] == null)\n                m_LandTiles[x] = new Tile[BlockHeight][];\n\n            m_LandTiles[x][y] = value;\n        }\n\n        public Tile[] GetLandBlock(int x, int y)\n        {\n            return GetLandBlock(x, y, true);\n        }\n\n        public Tile[] GetLandBlock(int x, int y, bool patch)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return InvalidLandBlock;\n\n            if (m_LandTiles[x] == null)\n                m_LandTiles[x] = new Tile[BlockHeight][];\n\n            Tile[] tiles = m_LandTiles[x][y];\n\n            if (tiles == null)\n                tiles = m_LandTiles[x][y] = ReadLandBlock(x, y);\n\n            if ((Map.UseDiff) && (patch))\n            {\n                if (Patch.LandBlocksCount > 0)\n                {\n                    if (Patch.LandBlocks[x] != null)\n                    {\n                        if (Patch.LandBlocks[x][y] != null)\n                            tiles = Patch.LandBlocks[x][y];\n                    }\n                }\n            }\n\n            return tiles;\n        }\n\n        public Tile GetLandTile(int x, int y, bool patch)\n        {\n            return GetLandBlock(x >> 3, y >> 3, patch)[((y & 0x7) << 3) + (x & 0x7)];\n        }\n\n        public Tile GetLandTile(int x, int y)\n        {\n            return GetLandBlock(x >> 3, y >> 3)[((y & 0x7) << 3) + (x & 0x7)];\n        }\n\n\n        private unsafe void InitStatics()\n        {\n            m_StaticIndex = new Entry3D[BlockHeight * BlockWidth];\n            if (indexPath == null)\n                return;\n            using (FileStream index = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n            {\n                m_Statics = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n                int count = (int) (index.Length / 12);\n                GCHandle gc = GCHandle.Alloc(m_StaticIndex, GCHandleType.Pinned);\n                byte[] buffer = new byte[index.Length];\n                index.Read(buffer, 0, (int) index.Length);\n                Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(),\n                    (int) Math.Min(index.Length, BlockHeight * BlockWidth * 12));\n                gc.Free();\n                for (int i = (int) Math.Min(index.Length, BlockHeight * BlockWidth); i < BlockHeight * BlockWidth; ++i)\n                {\n                    m_StaticIndex[i].lookup = -1;\n                    m_StaticIndex[i].length = -1;\n                    m_StaticIndex[i].extra = -1;\n                }\n\n                StaticIndexInit = true;\n            }\n        }\n\n        private static HuedTileList[][] m_Lists;\n        private static byte[] m_Buffer;\n\n        private unsafe HuedTile[][][] ReadStaticBlock(int x, int y)\n        {\n            try\n            {\n                if (!StaticIndexInit)\n                    InitStatics();\n                if (m_Statics == null || !m_Statics.CanRead || !m_Statics.CanSeek)\n                {\n                    if (staticsPath == null)\n                        m_Statics = null;\n                    else\n                        m_Statics = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n                }\n\n                if (m_Statics == null)\n                    return EmptyStaticBlock;\n\n                int lookup = m_StaticIndex[(x * BlockHeight) + y].lookup;\n                int length = m_StaticIndex[(x * BlockHeight) + y].length;\n\n                if (lookup < 0 || length <= 0)\n                    return EmptyStaticBlock;\n                else\n                {\n                    int count = length / 7;\n\n                    m_Statics.Seek(lookup, SeekOrigin.Begin);\n\n                    if (m_Buffer == null || m_Buffer.Length < length)\n                        m_Buffer = new byte[length];\n\n                    GCHandle gc = GCHandle.Alloc(m_Buffer, GCHandleType.Pinned);\n                    try\n                    {\n                        m_Statics.Read(m_Buffer, 0, length);\n\n                        if (m_Lists == null)\n                        {\n                            m_Lists = new HuedTileList[8][];\n\n                            for (int i = 0; i < 8; ++i)\n                            {\n                                m_Lists[i] = new HuedTileList[8];\n\n                                for (int j = 0; j < 8; ++j)\n                                    m_Lists[i][j] = new HuedTileList();\n                            }\n                        }\n\n                        HuedTileList[][] lists = m_Lists;\n\n                        for (int i = 0; i < count; ++i)\n                        {\n                            IntPtr ptr = new IntPtr((long) gc.AddrOfPinnedObject() + i * sizeof(StaticTile));\n                            StaticTile cur = (StaticTile) Marshal.PtrToStructure(ptr, typeof(StaticTile));\n                            lists[cur.m_X & 0x7][cur.m_Y & 0x7].Add(Art.GetLegalItemID(cur.m_ID), cur.m_Hue, cur.m_Z);\n                        }\n\n                        HuedTile[][][] tiles = new HuedTile[8][][];\n\n                        for (int i = 0; i < 8; ++i)\n                        {\n                            tiles[i] = new HuedTile[8][];\n\n                            for (int j = 0; j < 8; ++j)\n                                tiles[i][j] = lists[i][j].ToArray();\n                        }\n\n                        return tiles;\n                    }\n                    finally\n                    {\n                        gc.Free();\n                    }\n                }\n            }\n            finally\n            {\n                //if (m_Statics != null)\n                //    m_Statics.Close();\n            }\n        }\n\n        /* UOP map files support code, written by Wyatt (c) www.ruosi.org\n         * It's not possible if some entry has unknown hash. Throwed exception\n         * means that EA changed maps UOPs again.\n         */\n\n        #region UOP\n\n        public bool IsUOPFormat { get; set; }\n        public bool IsUOPAlreadyRead { get; set; }\n\n        private struct UOPFile\n        {\n            public long Offset;\n            public int Length;\n\n            public UOPFile(long offset, int length)\n            {\n                Offset = offset;\n                Length = length;\n            }\n        }\n\n        private UOPFile[] UOPFiles { get; set; }\n\n        private long UOPLength\n        {\n            get { return m_Map.Length; }\n        }\n\n        private void ReadUOPFiles(string pattern)\n        {\n            m_UOPReader = new BinaryReader(m_Map);\n\n            m_UOPReader.BaseStream.Seek(0, SeekOrigin.Begin);\n\n            if (m_UOPReader.ReadInt32() != 0x50594D)\n                throw new ArgumentException(\"Bad UOP file.\");\n\n            m_UOPReader.ReadInt64(); // version + signature\n            long nextBlock = m_UOPReader.ReadInt64();\n            m_UOPReader.ReadInt32(); // block capacity\n            int count = m_UOPReader.ReadInt32();\n\n            UOPFiles = new UOPFile[count];\n\n            Dictionary<ulong, int> hashes = new Dictionary<ulong, int>();\n\n            for (int i = 0; i < count; i++)\n            {\n                string file = $\"build/{pattern}/{i:D8}.dat\";\n                ulong hash = FileIndex.HashFileName(file);\n\n                if (!hashes.ContainsKey(hash))\n                    hashes.Add(hash, i);\n            }\n\n            m_UOPReader.BaseStream.Seek(nextBlock, SeekOrigin.Begin);\n\n            do\n            {\n                int filesCount = m_UOPReader.ReadInt32();\n                nextBlock = m_UOPReader.ReadInt64();\n\n                for (int i = 0; i < filesCount; i++)\n                {\n                    long offset = m_UOPReader.ReadInt64();\n                    int headerLength = m_UOPReader.ReadInt32();\n                    int compressedLength = m_UOPReader.ReadInt32();\n                    int decompressedLength = m_UOPReader.ReadInt32();\n                    ulong hash = m_UOPReader.ReadUInt64();\n                    m_UOPReader.ReadUInt32(); // Adler32\n                    short flag = m_UOPReader.ReadInt16();\n\n                    int length = flag == 1 ? compressedLength : decompressedLength;\n\n                    if (offset == 0)\n                        continue;\n\n                    int idx;\n                    if (hashes.TryGetValue(hash, out idx))\n                    {\n                        if (idx < 0 || idx > UOPFiles.Length)\n                            throw new IndexOutOfRangeException(\n                                \"hashes dictionary and files collection have different count of entries!\");\n\n                        UOPFiles[idx] = new UOPFile(offset + headerLength, length);\n                    }\n                    else\n                    {\n                        throw new ArgumentException(\n                            $\"File with hash 0x{hash:X8} was not found in hashes dictionary! EA Mythic changed UOP format!\");\n                    }\n                }\n            } while (m_UOPReader.BaseStream.Seek(nextBlock, SeekOrigin.Begin) != 0);\n        }\n\n        private long CalculateOffsetFromUOP(long offset)\n        {\n            long pos = 0;\n\n            foreach (UOPFile t in UOPFiles)\n            {\n                long currPos = pos + t.Length;\n\n                if (offset < currPos)\n                    return t.Offset + (offset - pos);\n\n                pos = currPos;\n            }\n\n            return UOPLength;\n        }\n\n        #endregion\n\n        private unsafe Tile[] ReadLandBlock(int x, int y)\n        {\n            if (m_Map == null || !m_Map.CanRead || !m_Map.CanSeek)\n            {\n                if (mapPath == null)\n                    m_Map = null;\n                else\n                    m_Map = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.Read);\n\n                if (IsUOPFormat && mapPath != null && !IsUOPAlreadyRead)\n                {\n                    FileInfo fi = new FileInfo(mapPath);\n                    string uopPattern = fi.Name.Replace(fi.Extension, \"\").ToLowerInvariant();\n\n                    ReadUOPFiles(uopPattern);\n                    IsUOPAlreadyRead = true;\n                }\n            }\n\n            Tile[] tiles = new Tile[64];\n            if (m_Map != null)\n            {\n                long offset = ((x * BlockHeight) + y) * 196 + 4;\n\n                if (IsUOPFormat)\n                    offset = CalculateOffsetFromUOP(offset);\n\n                m_Map.Seek(offset, SeekOrigin.Begin);\n\n                GCHandle gc = GCHandle.Alloc(tiles, GCHandleType.Pinned);\n                try\n                {\n                    if (m_Buffer == null || m_Buffer.Length < 192)\n                        m_Buffer = new byte[192];\n\n                    m_Map.Read(m_Buffer, 0, 192);\n\n                    Marshal.Copy(m_Buffer, 0, gc.AddrOfPinnedObject(), 192);\n                }\n                finally\n                {\n                    gc.Free();\n                }\n\n                //m_Map.Close();\n            }\n\n            return tiles;\n        }\n\n        public void RemoveStaticBlock(int blockx, int blocky)\n        {\n            if (m_RemovedStaticBlock == null)\n                m_RemovedStaticBlock = new bool[BlockWidth][];\n            if (m_RemovedStaticBlock[blockx] == null)\n                m_RemovedStaticBlock[blockx] = new bool[BlockHeight];\n            m_RemovedStaticBlock[blockx][blocky] = true;\n            if (m_StaticTiles[blockx] == null)\n                m_StaticTiles[blockx] = new HuedTile[BlockHeight][][][];\n            m_StaticTiles[blockx][blocky] = EmptyStaticBlock;\n        }\n\n        public bool IsStaticBlockRemoved(int blockx, int blocky)\n        {\n            if (m_RemovedStaticBlock == null)\n                return false;\n            if (m_RemovedStaticBlock[blockx] == null)\n                return false;\n            return m_RemovedStaticBlock[blockx][blocky];\n        }\n\n        public bool PendingStatic(int blockx, int blocky)\n        {\n            if (m_StaticTiles_ToAdd == null)\n                return false;\n            if (m_StaticTiles_ToAdd[blocky] == null)\n                return false;\n            if (m_StaticTiles_ToAdd[blocky][blockx] == null)\n                return false;\n            return true;\n        }\n\n        public void AddPendingStatic(int blockx, int blocky, StaticTile toadd)\n        {\n            if (m_StaticTiles_ToAdd == null)\n                m_StaticTiles_ToAdd = new List<StaticTile>[BlockHeight][];\n            if (m_StaticTiles_ToAdd[blocky] == null)\n                m_StaticTiles_ToAdd[blocky] = new List<StaticTile>[BlockWidth];\n            if (m_StaticTiles_ToAdd[blocky][blockx] == null)\n                m_StaticTiles_ToAdd[blocky][blockx] = new List<StaticTile>();\n            m_StaticTiles_ToAdd[blocky][blockx].Add(toadd);\n        }\n\n        public StaticTile[] GetPendingStatics(int blockx, int blocky)\n        {\n            if (m_StaticTiles_ToAdd == null)\n                return null;\n            if (m_StaticTiles_ToAdd[blocky] == null)\n                return null;\n            if (m_StaticTiles_ToAdd[blocky][blockx] == null)\n                return null;\n\n            return m_StaticTiles_ToAdd[blocky][blockx].ToArray();\n        }\n\n        public void Dispose()\n        {\n            if (m_Map != null)\n                m_Map.Close();\n\n            if (m_UOPReader != null)\n                m_UOPReader.Close();\n\n            if (m_Statics != null)\n                m_Statics.Close();\n        }\n    }\n\n    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public struct StaticTile\n    {\n        public ushort m_ID;\n        public byte m_X;\n        public byte m_Y;\n        public sbyte m_Z;\n        public short m_Hue;\n    }\n\n    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public struct HuedTile\n    {\n        internal sbyte m_Z;\n        internal ushort m_ID;\n        internal int m_Hue;\n\n        public ushort ID\n        {\n            get { return m_ID; }\n            set { m_ID = value; }\n        }\n\n        public int Hue\n        {\n            get { return m_Hue; }\n            set { m_Hue = value; }\n        }\n\n        public int Z\n        {\n            get { return m_Z; }\n            set { m_Z = (sbyte) value; }\n        }\n\n        public HuedTile(ushort id, short hue, sbyte z)\n        {\n            m_ID = id;\n            m_Hue = hue;\n            m_Z = z;\n        }\n\n        public void Set(ushort id, short hue, sbyte z)\n        {\n            m_ID = id;\n            m_Hue = hue;\n            m_Z = z;\n        }\n    }\n\n    public struct MTile : IComparable\n    {\n        internal ushort m_ID;\n        internal sbyte m_Z;\n        internal sbyte m_Flag;\n        internal int m_Unk1;\n        internal int m_Solver;\n\n        public ushort ID\n        {\n            get { return m_ID; }\n        }\n\n        public int Z\n        {\n            get { return m_Z; }\n            set { m_Z = (sbyte) value; }\n        }\n\n        public int Flag\n        {\n            get { return m_Flag; }\n            set { m_Flag = (sbyte) value; }\n        }\n\n        public int Unk1\n        {\n            get { return m_Unk1; }\n            set { m_Unk1 = value; }\n        }\n\n        public int Solver\n        {\n            get { return m_Solver; }\n            set { m_Solver = value; }\n        }\n\n        public MTile(ushort id, sbyte z)\n        {\n            m_ID = Art.GetLegalItemID(id);\n            m_Z = z;\n            m_Flag = 1;\n            m_Solver = 0;\n            m_Unk1 = 0;\n        }\n\n        public MTile(ushort id, sbyte z, sbyte flag)\n        {\n            m_ID = Art.GetLegalItemID(id);\n            m_Z = z;\n            m_Flag = flag;\n            m_Solver = 0;\n            m_Unk1 = 0;\n        }\n\n        public MTile(ushort id, sbyte z, sbyte flag, int unk1)\n        {\n            m_ID = Art.GetLegalItemID(id);\n            m_Z = z;\n            m_Flag = flag;\n            m_Solver = 0;\n            m_Unk1 = unk1;\n        }\n\n        public void Set(ushort id, sbyte z)\n        {\n            m_ID = Art.GetLegalItemID(id);\n            m_Z = z;\n        }\n\n        public void Set(ushort id, sbyte z, sbyte flag)\n        {\n            m_ID = Art.GetLegalItemID(id);\n            m_Z = z;\n            m_Flag = flag;\n        }\n\n        public void Set(ushort id, sbyte z, sbyte flag, int unk1)\n        {\n            m_ID = Art.GetLegalItemID(id);\n            m_Z = z;\n            m_Flag = flag;\n            m_Unk1 = unk1;\n        }\n\n        public int CompareTo(object x)\n        {\n            if (x == null)\n                return 1;\n\n            if (!(x is MTile))\n                throw new ArgumentNullException();\n\n            MTile a = (MTile) x;\n\n            ItemData ourData = TileData.ItemTable[m_ID];\n            ItemData theirData = TileData.ItemTable[a.ID];\n\n            int ourTreshold = 0;\n            if (ourData.Height > 0)\n                ++ourTreshold;\n            if (!ourData.Background)\n                ++ourTreshold;\n            int ourZ = Z;\n            int theirTreshold = 0;\n            if (theirData.Height > 0)\n                ++theirTreshold;\n            if (!theirData.Background)\n                ++theirTreshold;\n            int theirZ = a.Z;\n\n            ourZ += ourTreshold;\n            theirZ += theirTreshold;\n            int res = ourZ - theirZ;\n            if (res == 0)\n                res = ourTreshold - theirTreshold;\n            if (res == 0)\n                res = m_Solver - a.Solver;\n            return res;\n        }\n    }\n\n    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]\n    public struct Tile : IComparable\n    {\n        internal ushort m_ID;\n        internal sbyte m_Z;\n\n        public ushort ID\n        {\n            get { return m_ID; }\n        }\n\n        public int Z\n        {\n            get { return m_Z; }\n            set { m_Z = (sbyte) value; }\n        }\n\n        public Tile(ushort id, sbyte z)\n        {\n            m_ID = id;\n            m_Z = z;\n        }\n\n        public Tile(ushort id, sbyte z, sbyte flag)\n        {\n            m_ID = id;\n            m_Z = z;\n        }\n\n        public void Set(ushort id, sbyte z)\n        {\n            m_ID = id;\n            m_Z = z;\n        }\n\n        public void Set(ushort id, sbyte z, sbyte flag)\n        {\n            m_ID = id;\n            m_Z = z;\n        }\n\n        public int CompareTo(object x)\n        {\n            if (x == null)\n                return 1;\n\n            if (!(x is Tile))\n                throw new ArgumentNullException();\n\n            Tile a = (Tile) x;\n\n            if (m_Z > a.m_Z)\n                return 1;\n            else if (a.m_Z > m_Z)\n                return -1;\n\n            ItemData ourData = TileData.ItemTable[m_ID];\n            ItemData theirData = TileData.ItemTable[a.m_ID];\n\n            if (ourData.Height > theirData.Height)\n                return 1;\n            else if (theirData.Height > ourData.Height)\n                return -1;\n\n            if (ourData.Background && !theirData.Background)\n                return -1;\n            else if (theirData.Background && !ourData.Background)\n                return 1;\n\n            return 0;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/TileMatrixPatch.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\n\nnamespace Ultima\n{\n    public sealed class TileMatrixPatch\n    {\n        public int LandBlocksCount { get; private set; }\n        public int StaticBlocksCount { get; private set; }\n\n        public Tile[][][] LandBlocks { get; private set; }\n        public HuedTile[][][][][] StaticBlocks { get; private set; }\n\n        private int BlockWidth;\n        private int BlockHeight;\n\n        private static byte[] m_Buffer;\n        private static StaticTile[] m_TileBuffer = new StaticTile[128];\n\n        public bool IsLandBlockPatched(int x, int y)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return false;\n            if (LandBlocks[x] == null)\n                return false;\n            if (LandBlocks[x][y] == null)\n                return false;\n            return true;\n        }\n\n        public Tile[] GetLandBlock(int x, int y)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return TileMatrix.InvalidLandBlock;\n            if (LandBlocks[x] == null)\n                return TileMatrix.InvalidLandBlock;\n            return LandBlocks[x][y];\n        }\n\n        public Tile GetLandTile(int x, int y)\n        {\n            return GetLandBlock(x >> 3, y >> 3)[((y & 0x7) << 3) + (x & 0x7)];\n        }\n\n        public bool IsStaticBlockPatched(int x, int y)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return false;\n            if (StaticBlocks[x] == null)\n                return false;\n            if (StaticBlocks[x][y] == null)\n                return false;\n            return true;\n        }\n\n        public HuedTile[][][] GetStaticBlock(int x, int y)\n        {\n            if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)\n                return TileMatrix.EmptyStaticBlock;\n            if (StaticBlocks[x] == null)\n                return TileMatrix.EmptyStaticBlock;\n            return StaticBlocks[x][y];\n        }\n\n        public HuedTile[] GetStaticTiles(int x, int y)\n        {\n            return GetStaticBlock(x >> 3, y >> 3)[x & 0x7][y & 0x7];\n        }\n\n        public TileMatrixPatch(TileMatrix matrix, int index, string path)\n        {\n            BlockWidth = matrix.BlockWidth;\n            BlockHeight = matrix.BlockWidth;\n\n            LandBlocksCount = StaticBlocksCount = 0;\n            string mapDataPath, mapIndexPath;\n            if (path == null)\n            {\n                mapDataPath = Files.GetFilePath(\"mapdif{0}.mul\", index);\n                mapIndexPath = Files.GetFilePath(\"mapdifl{0}.mul\", index);\n            }\n            else\n            {\n                mapDataPath = Path.Combine(path, $\"mapdif{index}.mul\");\n                if (!File.Exists(mapDataPath))\n                    mapDataPath = null;\n                mapIndexPath = Path.Combine(path, $\"mapdifl{index}.mul\");\n                if (!File.Exists(mapIndexPath))\n                    mapIndexPath = null;\n            }\n\n            if (mapDataPath != null && mapIndexPath != null)\n            {\n                LandBlocks = new Tile[matrix.BlockWidth][][];\n                LandBlocksCount = PatchLand(matrix, mapDataPath, mapIndexPath);\n            }\n\n            string staDataPath, staIndexPath, staLookupPath;\n            if (path == null)\n            {\n                staDataPath = Files.GetFilePath(\"stadif{0}.mul\", index);\n                staIndexPath = Files.GetFilePath(\"stadifl{0}.mul\", index);\n                staLookupPath = Files.GetFilePath(\"stadifi{0}.mul\", index);\n            }\n            else\n            {\n                staDataPath = Path.Combine(path, $\"stadif{index}.mul\");\n                if (!File.Exists(staDataPath))\n                    staDataPath = null;\n                staIndexPath = Path.Combine(path, $\"stadifl{index}.mul\");\n                if (!File.Exists(staIndexPath))\n                    staIndexPath = null;\n                staLookupPath = Path.Combine(path, $\"stadifi{index}.mul\");\n                if (!File.Exists(staLookupPath))\n                    staLookupPath = null;\n            }\n\n            if (staDataPath != null && staIndexPath != null && staLookupPath != null)\n            {\n                StaticBlocks = new HuedTile[matrix.BlockWidth][][][][];\n                StaticBlocksCount = PatchStatics(matrix, staDataPath, staIndexPath, staLookupPath);\n            }\n        }\n\n        private unsafe int PatchLand(TileMatrix matrix, string dataPath, string indexPath)\n        {\n            using (FileStream fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read),\n                fsIndex = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n            {\n                using (BinaryReader indexReader = new BinaryReader(fsIndex))\n                {\n                    int count = (int) (indexReader.BaseStream.Length / 4);\n\n                    for (int i = 0; i < count; ++i)\n                    {\n                        int blockID = indexReader.ReadInt32();\n                        int x = blockID / matrix.BlockHeight;\n                        int y = blockID % matrix.BlockHeight;\n\n                        fsData.Seek(4, SeekOrigin.Current);\n\n                        Tile[] tiles = new Tile[64];\n\n                        GCHandle gc = GCHandle.Alloc(tiles, GCHandleType.Pinned);\n                        try\n                        {\n                            if (m_Buffer == null || m_Buffer.Length < 192)\n                                m_Buffer = new byte[192];\n\n                            fsData.Read(m_Buffer, 0, 192);\n\n                            Marshal.Copy(m_Buffer, 0, gc.AddrOfPinnedObject(), 192);\n                        }\n                        finally\n                        {\n                            gc.Free();\n                        }\n\n                        if (LandBlocks[x] == null)\n                            LandBlocks[x] = new Tile[matrix.BlockHeight][];\n                        LandBlocks[x][y] = tiles;\n                    }\n\n                    return count;\n                }\n            }\n        }\n\n        private unsafe int PatchStatics(TileMatrix matrix, string dataPath, string indexPath, string lookupPath)\n        {\n            using (FileStream fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read),\n                fsIndex = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read),\n                fsLookup = new FileStream(lookupPath, FileMode.Open, FileAccess.Read, FileShare.Read))\n            {\n                using (BinaryReader indexReader = new BinaryReader(fsIndex),\n                    lookupReader = new BinaryReader(fsLookup))\n                {\n                    int count = Math.Min((int) (indexReader.BaseStream.Length / 4),\n                        (int) (lookupReader.BaseStream.Length / 12));\n\n                    HuedTileList[][] lists = new HuedTileList[8][];\n\n                    for (int x = 0; x < 8; ++x)\n                    {\n                        lists[x] = new HuedTileList[8];\n\n                        for (int y = 0; y < 8; ++y)\n                            lists[x][y] = new HuedTileList();\n                    }\n\n                    for (int i = 0; i < count; ++i)\n                    {\n                        int blockID = indexReader.ReadInt32();\n                        int blockX = blockID / matrix.BlockHeight;\n                        int blockY = blockID % matrix.BlockHeight;\n\n                        int offset = lookupReader.ReadInt32();\n                        int length = lookupReader.ReadInt32();\n                        lookupReader.ReadInt32(); // Extra\n\n                        if (offset < 0 || length <= 0)\n                        {\n                            if (StaticBlocks[blockX] == null)\n                                StaticBlocks[blockX] = new HuedTile[matrix.BlockHeight][][][];\n\n                            StaticBlocks[blockX][blockY] = TileMatrix.EmptyStaticBlock;\n                            continue;\n                        }\n\n                        fsData.Seek(offset, SeekOrigin.Begin);\n\n                        int tileCount = length / 7;\n\n                        if (m_TileBuffer.Length < tileCount)\n                            m_TileBuffer = new StaticTile[tileCount];\n\n                        StaticTile[] staTiles = m_TileBuffer;\n\n                        GCHandle gc = GCHandle.Alloc(staTiles, GCHandleType.Pinned);\n                        try\n                        {\n                            if (m_Buffer == null || m_Buffer.Length < length)\n                                m_Buffer = new byte[length];\n\n                            fsData.Read(m_Buffer, 0, length);\n\n                            Marshal.Copy(m_Buffer, 0, gc.AddrOfPinnedObject(), length);\n\n                            for (int j = 0; j < tileCount; ++j)\n                            {\n                                StaticTile cur = staTiles[j];\n                                lists[cur.m_X & 0x7][cur.m_Y & 0x7]\n                                    .Add(Art.GetLegalItemID(cur.m_ID), cur.m_Hue, cur.m_Z);\n                            }\n\n                            HuedTile[][][] tiles = new HuedTile[8][][];\n\n                            for (int x = 0; x < 8; ++x)\n                            {\n                                tiles[x] = new HuedTile[8][];\n\n                                for (int y = 0; y < 8; ++y)\n                                    tiles[x][y] = lists[x][y].ToArray();\n                            }\n\n                            if (StaticBlocks[blockX] == null)\n                                StaticBlocks[blockX] = new HuedTile[matrix.BlockHeight][][][];\n\n                            StaticBlocks[blockX][blockY] = tiles;\n                        }\n                        finally\n                        {\n                            gc.Free();\n                        }\n                    }\n\n                    return count;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/UnicodeFont.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\n\nnamespace Ultima\n{\n    public sealed class UnicodeFont\n    {\n        public UnicodeChar[] Chars { get; set; }\n\n        public UnicodeFont()\n        {\n            Chars = new UnicodeChar[0x10000];\n        }\n\n        /// <summary>\n        /// Returns width of text\n        /// </summary>\n        /// <param name=\"text\"></param>\n        /// <returns></returns>\n        public int GetWidth(string text)\n        {\n            if (text == null || text.Length == 0)\n                return 0;\n            int width = 0;\n            for (int i = 0; i < text.Length; ++i)\n            {\n                int c = (int) text[i] % 0x10000;\n                width += Chars[c].Width;\n                width += Chars[c].XOffset;\n            }\n\n            return width;\n        }\n\n        /// <summary>\n        /// Returns max height of text\n        /// </summary>\n        /// <param name=\"text\"></param>\n        /// <returns></returns>\n        public int GetHeight(string text)\n        {\n            if (text == null || text.Length == 0)\n                return 0;\n            int height = 0;\n            for (int i = 0; i < text.Length; ++i)\n            {\n                int c = (int) text[i] % 0x10000;\n                height = Math.Max(height, Chars[c].Height + Chars[c].YOffset);\n            }\n\n            return height;\n        }\n    }\n\n    public sealed class UnicodeChar\n    {\n        public byte[] Bytes { get; set; }\n        public sbyte XOffset { get; set; }\n        public sbyte YOffset { get; set; }\n        public int Height { get; set; }\n        public int Width { get; set; }\n\n        public UnicodeChar()\n        {\n        }\n\n        /// <summary>\n        /// Gets Bitmap of Char\n        /// </summary>\n        /// <returns></returns>\n        public Bitmap GetImage()\n        {\n            return GetImage(false);\n        }\n\n        /// <summary>\n        /// Gets Bitmap of Char with Background -1\n        /// </summary>\n        /// <param name=\"fill\"></param>\n        /// <returns></returns>\n        public unsafe Bitmap GetImage(bool fill)\n        {\n            if ((Width == 0) || (Height == 0))\n                return null;\n            Bitmap bmp = new Bitmap(Width, Height, PixelFormat.Format16bppArgb1555);\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly,\n                PixelFormat.Format16bppArgb1555);\n            ushort* line = (ushort*) bd.Scan0;\n            int delta = bd.Stride >> 1;\n            for (int y = 0; y < Height; ++y, line += delta)\n            {\n                ushort* cur = line;\n                for (int x = 0; x < Width; ++x)\n                {\n                    if (IsPixelSet(Bytes, Width, x, y))\n                        cur[x] = 0x8000;\n                    else if (fill)\n                        cur[x] = 0xffff;\n                }\n            }\n\n            bmp.UnlockBits(bd);\n            return bmp;\n        }\n\n        private static bool IsPixelSet(byte[] data, int width, int x, int y)\n        {\n            int offset = x / 8 + y * ((width + 7) / 8);\n            if (offset > data.Length)\n                return false;\n            return (data[offset] & (1 << (7 - (x % 8)))) != 0;\n        }\n\n        /// <summary>\n        /// Resets Buffer with Bitmap\n        /// </summary>\n        /// <param name=\"bmp\"></param>\n        public unsafe void SetBuffer(Bitmap bmp)\n        {\n            Bytes = new byte[bmp.Height * (((bmp.Width - 1) / 8) + 1)];\n            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly,\n                PixelFormat.Format16bppArgb1555);\n            ushort* line = (ushort*) bd.Scan0;\n            //int delta = bd.Stride >> 1;\n            for (int y = 0; y < bmp.Height; ++y)\n            {\n                ushort* cur = line;\n                for (int x = 0; x < bmp.Width; ++x)\n                {\n                    if (cur[x] == 0x8000)\n                    {\n                        int offset = x / 8 + y * ((bmp.Width + 7) / 8);\n                        Bytes[offset] |= (byte) (1 << (7 - (x % 8)));\n                    }\n                }\n            }\n\n            bmp.UnlockBits(bd);\n        }\n    }\n\n    public static class UnicodeFonts\n    {\n        private static string[] m_files = new string[]\n        {\n            \"unifont.mul\",\n            \"unifont1.mul\",\n            \"unifont2.mul\",\n            \"unifont3.mul\",\n            \"unifont4.mul\",\n            \"unifont5.mul\",\n            \"unifont6.mul\",\n            \"unifont7.mul\",\n            \"unifont8.mul\",\n            \"unifont9.mul\",\n            \"unifont10.mul\",\n            \"unifont11.mul\",\n            \"unifont12.mul\"\n        };\n\n        public static UnicodeFont[] Fonts = new UnicodeFont[13];\n\n        static UnicodeFonts()\n        {\n            Initialize();\n        }\n\n        /// <summary>\n        /// Reads unifont*.mul\n        /// </summary>\n        public static void Initialize()\n        {\n            for (int i = 0; i < m_files.Length; i++)\n            {\n                string filePath = Files.GetFilePath(m_files[i]);\n                if (filePath == null)\n                    continue;\n                Fonts[i] = new UnicodeFont();\n                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    using (BinaryReader bin = new BinaryReader(fs))\n                    {\n                        for (int c = 0; c < 0x10000; ++c)\n                        {\n                            Fonts[i].Chars[c] = new UnicodeChar();\n                            fs.Seek((long) ((c) * 4), SeekOrigin.Begin);\n                            int num2 = bin.ReadInt32();\n                            if ((num2 >= fs.Length) || (num2 <= 0))\n                                continue;\n                            fs.Seek((long) num2, SeekOrigin.Begin);\n                            sbyte xOffset = bin.ReadSByte();\n                            sbyte yOffset = bin.ReadSByte();\n                            int Width = bin.ReadByte();\n                            int Height = bin.ReadByte();\n                            Fonts[i].Chars[c].XOffset = xOffset;\n                            Fonts[i].Chars[c].YOffset = yOffset;\n                            Fonts[i].Chars[c].Width = Width;\n                            Fonts[i].Chars[c].Height = Height;\n                            if (!((Width == 0) || (Height == 0)))\n                                Fonts[i].Chars[c].Bytes = bin.ReadBytes(Height * (((Width - 1) / 8) + 1));\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Draws Text with font in Bitmap and returns\n        /// </summary>\n        /// <param name=\"fontId\"></param>\n        /// <param name=\"text\"></param>\n        /// <returns></returns>\n        public static Bitmap WriteText(int fontId, string text)\n        {\n            Bitmap result = new Bitmap(Fonts[fontId].GetWidth(text) + 2, Fonts[fontId].GetHeight(text) + 2);\n\n            int dx = 2;\n            int dy = 2;\n            using (Graphics graph = Graphics.FromImage(result))\n            {\n                for (int i = 0; i < text.Length; ++i)\n                {\n                    int c = (int) text[i] % 0x10000;\n                    Bitmap bmp = Fonts[fontId].Chars[c].GetImage();\n                    dx += Fonts[fontId].Chars[c].XOffset;\n                    graph.DrawImage(bmp, dx, dy + Fonts[fontId].Chars[c].YOffset);\n                    dx += bmp.Width;\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Saves Font and returns string Filename\n        /// </summary>\n        /// <param name=\"path\"></param>\n        /// <param name=\"filetype\"></param>\n        /// <returns></returns>\n        public static string Save(string path, int filetype)\n        {\n            string FileName = Path.Combine(path, m_files[filetype]);\n            using (FileStream fs = new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Write))\n            {\n                using (BinaryWriter bin = new BinaryWriter(fs))\n                {\n                    fs.Seek(0x10000 * 4, SeekOrigin.Begin);\n                    bin.Write(0);\n                    // Set first data\n                    for (int c = 0; c < 0x10000; ++c)\n                    {\n                        if (Fonts[filetype].Chars[c].Bytes == null)\n                            continue;\n                        fs.Seek((long) ((c) * 4), SeekOrigin.Begin);\n                        bin.Write((int) fs.Length);\n                        fs.Seek(fs.Length, SeekOrigin.Begin);\n                        bin.Write(Fonts[filetype].Chars[c].XOffset);\n                        bin.Write(Fonts[filetype].Chars[c].YOffset);\n                        bin.Write((byte) Fonts[filetype].Chars[c].Width);\n                        bin.Write((byte) Fonts[filetype].Chars[c].Height);\n                        bin.Write(Fonts[filetype].Chars[c].Bytes);\n                    }\n                }\n            }\n\n            return FileName;\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/ValueStringBuilder.cs",
    "content": "using System;\nusing System.Buffers;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\nnamespace Ultima\n{\n    // https://github.com/Thealexbarney/LibHac/blob/master/src/LibHac/FsSystem/ValueStringBuilder.cs\n    internal ref struct ValueStringBuilder\n    {\n        private char[] _arrayToReturnToPool;\n        private Span<char> _chars;\n        private int _pos;\n\n\n        // If this ctor is used, you cannot pass in stackalloc ROS for append/replace.\n        public ValueStringBuilder(ReadOnlySpan<char> initialString) : this(initialString.Length)\n        {\n            Append(initialString);\n        }\n\n        public ValueStringBuilder(ReadOnlySpan<char> initialString, Span<char> initialBuffer) : this(initialBuffer)\n        {\n            Append(initialString);\n        }\n\n        public ValueStringBuilder(Span<char> initialBuffer)\n        {\n            _arrayToReturnToPool = null;\n            _chars = initialBuffer;\n            _pos = 0;\n        }\n\n        public ValueStringBuilder(int initialCapacity)\n        {\n            _arrayToReturnToPool = ArrayPool<char>.Shared.Rent(initialCapacity);\n            _chars = _arrayToReturnToPool;\n            _pos = 0;\n        }\n\n        public int Length\n        {\n            get => _pos;\n            set\n            {\n                Debug.Assert(value >= 0);\n                Debug.Assert(value <= _chars.Length);\n                _pos = value;\n            }\n        }\n\n        public int Capacity => _chars.Length;\n\n        public void EnsureCapacity(int capacity)\n        {\n            if (capacity > _chars.Length)\n                Grow(capacity - _chars.Length);\n        }\n\n        /// <summary>\n        /// Get a pinnable reference to the builder.\n        /// Does not ensure there is a null char after <see cref=\"Length\"/>\n        /// This overload is pattern matched in the C# 7.3+ compiler so you can omit\n        /// the explicit method call, and write eg \"fixed (char* c = builder)\"\n        /// </summary>\n        public ref char GetPinnableReference()\n        {\n            return ref MemoryMarshal.GetReference(_chars);\n        }\n\n        /// <summary>\n        /// Get a pinnable reference to the builder.\n        /// </summary>\n        /// <param name=\"terminate\">Ensures that the builder has a null char after <see cref=\"Length\"/></param>\n        public ref char GetPinnableReference(bool terminate)\n        {\n            if (terminate)\n            {\n                EnsureCapacity(Length + 1);\n                _chars[Length] = '\\0';\n            }\n            return ref MemoryMarshal.GetReference(_chars);\n        }\n\n        public ref char this[int index]\n        {\n            get\n            {\n                Debug.Assert(index < _pos);\n                return ref _chars[index];\n            }\n        }\n\n        public override string ToString()\n        {\n            string s = _chars.Slice(0, _pos).ToString();\n            Dispose();\n            return s;\n        }\n\n        /// <summary>Returns the underlying storage of the builder.</summary>\n        public Span<char> RawChars => _chars;\n\n        /// <summary>\n        /// Returns a span around the contents of the builder.\n        /// </summary>\n        /// <param name=\"terminate\">Ensures that the builder has a null char after <see cref=\"Length\"/></param>\n        public ReadOnlySpan<char> AsSpan(bool terminate)\n        {\n            if (terminate)\n            {\n                EnsureCapacity(Length + 1);\n                _chars[Length] = '\\0';\n            }\n            return _chars.Slice(0, _pos);\n        }\n\n        public ReadOnlySpan<char> AsSpan() => _chars.Slice(0, _pos);\n        public ReadOnlySpan<char> AsSpan(int start) => _chars.Slice(start, _pos - start);\n        public ReadOnlySpan<char> AsSpan(int start, int length) => _chars.Slice(start, length);\n\n        public bool TryCopyTo(Span<char> destination, out int charsWritten)\n        {\n            if (_chars.Slice(0, _pos).TryCopyTo(destination))\n            {\n                charsWritten = _pos;\n                Dispose();\n                return true;\n            }\n            else\n            {\n                charsWritten = 0;\n                Dispose();\n                return false;\n            }\n        }\n\n        public void Insert(int index, char value, int count)\n        {\n            if (_pos > _chars.Length - count)\n            {\n                Grow(count);\n            }\n\n            int remaining = _pos - index;\n            _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));\n            _chars.Slice(index, count).Fill(value);\n            _pos += count;\n        }\n\n        public void Insert(int index, ReadOnlySpan<char> s)\n        {\n            int count = s.Length;\n\n            if (_pos > (_chars.Length - count))\n            {\n                Grow(count);\n            }\n\n            int remaining = _pos - index;\n            _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));\n            s.CopyTo(_chars.Slice(index));\n            _pos += count;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Append(char c)\n        {\n            int pos = _pos;\n            if ((uint)pos < (uint)_chars.Length)\n            {\n                _chars[pos] = c;\n                _pos = pos + 1;\n            }\n            else\n            {\n                GrowAndAppend(c);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Append(string s)\n        {\n            int pos = _pos;\n            if (s.Length == 1 && (uint)pos < (uint)_chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc.\n            {\n                _chars[pos] = s[0];\n                _pos = pos + 1;\n            }\n            else\n            {\n                AppendSlow(s);\n            }\n        }\n\n        private void AppendSlow(string s)\n        {\n            int pos = _pos;\n            if (pos > _chars.Length - s.Length)\n            {\n                Grow(s.Length);\n            }\n\n            s.AsSpan().CopyTo(_chars.Slice(pos));\n            _pos += s.Length;\n        }\n\n        public void Append(char c, int count)\n        {\n            if (_pos > _chars.Length - count)\n            {\n                Grow(count);\n            }\n\n            Span<char> dst = _chars.Slice(_pos, count);\n            for (int i = 0; i < dst.Length; i++)\n            {\n                dst[i] = c;\n            }\n            _pos += count;\n        }\n\n        public void Append(ReadOnlySpan<char> value)\n        {\n            int pos = _pos;\n            if (pos > _chars.Length - value.Length)\n            {\n                Grow(value.Length);\n            }\n\n            value.CopyTo(_chars.Slice(_pos));\n            _pos += value.Length;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public Span<char> AppendSpan(int length)\n        {\n            int origPos = _pos;\n            if (origPos > _chars.Length - length)\n            {\n                Grow(length);\n            }\n\n            _pos = origPos + length;\n            return _chars.Slice(origPos, length);\n        }\n\n        public void Replace(ReadOnlySpan<char> oldChars, ReadOnlySpan<char> newChars)\n        {\n            Replace(oldChars, newChars, 0, _pos);\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Replace(ReadOnlySpan<char> oldChars, ReadOnlySpan<char> newChars, int startIndex, int count)\n        {\n            var slice = _chars.Slice(startIndex, count);\n\n            var indexOf = slice.IndexOf(oldChars);\n\n            if (indexOf == -1)\n            {\n                return;\n            }\n\n            if (newChars.Length > oldChars.Length)\n            {\n                int i = 0;\n\n                for (; i < oldChars.Length; ++i)\n                {\n                    slice[indexOf + i] = newChars[i];\n                }\n\n                Insert(indexOf + i, newChars.Slice(i));\n            }\n            else if (newChars.Length < oldChars.Length)\n            {\n                int i = 0;\n\n                for (; i < newChars.Length; ++i)\n                {\n                    slice[indexOf + i] = newChars[i];\n                }\n\n                Remove(indexOf + i, oldChars.Length - i);\n            }\n            else\n            {\n                newChars.CopyTo(slice.Slice(0, oldChars.Length));\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Replace(char oldChar, char newChar)\n        {\n            var slice = _chars;\n\n            var indexOf = slice.IndexOf(oldChar);\n            if (indexOf == -1)\n            {\n                return;\n            }\n\n            slice[indexOf] = newChar;\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Remove(int startIndex, int length)\n        {\n            if (length < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(length));\n            }\n\n            if (startIndex < 0)\n            {\n                throw new ArgumentOutOfRangeException(nameof(startIndex));\n            }\n\n            if (length > _pos - startIndex)\n            {\n                throw new ArgumentOutOfRangeException(nameof(length));\n            }\n\n            if (startIndex == 0)\n            {\n                _chars = _chars.Slice(length);\n            }\n            else if (startIndex + length == _pos)\n            {\n                _chars = _chars.Slice(0, startIndex);\n            }\n            else\n            {\n                // Somewhere in the middle, this will be slow\n                _chars.Slice(startIndex + length).CopyTo(_chars.Slice(startIndex));\n            }\n\n            _pos -= length;\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void GrowAndAppend(char c)\n        {\n            Grow(1);\n            Append(c);\n        }\n\n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private void Grow(int requiredAdditionalCapacity)\n        {\n            Debug.Assert(requiredAdditionalCapacity > 0);\n\n            char[] poolArray = ArrayPool<char>.Shared.Rent(Math.Max(_pos + requiredAdditionalCapacity, _chars.Length * 2));\n\n            _chars.CopyTo(poolArray);\n\n            char[] toReturn = _arrayToReturnToPool;\n            _chars = _arrayToReturnToPool = poolArray;\n            if (toReturn != null)\n            {\n                ArrayPool<char>.Shared.Return(toReturn);\n            }\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void Dispose()\n        {\n            char[] toReturn = _arrayToReturnToPool;\n            this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again\n            if (toReturn != null)\n            {\n                ArrayPool<char>.Shared.Return(toReturn);\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/Verdata.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nusing System.IO;\n\n// FileIDs\n//0 - map0.mul\n//1 - staidx0.mul\n//2 - statics0.mul\n//3 - artidx.mul\n//4 - art.mul\n//5 - anim.idx\n//6 - anim.mul\n//7 - soundidx.mul\n//8 - sound.mul\n//9 - texidx.mul\n//10 - texmaps.mul\n//11 - gumpidx.mul\n//12 - gumpart.mul\n//13 - multi.idx\n//14 - multi.mul\n//15 - skills.idx\n//16 - skills.mul\n//30 - tiledata.mul\n//31 - animdata.mul\n\nnamespace Ultima\n{\n    public sealed class Verdata\n    {\n        public static Stream Stream { get; private set; }\n        public static Entry5D[] Patches { get; private set; }\n\n        private static string path;\n\n        static Verdata()\n        {\n            Initialize();\n        }\n\n        public static void Initialize()\n        {\n            path = Files.GetFilePath(\"verdata.mul\");\n\n            if (path == null)\n            {\n                Patches = new Entry5D[0];\n                Stream = Stream.Null;\n            }\n            else\n            {\n                using (Stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))\n                {\n                    using (BinaryReader bin = new BinaryReader(Stream))\n                    {\n                        Patches = new Entry5D[bin.ReadInt32()];\n\n                        for (int i = 0; i < Patches.Length; ++i)\n                        {\n                            Patches[i].file = bin.ReadInt32();\n                            Patches[i].index = bin.ReadInt32();\n                            Patches[i].lookup = bin.ReadInt32();\n                            Patches[i].length = bin.ReadInt32();\n                            Patches[i].extra = bin.ReadInt32();\n                        }\n                    }\n                }\n\n                Stream.Close();\n            }\n        }\n\n        public static void Seek(int lookup)\n        {\n            if (Stream == null || !Stream.CanRead || !Stream.CanSeek)\n            {\n                if (path != null)\n                    Stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);\n            }\n\n            Stream.Seek(lookup, SeekOrigin.Begin);\n        }\n    }\n\n    public struct Entry5D\n    {\n        public int file;\n        public int index;\n        public int lookup;\n        public int length;\n        public int extra;\n    }\n}"
  },
  {
    "path": "Razor/UltimaSDK/WindowProcessStream.cs",
    "content": "#region license\n// Razor: An Ultima Online Assistant\n// Copyright (c) 2022 Razor Development Community on GitHub <https://github.com/markdwags/Razor>\n// \n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n// \n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n// \n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#endregion\n\nnamespace Ultima\n{\n    public class WindowProcessStream : ProcessStream\n    {\n        private ClientWindowHandle m_Window;\n        private ClientProcessHandle m_ProcessID;\n\n        public ClientWindowHandle Window\n        {\n            get { return m_Window; }\n            set { m_Window = value; }\n        }\n\n        public WindowProcessStream(ClientWindowHandle window)\n        {\n            m_Window = window;\n            m_ProcessID = ClientProcessHandle.Invalid;\n        }\n\n        public override ClientProcessHandle ProcessID\n        {\n            get\n            {\n                if (NativeMethods.IsWindow(m_Window) != 0 && !m_ProcessID.IsInvalid)\n                    return m_ProcessID;\n\n                NativeMethods.GetWindowThreadProcessId(m_Window, ref m_ProcessID);\n\n                return m_ProcessID;\n            }\n        }\n    }\n}"
  },
  {
    "path": "Razor/app.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <configSections>\n    <section name=\"Servers\" type=\"System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\"/>\n  </configSections>\n\n  <startup>\n    <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.7.2\"/>\n  </startup>\n\n  <appSettings>\n    <add key=\"UODataDir\" value=\"D:\\Games\\UO\"/>\n    <add key=\"UOClient\" value=\"D:\\Games\\UO\\client.exe\"/>\n    <add key=\"LastPort\" value=\"2593\"/>\n    <add key=\"LastProfile\" value=\"default\"/>\n    <add key=\"LastServer\" value=\"login.server.com\"/>\n    <add key=\"LastServerId\" value=\"0\"/>\n    <add key=\"ClientEncrypted\" value=\"1\"/>\n    <add key=\"ServerEncrypted\" value=\"0\"/>\n    <add key=\"ShowWelcome\" value=\"1\"/>\n    <add key=\"UId\" value=\"21613fcd\"/>\n    <add key=\"MaxOrganizerAgents\" value=\"20\"/>\n    <add key=\"MaxBuyAgents\" value=\"10\"/>\n    <add key=\"MaxRestockAgents\" value=\"10\"/>\n    <add key=\"ImportProfilesAndMacros\" value=\"true\"/>\n    <add key=\"BackupPath\" value=\".\\Backup\"/>\n  </appSettings>\n\n  <Servers>\n    <add key=\"Custom Server\" value=\"server.someserver.com,2593\"/>\n  </Servers>\n\n</configuration>\n"
  },
  {
    "path": "Razor/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"System.Buffers\" version=\"4.5.1\" targetFramework=\"net472\" />\n  <package id=\"System.Memory\" version=\"4.5.5\" targetFramework=\"net472\" />\n  <package id=\"System.Numerics.Vectors\" version=\"4.5.0\" targetFramework=\"net472\" />\n  <package id=\"System.Runtime.CompilerServices.Unsafe\" version=\"4.5.3\" targetFramework=\"net472\" />\n</packages>"
  },
  {
    "path": "Razor.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 17\r\nVisualStudioVersion = 17.0.31903.59\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Razor\", \"Razor\\Razor.csproj\", \"{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Crypt\", \"Crypt\\Crypt.vcxproj\", \"{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}\"\r\n\tProjectSection(ProjectDependencies) = postProject\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D} = {F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Loader\", \"Loader\\Loader.vcxproj\", \"{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{44ADAD77-7431-41DE-871C-F122478D39B2}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tCODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md\r\n\t\tCONTRIBUTING.md = CONTRIBUTING.md\r\n\t\tINSTALL.md = INSTALL.md\r\n\t\tLICENSE.md = LICENSE.md\r\n\t\tetc\\Language\\Razor_lang.enu = etc\\Language\\Razor_lang.enu\r\n\t\tREADME.md = README.md\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Platform\", \"Platform\\Platform.vcxproj\", \"{DB18390C-8AD4-4E69-8A5A-171260F7D74A}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"FastColoredTextBox\", \"FastColoredTextBox\\FastColoredTextBox.csproj\", \"{6DD14A85-CCFC-4774-BD26-0F5772512319}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Debug|Any CPU.ActiveCfg = Debug|x86\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Debug|Any CPU.Build.0 = Debug|x86\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Release|Any CPU.ActiveCfg = Release|x86\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Release|Any CPU.Build.0 = Release|x86\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Release|x64.Build.0 = Release|x64\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{B24E4FB1-4936-4544-9E88-F3FF9B04FDBA}.Release|x86.Build.0 = Release|x86\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Debug|Any CPU.Build.0 = Debug|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Debug|x64.ActiveCfg = Debug|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Release|Any CPU.Build.0 = Release|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Release|x64.ActiveCfg = Release|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{B32A4D9E-3AF1-4C75-989D-D62C4E8F08B1}.Release|x86.Build.0 = Release|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Debug|Any CPU.Build.0 = Debug|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Debug|x64.ActiveCfg = Debug|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Release|Any CPU.Build.0 = Release|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Release|x64.ActiveCfg = Release|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{F308E8D5-2B4F-40AD-9BF7-9A8F5DDA420D}.Release|x86.Build.0 = Release|Win32\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Debug|Any CPU.ActiveCfg = Debug|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Debug|Any CPU.Build.0 = Debug|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Debug|x86.ActiveCfg = Debug|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Debug|x86.Build.0 = Debug|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Release|Any CPU.ActiveCfg = Release|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Release|Any CPU.Build.0 = Release|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{DB18390C-8AD4-4E69-8A5A-171260F7D74A}.Release|x86.Build.0 = Release|Win32\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Release|x64.Build.0 = Release|x64\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{6DD14A85-CCFC-4774-BD26-0F5772512319}.Release|x86.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {185AA9DC-62C1-4770-80D5-82AA7648EE75}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.CHS",
    "content": "// Razor Simplified Chinese/CHS Language Pack\r\n// Last modified Date: 2007-7-19\r\n// Based on English language file.\r\n// Translated by Cloud, E-mail: linhongjun@hotmail.com, Blog: http://blog.plaync.jp/linhongjun/55934\r\n// Special thanks to: haojz(TLF Forum), DontdroptheSOAD(RunUO Forum),Thraxus(RunUO Forum).\r\n// If Razor can not load skillnames with this language file, please replace \"Cliloc.chs\" with \"Cliloc.enu\" under UO installation directory. Becuase there's no corresponding entry in localization file of Simplified Chinese(). Make sure you have made a copy of original file before doing this.\r\n// Ϊȷƿȷʾ,\"Cliloc.enu\"滻UOװĿ¼µ\"Cliloc.chs\",Ҳ˵ɾԭʼ\"Cliloc.chs\"ļ,Ȼ\"Cliloc.enu\"Ϊ\"Cliloc.chs\".ǰϵͳΪ.ڷİ汾\"Cliloc.cht\",ĻҲԽ滻,ĺɶȺܸ.ųӰ,ǿƼʹ.滻ǰҪԭʼļ.\r\n// Special string used in the game such as LastTarget, LastObject will not be translated in order to match with UO.\r\n// LastTarget,LastObjectָз,UOеһ.\r\n// UseOnceʾһԵĴ,ر,ʱ뿼.\r\n// Ϊĵ˵,Ϊļ:\r\n::Encoding=GB2312\r\n::CliLoc=CHS\r\n\r\n[controls]\r\nWelcomeForm::Text=ӭʹRazor - UOҵ!\r\nWelcomeForm::groupBox3=UOװ·(ĬΪԶ)\r\nWelcomeForm::dataBrowse=...\r\nWelcomeForm::label5=:\r\nWelcomeForm::groupBox2=\r\nWelcomeForm::label3=:\r\nWelcomeForm::label4=˿:\r\nWelcomeForm::groupBox1=ͻѡ(ĬΪԶ)\r\nWelcomeForm::useEnc=ʹOSI\r\nWelcomeForm::makeDef=浱ǰֵΪĬ\r\nWelcomeForm::browse=...\r\nWelcomeForm::label1=ؿͻ:\r\nWelcomeForm::patchEncy=ܿͻ(OSIѡ)\r\nWelcomeForm::showAtStart=ʱʾ\r\nWelcomeForm::quit=˳(&Q)\r\nWelcomeForm::okay=(&O)\r\n\r\nMainForm::Text=Razor v{0}\r\nMainForm::generalTab=һ\r\nMainForm::btnMap=UOλϵͳ\r\nMainForm::label10=:\r\nMainForm::systray=ϵͳ֪ͨ\r\nMainForm::taskbar=\r\nMainForm::smartCPU=ܻCPUʹ\r\nMainForm::label7=:\r\nMainForm::label11=ʾ:\r\nMainForm::groupBox4=õ(ProfilesĿ¼)\r\nMainForm::delProfile=ɾ\r\nMainForm::newProfile=½(&N)...\r\nMainForm::showWelcome=ʾӭ(Ӱû)\r\nMainForm::alwaysTop=ܶʾ\r\nMainForm::groupBox1=\r\nMainForm::opacityLabel=͸: 100%\r\nMainForm::moreMoreOptTab=ѡ\r\nMainForm::blockHealPoison=ֹĿжʱ\r\nMainForm::potionEquip=ʹҩˮʱԶ/װ\r\nMainForm::label17=RazorϢʾ:\r\nMainForm::QueueActions=ԶлĿʱ\r\nMainForm::spellUnequip=ʩʱԶ˫װ\r\nMainForm::autoOpenDoors=Զ(ʱ)\r\nMainForm::alwaysStealth=ʾǱв\r\nMainForm::autoFriend=ŶӳԱΪ\r\nMainForm::chkStealth=Ǳв\r\nMainForm::rememberPwds=ס(Ƽ)\r\nMainForm::showtargtext=ʱʾĿ״̬\r\nMainForm::preAOSstatbar=ʹPre-AOS״̬\r\nMainForm::logPackets=ݰ¼(Ƽ)\r\nMainForm::rangeCheckLT=LastTargetָ\r\nMainForm::actionStatusMsg=ʾ״̬Ϣ\r\nMainForm::label5=Ŀ궯ӳ:\r\nMainForm::label9=ĬϷȼ:\r\nMainForm::label8=\r\nMainForm::label6=ms\r\nMainForm::label18=x\r\nMainForm::gameSize=ǿϷڴС:\r\nMainForm::smartLT=ܻLastTargetָ\r\nMainForm::moreOptTab=ѡ\r\nMainForm::smoothWalk=ƽ\r\nMainForm::negotiate=ЭϷ\r\nMainForm::setLTHilight=\r\nMainForm::lthilight=ʾLastTarget\r\nMainForm::filterSnoop=͵Ϣ\r\nMainForm::incomingCorpse=ʾʬ(Ƽ)\r\nMainForm::incomingMob=ʾ/(Ƽ)\r\nMainForm::setHarmHue=\r\nMainForm::setNeuHue=\r\nMainForm::lblHarmHue=к\r\nMainForm::lblNeuHue=\r\nMainForm::lblBeneHue=\r\nMainForm::setBeneHue=\r\nMainForm::setSpeechHue=\r\nMainForm::setWarnHue=\r\nMainForm::setMsgHue=\r\nMainForm::setExHue=\r\nMainForm::autoStackRes=Զڽ¶ѻ//ԭľ\r\nMainForm::queueTargets=лLastTargetTargetSelfָ\r\nMainForm::spamFilter=ظϵͳϢ\r\nMainForm::label4=\r\nMainForm::openCorpses=µʬ\r\nMainForm::showNotoHue=ʾǰɫɫڱ(,,,,)\r\nMainForm::lblWarnHue=Ϣɫ\r\nMainForm::lblMsgHue=RazorϢɫ\r\nMainForm::lblExHue=ɫ\r\nMainForm::blockDis=սģʽֹ\r\nMainForm::chkForceSpellHue=ǿħɫ:\r\nMainForm::chkForceSpeechHue=ǿıɫ\r\nMainForm::label3=ʽ:\r\n\r\nMainForm::displayTab=ʾ/\r\nMainForm::warnCount=ֵʱ:\r\nMainForm::excludePouches=ԶԶС\r\nMainForm::highlightSpellReags=ʩʱħҩ(ʾ)\r\nMainForm::titlebarImages=ͼηʽʾԴ\r\nMainForm::checkNewConts=Զ\r\nMainForm::groupBox3=ʾ\r\nMainForm::showInBar=UOʾϢ:\r\nMainForm::groupBox2=Դ\r\nMainForm::counters::0=(ʽ)\r\nMainForm::counters::1=\r\nMainForm::delCounter=ɾ/༭\r\nMainForm::addCounter=...\r\nMainForm::recount=¼\r\nMainForm::dressTab=װ/\r\nMainForm::groupBox6=װ/Ʒ\r\nMainForm::clearDress=б\r\nMainForm::dressDelSel=Ƴ\r\nMainForm::undressBag=Ű\r\nMainForm::undressList=ȥ\r\nMainForm::dressUseCur=ӵǰ\r\nMainForm::targItem=(Ŀ)\r\nMainForm::dressNow=װ\r\nMainForm::groupBox5=װ/ѡ\r\nMainForm::removeDress=Ƴ\r\nMainForm::addDress=...\r\nMainForm::undressConflicts=Զ³ͻƷ\r\nMainForm::skillsTab=\r\nMainForm::dispDelta=ʾ״̬ĸı\r\nMainForm::skillCopyAll=\r\nMainForm::skillCopySel=ѡ\r\nMainForm::label1=ܺ:\r\nMainForm::setlocks=ü:\r\nMainForm::resetDelta=λ+/-\r\nMainForm::skillList::0=\r\nMainForm::skillList::1=ֵ\r\nMainForm::skillList::2=\r\nMainForm::skillList::3=+/-\r\nMainForm::skillList::4=\r\nMainForm::skillList::5=\r\nMainForm::agentsTab=\r\nMainForm::hotkeysTab=ȼ\r\nMainForm::dohotkey=ִѡȼ\r\nMainForm::groupBox8=ȼ\r\nMainForm::chkPass=UO\r\nMainForm::label2=:\r\nMainForm::unsetHK=ȡ\r\nMainForm::setHK=\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=\r\nMainForm::macroActGroup=\r\nMainForm::loopMacro=ѭ\r\nMainForm::recMacro=¼\r\nMainForm::playMacro=\r\nMainForm::delMacro=Ƴ\r\nMainForm::newMacro=½...\r\nMainForm::screenshotTab=ͼ\r\nMainForm::label12=ͼʽ:\r\nMainForm::capNow=ͼ\r\nMainForm::radioUO=UO\r\nMainForm::radioFull=ȫĻ\r\nMainForm::screenAutoCap=ʱԶͼ\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=ͼȡʱ\r\nMainForm::videoTab=Ƶ\r\nMainForm::recFolder=...\r\nMainForm::label13=Ƶļ:\r\nMainForm::groupBox7=PacketVideo¼\r\nMainForm::vidRec=ʼ¼PacketVideo\r\nMainForm::groupBox10=AVIӰ¼\r\nMainForm::flipVidVert=ֱ\r\nMainForm::flipVidHoriz=ˮƽ\r\nMainForm::recAVI=ʼ¼AVIӰ...\r\nMainForm::label16=:\r\nMainForm::label15=FPS:\r\nMainForm::label19=ת:\r\nMainForm::groupBox9=PacketVideoط\r\nMainForm::rpvTime=00:00/00:00\r\nMainForm::label14=ٶ:\r\nMainForm::vidClose=ر\r\nMainForm::vidPlayStop=ֹͣ\r\nMainForm::vidPlay=\r\nMainForm::vidOpen=...\r\nMainForm::statusTab=״̬\r\nMainForm::forumsLink=Razor\r\nMainForm::homeLink=Razorҳ\r\nMainForm::userGuideLink=Razorûֲ\r\n\r\nHueEntry::Text=ѡɫ\r\nHueEntry::cancel=ȡ\r\nHueEntry::okay=ȷ(&O)\r\nHueEntry::preview=Ԥ\r\nHueEntry::inGame=Ϸѡ\r\nHueEntry::label1=ɫ:\r\n\r\nAddCounter::Text=һ\r\nAddCounter::delete=ɾ\r\nAddCounter::target=Ŀ\r\nAddCounter::cancel=ȡ\r\nAddCounter::Add=ȷ(&O)\r\nAddCounter::label4=ɫ(κ:-1):\r\nAddCounter::label3=ƷID:\r\nAddCounter::label2=ʽ:\r\nAddCounter::label1=:\r\n\r\nMacroInsertWait::Text=ȴ/ͣ...\r\nMacroInsertWait::radioMenu=ȴɷĲ˵/Ի\r\nMacroInsertWait::cancel=ȡ(&C)\r\nMacroInsertWait::radioStat=ȴ\r\nMacroInsertWait::radioTarg=ȴĿ\r\nMacroInsertWait::radioGump=ȴԻ\r\nMacroInsertWait::label1=ms\r\nMacroInsertWait::radioPause=ͣȴ:\r\nMacroInsertWait::insert=(&I)\r\n\r\nMacroInsertIf::Text=If...\r\nMacroInsertIf::label1=If:\r\nMacroInsertIf::cancel=ȡ(&C)\r\nMacroInsertIf::insert=(&I)\r\n\r\nInputBox::cancel=ȡ\r\nInputBox::ok=ȷ(&O)\r\n\r\n[strings]\r\n1001=״̬\r\n1002=ʫ\r\n1003=\r\n1004=è\r\n1005=\r\n1006=\r\n1007=\r\n1008=ħʧ\r\n1009=\r\n1010=ʾ\r\n1011=¼\r\n1012=AOS\r\n1013=ѡ(AOS)\r\n1014=ôѡ(AOS)\r\n1015=ѣ(Pre-AOS)\r\n1016=ý(Pre-AOS)\r\n1017={0}\r\n1018=AOSȡ.\r\n1019=жװ\r\n1020=ж˫װ\r\n1021=жװ\r\n1022=жװ\r\n1023=жñ\r\n1024=ж\r\n1025=ñԼ\r\n1026=ñLastTarget\r\n1027=ʹñ(޼ʱ)\r\n1028=ʹHeal\r\n1029=ʹCure\r\n1030=ʹRefresh\r\n1031=ʹNight Sight\r\n1032=ʹExplosion\r\n1033=ʹStrength\r\n1034=ʹAgility\r\n1035=δֱ\r\n1036=δָƷ{0}!\r\n1037=˫({0})\r\n1038=ѡĿ\r\n1039=תΪ˫\r\n1040=ΪöѡһµĿ.\r\n1041=:ظõʱ:\\n{0}\r\n1042=꾯:޷ҵƷ(Χ).\r\n1043={1} - {0}\r\n1044=תΪ\r\n1045=꾯:δװκƷ.\r\n1046=װ{0} (L:{1})\r\n1047=϶{0} (@{1})\r\n1048=תΪλ\r\n1049=϶()@({0},{1},{2})\r\n1050=ԻӦ({0})\r\n1051=رնԻ\r\n1052=˵Ӧ{0}\r\n1053=:ҪĿ,ǷδĿ!(ҪһWaitForTarget(ȴĿ)ָ?)\r\n1054=Ŀѡ\r\n1055=תΪLastTarget\r\n1056=ѡĿ\r\n1057=ѡĿλ({0},{1})\r\n1058=LastTarget\r\n1059=TargetSelf\r\n1060=LastTarget\r\n1061=ָﷸ()\r\n1062=ָ()\r\n1063=ָͨ()\r\n1064=ָ\r\n1065=ָ\r\n1066=ָ\r\n1067=˵\"{0}\"\r\n1068=ʹü{0}\r\n1069=ʹħ{0}\r\n1070=ʹ{0}\r\n1071=װ:{0}\r\n1072=ж:{0}\r\n1073=װ{0}\r\n1074=ȴ˵()\r\n1075=ȴ˵(#{0})\r\n1076=༭...\r\n1077=ȴԻ()\r\n1078=ȴԻ(#{0})\r\n1079=WaitForTarget\r\n1080=ͣ{0:#.00}\r\n1081=ȴ{0} {1} {2}\r\n1082='{0}'...\r\n1083=>ֹͣǰ\r\n1084=:{0}\r\n1085=ź'{0}'...\r\n1086='{0}'.\r\n1087=Razor޷ʼ.:\r\n1088=:޷ҵͻ˴ھ.\\nԭ:ͻδʼ(Razor޷,ȷͻ).\r\n1089=:޷ҵͻ˽ID\\nԭ:ͻδʼ(Razor޷ͻ˹ҹ,ͨڿͻδʱı,ȷͻ).\r\n1090=:޷ϵͳҹ.\\nԭ:ڲڴ.\r\n1091=:޷ȡRazorڴ.\\nԭ:ϵͳЧ.\r\n1092=:Crypt.dllѱԶ.\\nԭ:汾(Crypt.dllļ,°װRazor,ʹԭʼ汾Crypt.dllļ).\r\n1093=:޷Winsock.\\nԭ:ڲ,ϵͳ,(°װRazor).\r\n1094=:Ч͵.\\nԭ:ƥDLLļ汾(°װRazor).\r\n1095=:޷ӿͻ˸ưȻϢ.\\nRazorԲʹЩϢ,һЩܽ޷.Razor?\\n\\nԭ:Ŀͻ˰汾Razor汾(뾡Razor5.0.0ϰ汾ȷ).\r\n1096=ļ{0}Ѿ{4}{5:F1},{3:F1}({1}{2:F1}).\r\n1097=ЧԴ.\r\n1098=ЧƷID.\r\n1099=Чɫ.\r\n1100=ѡһƷ.\r\n1101='{0}'!\\nøõѾ𻵲޷ʹ.\r\n1102={0}ڸøõ޷ҵ.\r\n1103=counters.xmlļѾ𻵲޷ʹ.\r\n1104=ΪԶѡڹر״̬,ڱ´еİԱԸ.\r\n1105=:{0}{1}!\r\n1106=ѡʹõɫ.\r\n1107=ͼ\r\n1108=òֵ:\\n{char} - ɫ\\n{shard} - վ\\n{str}/{hp}/{hpmax} - ״̬\\n{dex}/{stam}/{stammax} - ״̬\\n{int}/{mana}/{manamax} - ״̬\\n{weight}/{maxweight} - Ϣ\\n{gold} - Ǯ\\n{AR} - װ/ ֿ\\n{tithe} - ˰״̬\\n{followers}/{followersmax} - ֵ\\n{bandage} - ʱ\\n{statbar}/{mediumstatbar}/{largestatbar} - ״̬(С//)\\n{crimtime} - Ϊﷸʱ\\n{stealthsteps} - Ǳв\\n{physresist} - ֿ\\n{coldresist} - 俹\\n{fireresist} - ׿\\n{energyresist} - \\n{poisonresist} - \\n{luck} - ֵ\\n{damage} - ˺ֵ Min-Max(Сֵ-ֵ)\\nɫ - HTML16ƴ:'~#rrggbb'('~#~'ɫ)\\nߴӼбʹ{Format}ʽ\r\n1109=汾:{0}\\nڴʹ:{1}\\n:{2} ({3}/s)\\n:{4} ({5}/s)\\nʱ:{6}\\n:0x{7:X8}\\n:0x{8:X8}\\nƷ:{9}\\n:{10}\\n\\n:Cloud (linhongjun@hotmail.com)\\nʱ:2007/07/19\\nע:ĳЩϢִ޷ʾ(ħ,),ı༭Razor\\Language\\µRazor_lang.chsļĶϸ˵.\r\n1110=趨:\r\n1111=趨:½\r\n1112=趨:\r\n1113=ȷҪƳ\"{0}\"?\\n⽫Ӱиõ.\r\n1114=ڼظõ\"{0}\"?\r\n1115=ȡõʱ.\r\n1116=㲻ɾĬϵĸõ.\r\n1117=µĸõ:\r\n1118=޷µĸõ!\\nԭ:øõѴ.\\n\\nھͼظøõ?\r\n1119=µб:\r\n1120=ɾб?\r\n1121={0:X}(ƷΧ)\r\n1122=бɾƷ?\r\n1123=ѡһжб'{0}'еƷ.\r\n1124=жƷŰ.\r\n1125=Ʒδҵ,ѡЧƷ.\r\n1126=Ѿ'{0}'.\\nҪΪ'{1}'?\r\n1127=ݳɹ.\r\n1128=!\\n¼ݰܻήRazor.¼ļ,RazorԶƳ.\\n\\nRazorݼ¼ļܻϢ,ЩļӦøκ㲻ε.\\n\\nȷҪݰ¼?\\n(ᱣĸõ)\r\n1129=ѡĿתΪ\r\n1130=µĺ:\r\n1131=ưЧַ.\r\n1132=ͬѴ.\r\n1133=úڼ¼ǰᱻ.\\nȷҪ¼ǵú?\r\n1134=ȷҪɾ'{0}'?\\n(⽫ǲ)\r\n1135=ͣ/ȴ...\r\n1136=LastTarget\r\n1137=\r\n1138=\r\n1139=Ƴ\r\n1140=ʼ¼\r\n1141=ļ'{0}'δҵ.\r\n1142=ȷ?\r\n1143=:{0}ļ{1}޷ɾ:\\n{2}\r\n1144=Ľ´RazorʱЧ.\r\n1145=øѡᵼRazorڸõ.\\nѾ,Ȼпܻȡ.\\nȷҪøù?\r\n1146=ָһЧĶ˿.\r\n1147=Զ(Ѿڶ).\r\n1148=ж{0}...{1}ʣ.\r\n1149={0}ж{1:F1}.\r\n1150=UseOnce\r\n1151=(Ŀ)...\r\n1152=(Ŀ)...\r\n1153=Ƴ(Ŀ)...\r\n1154=б\r\n1155=ָһƷ.\r\n1156=ָһ.\r\n1157=ָһƷƳ.\r\n1158=Ʒ.\r\n1159=ƷƳ.\r\n1160={0}ƷѾӵUseOnce.\r\n1161=UseOnceѿ!\r\n1162=ʹ'{0}'.({1}ƷUseOnce)\r\n1163=ĳUseOnceƷд,һ.\r\n1164=:ԶԼ۸{1}gp{0}Ʒ.\r\n1165=Ƴ\r\n1166=óɹ.\r\n1167=\r\n1168=(Խ)\r\n1169=()\r\n1170=ð\r\n1171=\r\n1172=\r\n1173=\r\n1174=\r\n1175=δ.\r\n1176=Razor޷ҵı.\r\n1177={0}ƷҪƶ.(ҪһЩʱ)\r\n1178=޷ҵκοƶƷ.\r\n1179=ƷѴб.\r\n1180=Զ\r\n1181=Լ۸{1}gp{0}Ʒ.\r\n1182=޷беһЩƷ,Ϊû㹻ĽǮ.\r\n1183=:\r\n1184=ͻ˳ȼΪ{0}\r\n1185=ǰʱ:{0}\r\n1186=λõǰ{0},λ'{1}'\r\n1187=ж°δֻ򳬳Χ,ʹñ.\r\n1188={0}Ʒڶнж.\r\n1189={0}Ʒڶнװ.\r\n1190={0}Ʒװ.\r\n1191={0}Ʒδ.(Χ)\r\n1192=:Spells.defļδҵ,ħʽıʾ.\r\n1193=Ǳв:{0}\r\n1194=ڼ¼Ǳв.\r\n1195=Ŀ\r\n1196=μս\r\n1197=Ŀ.\r\n1198=ָһµLastTarget\r\n1199=LastTarget.\r\n1200=Ŀ.\r\n1201=δҵ֮ĿĻ֮.\r\n1202=мTargetSelf.\r\n1203=мLastTarget.\r\n1204=µĿ,ȡRazorõĿ.\r\n1205=Ŀ{0}\r\n1206=\r\n1207=ȷҪɾ?\r\n1208=ѡһļͼ.\r\n1209=ȼ\r\n\r\n1210=Ʒ\r\n1211=Ŀ\r\n1212=\r\n1213=\r\n1214=\r\n1215=ħ\r\n1216=\r\n1217=\r\n1251=1st\r\n1252=2nd\r\n1253=3rd\r\n1254=4th\r\n1255=5th\r\n1256=6th\r\n1257=7th\r\n1258=8th\r\n1260=ʦ\r\n1270=ʿ\r\n1271=ҩˮ\r\n1272=\r\n1290=ʿ\r\n1300=\r\n1301=\r\n1302=\r\n1303=Ҫ\r\n1304=Razorб\r\n1305=ʹƷ\r\n1306=װ֮ǰжһЩװ.\r\n1307=װ/жƷ\r\n1308=װ/жƷ\r\n1309=µǰʹ֮Ʒ\r\n1310=δװκƷ.\r\n1311=>/Razorȼ\r\n1312=ȼ( {0} )\r\n1313=ȼѽ( {0} )\r\n1314=ȼ\r\n1315=ȼѽ\r\n1316=:{0}\r\n1317=(Ŀ)...\r\n1318=Ŀ곬Χ,LastTargetָᱻִ!\r\n1319=:{0}\r\n1320=͵Ϣ\r\n1321=Ч\r\n1322=\"If\"\r\n1323=\"Else\"\r\n1324=\"End If\"\r\n1325=\r\n1326=\r\n1327=ڲ\r\n1328=\r\n1329=ָһָԼʹ.\r\n1330=ĿЧ.\r\n1331=,Ѽ{0}Ʒ{1}.\r\n1332=ȡǰĿ\r\n1333=⵽°汾.\\n\\nRazorվ°?\r\n1334=¼\r\n1335=\r\n1336=:ǰĿ겻㽫Ŀָ.LastTargetָЧ.\r\n1337=ͬͻ\r\n1338=ֹ.\r\n1339=ʼRazor\"PacketVideo\"¼\r\n1340=ֹͣ\"PacketVideo\"¼/\r\n1341=ʼ¼ʱ.\\nѾ¼.\r\n1342=ļڴ˰汾.ȷѰװ°汾Razor.\r\n1343=Ӱļ.\\nܲ,Ѿ޸.\\nļ޷.\r\n1344=ȡļʱ.ļ𻵻.\r\n1345=:\r\n1346=Ŀ¼޷ɾ.ȷĿ¼Ϊ.\r\n1347=޷Ŀ¼.ȷȷȻ³.\r\n1348=޷ƶļ.ȷЧ.\r\n1349=\r\n// 1350 to 1359 reserved (max length 15!)\r\n1350=ֹͣ\r\n1351=\r\n1352=Ϸ?\r\n1353=\r\n1354=?\r\n1355=ˣ\r\n1356=ɵ?\r\n1357=̫!\r\n1358=군\r\n1359=!\r\n1360=ָһҲ뵽б.\r\n1361=ָһҲӺбƳ.\r\n1362=.\r\n1363=Ƴ.\r\n1364=⹹\r\n1365=\"For Loop\"\r\n1366=\"End For\"\r\n1367=ظ:\r\n1368=Ļ\r\n1369=LastSpell(ħ)\r\n1370=LastSkill()\r\n1371=LastObject(Ŀ)\r\n1372=AllNames(ʾ/)\r\n1373=UseOnce\r\n1374=ָж\r\n1375=ָ\r\n1376=ָ\r\n1377=ָﷸ\r\n1378=ָﷸ\r\n1379=:Ϸųʱ!еƷ뵽.\r\n1380=RazorͿͻȷЧ.\r\n1381=ǳϷ,ȻµȷЧ.\r\n1382=Ϸ{0}...{1}ʣ.\r\n1383=...\r\n1384=Ѿ{0}{1},{2}.\r\n1385=Ѿ{0}{1},{2}.\r\n1386=Ѿ{0}{1},{2}.\r\n1387=Դ\r\n1388=Ʊֹ(Ŀж)!\r\n1389=ϷŶ\r\n1390=ֹͣ\r\n1391=>/Լ\r\n1392=NextTarget\r\n1393=ò\r\n1394=ӵUseOnce\r\n1395=LastTarget\r\n1396=༭ʱ...\r\n1397=㵱ǰδκƷ.\r\n1398=\r\n1399=\r\n1400=Э̵:\r\n1401=Ա.\r\n1402=\r\n1403=Դ\r\n1404=LastTarget\r\n1405=ΧڼLastTarget\r\n1406=Զ\r\n1407=ʩʱжװ\r\n1408=Զʹҩˮ,װ\r\n1409=жʱֹ\r\n1410=ѭ\r\n1411=UseOnce\r\n1412=\r\n1413=۴\r\n1414=\r\n1415=ҩˮȼ\r\n1416=Ŀ\r\n1417=/״̬ʾ\r\n// up to 1465: reserved\r\n1466=Բ\r\n1467=ԱǰϷ.\\nѡԷ,ѡǩ½.\\n\\n鿴ֹб,ڰ״̬ǩ.\r\n1468=ע\r\n1469=Ӻ\r\n1470=Ƴ\r\n1471=>/Լ\r\n1472=ʹѽܵĿͻ,Ӧý\"\".ùܽʹҪͻ˼ܵķ(OSI/EAٷ).\\n㲻ȷ,벻Ҫѡ.\\n\\nȷҪرտͻ˽?\r\n1473=\r\n1474=ʾ/صͼ\r\n1475=̫Զ.\r\n1476=ϷŶ!Ժ.\r\n1477=лս/ƽģʽ\r\n1478=ͶԻ\r\n1479=ָϷڴСЧ,³.\r\n1480=()\r\n1481=( {0})\r\n1482=(UseOnce #{0})\r\n1483=()\r\n1484=( {0} )\r\n1485=ָķַ޷,ȷϵַǷȷ.\r\n1486=Ŷ:\r\n1487=Ŷ:ܾ\r\n1488=Ŀ\r\n1489=жĿ\r\n1490=(Razor)\r\n1491=Ӵ˴\r\n1492=ʼ...\r\n1493=ڼµĸõ...\r\n1494=ڼؿͻ...\r\n1495=ȴͻ...\r\n1496=ǵ!\r\n1497=ӭʹRazor!\r\n1498=2Dͻ(Զ)\r\n1499=3Dͻ(Զ)\r\n1500=(Զ)\r\n1501=͸: {0}%\r\n1502=ָöĳʱʱ():\r\n1503=δָ\r\n1504=ĳʱ\r\n1505=\r\n1506=Ч.\r\n1507=ԱƷ\r\n1508={0} ״̬\r\n1509=ʳñʩħƻ\r\n1510=ָ\r\n1511=ָ\r\n1512=ָͨ\r\n1513=ָ\r\n1514=ָ\r\n1515=ָ\r\n1516=ָж\r\n1517=ָ\r\n1518=ָͨ\r\n1519=ָ\r\n1520=ָﷸ\r\n1521=:õ'{0}'ڱRazorʹ!\\nԸõ޸,ôѾ.ÿһRazorʹö(ͬ)õ.\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.PTB",
    "content": "// Razor Portuguese Brazil/PTB Language Pack - By Thiago X\r\n// Last Modified 01/01/04\r\n::CliLoc=ENU\r\n\r\n[controls]\r\nWelcomeForm::Text=Bem-Vindo ao razor!\r\nWelcomeForm::label5=Lingua do Razor\r\nWelcomeForm::groupBox3=Perfil\r\nWelcomeForm::newProfile=Novo...\r\nWelcomeForm::label2=Carregar Perfil:\r\nWelcomeForm::groupBox2=Servidor\r\nWelcomeForm::label3=Servidor:\r\nWelcomeForm::label4=Porta:\r\nWelcomeForm::groupBox1=Opcoes do Client\r\nWelcomeForm::makeDef=Fazer essas opcoes como padrao\r\nWelcomeForm::browse=Navegador...\r\nWelcomeForm::label1=Carregar Client:\r\nWelcomeForm::patchEncy=Fazer patch na encriptacao do Client\r\nWelcomeForm::showAtStart=Mostrar isso quando o razor iniciar.\r\nWelcomeForm::quit=&Sair\r\nWelcomeForm::okay=&Ok\r\nMainForm::Text=Razor v{0} (Beta)\r\nMainForm::generalTab=Geral\r\nMainForm::label7=Indioma:\r\nMainForm::logPackets=Abilitar LOGs\r\nMainForm::rememberPwds=Lembrar Senhas \r\nMainForm::systray=System Tray\r\nMainForm::taskbar=TaskBar\r\nMainForm::label11=Mostrar na:\r\nMainForm::groupBox4=Perfis\r\nMainForm::delProfile=Deletar\r\nMainForm::newProfile=&Novo...\r\nMainForm::showWelcome=Mostrar tela de Bem-Vindo\r\nMainForm::alwaysTop=Usar modo de Sempre no Topo\r\nMainForm::groupBox1=Filtros\r\nMainForm::opacityLabel=Opaco: 100%\r\nMainForm::moreOptTab=Opcoes\r\nMainForm::incomingCorpse=Mostrar nomes de Corpos\r\nMainForm::incomingMob=Mostrar nome de Pessoas/Criaturas\r\nMainForm::setHarmHue=Setar\r\nMainForm::setNeuHue=Setar\r\nMainForm::lblHarmHue=Dano\r\nMainForm::lblNeuHue=Neutra\r\nMainForm::lblBeneHue=Beneficial\r\nMainForm::setBeneHue=Setar\r\nMainForm::setSpeechHue=Setar\r\nMainForm::setWarnHue=Setar\r\nMainForm::setMsgHue=Setar\r\nMainForm::setExHue=Setar\r\nMainForm::autoStackRes=Sempre Jogar Minerios/Peixes no chao\r\nMainForm::queueTargets=Colocar LastTarget e TargetSelf na Fila\r\nMainForm::actionStatusMsg=Mostrar msg de Itens na \"fila\"\r\nMainForm::spamFilter=Filtrar Spam (Experimental)\r\nMainForm::label4=tiles\r\nMainForm::openCorpses=Abrir corpos em\r\nMainForm::showNotoHue=Mostrar cor de estado na barra de Ttulo\r\nMainForm::lblWarnHue=Msg de aviso\r\nMainForm::lblMsgHue=Msg de sistema\r\nMainForm::lblExHue=Cor da busca\r\nMainForm::chkStealth=Contar passos de Stealth\r\nMainForm::label6=ms\r\nMainForm::label5=Tempo:\r\nMainForm::QueueActions=Tempo para efetuar acoes\r\nMainForm::chkForceSpellHue=Cores das Magias:\r\nMainForm::chkForceSpeechHue=Sobrepor cor da fala\r\nMainForm::label3=Magias:\r\nMainForm::displayTab=Mostrar/Contadores\r\nMainForm::highlightSpellReags=Grifar reagentes requeridos\r\nMainForm::titlebarImages=Mostrar Imagem nos contadores\r\nMainForm::sortCounters=Manter contadores Atualizados\r\nMainForm::checkNewConts=Sempre proucurar novos containers\r\nMainForm::warnCount=Avisar quando contador estiver:\r\nMainForm::groupBox3=Barra de Titulo\r\nMainForm::showInBar=Mostrar isso na barra de titulo:\r\nMainForm::groupBox2=Contadores\r\nMainForm::delCounter=Del/Editar\r\nMainForm::addCounter=Novo\r\nMainForm::recount=Recontar\r\nMainForm::dressTab=(Des)Verstir\r\nMainForm::groupBox6=(Des)Vestir Itens\r\nMainForm::dressDelSel=Remover\r\nMainForm::undressBag=Mudar bag de desvestir\r\nMainForm::undressList=Desvestir agora\r\nMainForm::dressUseCur=Adic. Atual\r\nMainForm::targItem=Adic. (Alvo)\r\nMainForm::dressNow=Vestir Agora\r\nMainForm::groupBox5=Selecao de (Des)Vestir\r\nMainForm::removeDress=Remover\r\nMainForm::addDress=Novo...\r\nMainForm::undressConflicts=Mover itens em conflito (automatico)\r\nMainForm::skillsTab=Skills\r\nMainForm::dispDelta=Atualizar\r\nMainForm::skillCopyAll=Copiar Todos\r\nMainForm::skillCopySel=Copiar Selec.\r\nMainForm::label1=Soma:\r\nMainForm::setlocks=Mudar Todos:\r\nMainForm::resetDelta=Resetar  +/-\r\nMainForm::screenshotTab=Screen Shots\r\nMainForm::capNow=Tirar Foto\r\nMainForm::radioUO=Apenas UO\r\nMainForm::radioFull=Tela Toda\r\nMainForm::screenAutoCap=Capturar Foto de Mortes\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Incluir data nas Fotos\r\nMainForm::hotkeysTab=Atalhos\r\nMainForm::dohotkey=Executar Selec.\r\nMainForm::groupBox8=Atalho\r\nMainForm::chkPass=Passar para o UO\r\nMainForm::label2=Key:\r\nMainForm::unsetHK=Tirar\r\nMainForm::setHK=Setar\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Macros\r\nMainForm::macroActGroup=Acoes\r\nMainForm::loopMacro=Intinito\r\nMainForm::recMacro=Gravar\r\nMainForm::playMacro=Reproduzir\r\nMainForm::delMacro=Remover\r\nMainForm::newMacro=Novo...\r\nMainForm::agentsTab=Agentes\r\nMainForm::statusTab=Ajuda && Status\r\nMainForm::visitForums=Forum de Ajuda && Suporte\r\nMainForm::visitHome=HomePage do Razor\r\nMainForm::visitGuide=Guia do Usuario - Razor\r\nMainForm::spellUnequip=Desequipar Maos Antes de Castar\r\nMainForm::rangeCheckLT=Distancia Ultimo alvo:\r\nMainForm::moreMoreOptTab=Mais Opcoes\r\nHueEntry::Text=Selecione uma Cor\r\nHueEntry::cancel=Cancelar\r\nHueEntry::okay=&Ok\r\nHueEntry::preview=Proximo\r\nHueEntry::inGame=Selecinar no jogo\r\nHueEntry::label1=Cor:\r\nAddCounter::Text=Editor de Contador\r\nAddCounter::delete=Deletar\r\nAddCounter::target=Alvo \r\nAddCounter::cancel=Cancelar\r\nAddCounter::Add=&Ok\r\nAddCounter::label4=Cor (Qq: -1):\r\nAddCounter::label3=Item ID:\r\nAddCounter::label2=Formato:\r\nAddCounter::label1=Nome:\r\nMacroInsertWait::Text=Inserir Esperar/Pausar...\r\nMacroInsertWait::radioMenu=Espear por Menus de Estilo Antigo/Dialogos\r\nMacroInsertWait::cancel=&Cancelar\r\nMacroInsertWait::radioStat=Esperar por \r\nMacroInsertWait::radioTarg=Esperar por Alvo\r\nMacroInsertWait::radioGump=Esperar por GUMP\r\nMacroInsertWait::label1=milliseconds\r\nMacroInsertWait::radioPause=Pausar por:\r\nMacroInsertWait::insert=&Inserir\r\n\r\n[strings]\r\n1001=Status de Morto\r\n1002=Musica de Bardo\r\n1003=Sons de Cachorro\r\n1004=Sons de Gato\r\n1005=Son de Cavalo\r\n1006=Sons de Ovelha\r\n1007=Sons de Spirt Speak\r\n1008=Sons de Errar Magia\r\n1009=Estacoes\r\n1010=Mostrar Contadores\r\n1011=Recontar Contadores\r\n1012=Limpar Habilidade Aos\r\n1013=Setar habilidade Primaria (AOS)\r\n1014=Setar Habilidade Secundaria (AOS)\r\n1015=Setar Stun (Pre-AOS)\r\n1016=Setar Disarm (Pre-AOS)\r\n1017=Setando Habilidade {0}\r\n1018=Habilidades do AOS Resetadas.\r\n1019=Desvestir Tudo\r\n1020=Desvestir ambas as Maos\r\n1021=Desvestir mao esquerda\r\n1022=Desvestir mao direita\r\n1023=Desvestir chapeu\r\n1024=Desvestir Joias\r\n1025=Curar-se Com Bandagem\r\n1026=Bandagem do LastTarget\r\n1027=Usar Bandagem (Sem Timer)\r\n1028=Beber Heal\r\n1029=Beber Cura\r\n1030=Beber Refresh\r\n1031=Beber Night Sight\r\n1032=Beber Explosao\r\n1033=Beber Strength\r\n1034=Beber Agility\r\n1035=Bandagem nao encontrada.\r\n1036=Item do tipo {0} nao encontrado!\r\n1037=Dois clicks ({0})\r\n1038=Escolher Novo\r\n1039=Converter para 2Clicks por tipo\r\n1040=Selecione um novo alvo para esta acao.\r\n1041=WARNING: Exception while loading profile property:\\n{0}\r\n1042=Macro Warning: Cannot find that item (Out of Range).\r\n1043=Lift {1} - {0}\r\n1044=Convert to Lift by Type\r\n1045=Macro Warning: Not holding anything.\r\n1046=Equip to {0}\r\n1047=Drop to {0} (@{1})\r\n1048=Convert to Relative Location\r\n1049=Drop (Relative) @({0},{1},{2})\r\n1050=GumpResponse (Button {0})\r\n1051=Fechar Gump\r\n1052=MenuResponse {0}\r\n1053=Warning: Macro requested target, but no target sent from server! (Do you need a 'WaitForTarget'?)\r\n1054=Alvo Absoluto\r\n1055=Converter para Ultimo Alvo\r\n1056=Target by Type {0}\r\n1057=Target RelLoc ({0},{1},{2})\r\n1058=Ultimo Alvo\r\n1059=Alvo - Voce Mesmo\r\n1060=Setar ultimo alvo\r\n1061=Alvo - Assassino Aleatorio\r\n1062=Alvo - Criminoso Aleatorio\r\n1063=Alvo - Neutro Aleatorio\r\n1064=Alvo - Inimigo Aleatorio\r\n1065=Alvo - Amigo Aleatorio\r\n1066=Alvo - Nao-Inimigo Aleatio\r\n1067=Dizer \"{0}\"\r\n1068=UseSkill {0}\r\n1069=Castar Magia {0}\r\n1070=SetAbility {0}\r\n1071=Vestir: {0}\r\n1072=Desvestir: {0}\r\n1073=Unequip Layer {0}\r\n1074=Wait for Menu (Any)\r\n1075=Wait for Menu (#{0})\r\n1076=Edit...\r\n1077=Wait For Gump (Any)\r\n1078=Wait for Gump (#{0})\r\n1079=Wait for Target\r\n1080=Pausa {0:#.00}sec\r\n1081=Esperar por {0} {1} {2}\r\n1082=Carregando '{0}'...\r\n1083=> Para Macro atual\r\n1084=Reproduzir macro: {0}\r\n1085=Reproduzindo '{0}'...\r\n1086=Macro '{0}' terminado.\r\n1087=O razor nao foi possivel inicializar.  Erro Codigo:\\n\r\n1088=Descricao: Nao foi possivel achar a janela do client.\\nPossivel Causa: O client nao foi iniciado.\r\n1089=Descricao: Nao foi possivel encontrar ThreadID\\nPossivel Causa: O client nao foi iniciado.\r\n1090=Descricao: Nao foi possivel criar hook de janela.\\nPossivel Causa: Erro interno.\r\n1091=Descricao: O razor nao conseguiu acessar a memoria compartilhada.\\nPossivel Causa: Erro ou permissoes invalidas.\r\n1092=Descricao: Crypt.dll foi desabilidado.\\nPossivel Causa: Falta de .NETFRAMEWORK ou Versao invalida.\r\n1093=Descricao: Nao foi possivel patchear o client.\\nPossivel Causa: Erro interno, Erro do Windows, ou versao imcompativel.\r\n1094=\r\n1095=Warning: Nao foi possivel copiar encriptacao para o client.\\nO razor talvez consiga rodar sem essas informacoes, mas talvez todas as opcoes nao funcionem corretamente.  Voce gostaria de executa-lo mesmo assim?\\n\\nPossivel Causa: O seu client nao  compativel com essa versao do razor.\r\n1096=sua skill {0} foi mudada em {1}{2:F1}, agora e {3:F1}.\r\n1097=Abreviacao invalida.\r\n1098=ItemID Invalida.\r\n1099=Cor Invalida.\r\n1100=Selecione um item para Contar.\r\n1101=Erro carregando '{0}'!\\nEsse perfil esta corrompido ou nao pode ser usado.\r\n1102=A propriedade {0} nao foi encontrada nesse perfil.\r\n1103=Seu counters.xml esta corrompido e nao pode ser usado.\r\n1104=A opcao de busca por containers esta desabilidata, Voce tera que abrir todos os containers para os contadores funcionarem.\r\n1105=AVISO: {0} esta agora em {1}!\r\n1106=Selecione a cor que voce quer usar.\r\n1107=Tirar foto agora\r\n//1108=Valores possiveis:\\n{char} - Nome do Char\\n{shard} - Nome do Shard\\n{str}/{hp}/{hpmax} - Status de Vida\\n{dex}/{stam}/{stammax} - Status de Dex\\n{int}/{mana}/{manamax} - Status de Int\\n{weight}/{maxweight} - Informacao do Peso\\n{gold} - Ouro total no personagem\\n{AR} - Valor da Armadura / Resistencia fisica\\n{tithe} - Tithing points\\n{bandage} - Tempo de Bandagens\\n{statbar}/{mediumstatbar}/{largestatbar} - Status bar\\n{crimtime} - Quanto tempo send criminoso\\n{stealthsteps} - Passos de Stealth contagem de cor - Codigo de Cor HTML hex: '~#rrggbb' ('~#~' para terminar)\\nou um {Format} para a lista de contadroes.\r\n1109=Razor Versao {0}\\nMemoria Usada: {1}\\nEnviado: {2} ({3}/s)\\nRecv: {4} ({5}/s)\\nConectado por {6}\\n\\nSerial do Personagem: 0x{7:X8}\\nSerial da Mochila: 0x{8:X8}\\n\\nItens Rastreados: {9}\\nPersonagens Rastreados: {10}\\n\r\n1110=Setar Tranca: Cima\r\n1111=Setar Tranca: Baixo\r\n1112=Setar Tranca: Fechada\r\n1113=Tem certeza que deseja remover o contador \"{0}\"?\\nIsso afeta todos os perfis.\r\n1114=Carregar Perfil \"{0}\" agora?\r\n1115=Aconteceu um erro carregando aquele perfil.\r\n1116=Voce nao pode deletar o perfil padrao.\r\n1117=Entre um nome para o novo perfil: \r\n1118=Voce nao pode criar um novo perfil!\\n Um perfil come sse nome ja existe.\\n\\nDeseja carregar aquele perfila agora?\r\n1119=Entre um nome para a nova lista de (DES)Vestiver:\r\n1120=Deletar essa lista de (Des)Vestir?\r\n1121={0:X} (Item muito longe)\r\n1122=Deletar esse item da lista de (Des)Vestir?\r\n1123=Selecione uma bag para colocar a lista de '{0}' dentro.\r\n1124=(Des)Vestir bag setada.\r\n1125=Item nao encontrado ou item invalido selecionado.\r\n1126=Essa combinacao de chaves ja esta ligada com '{0}'.\\nmudar isso para '{1}'?\r\n1127=Arquivos salvos com sucesso.\r\n1128=AVISO!\\nPacotes de LOGs vao reduzir a performace do razor. Arquivos de LOG serao extremamente grandes e o razor nao ira remove-los automaticamente.\\n\\nIsso tambem ira salvar informacoes pessoais (senhas e etc) e podera cair em maos erradas.\\n\\nTem certeza que voce deseja habilitar isso?\\n(Isso nao vai ser salvo em seu perfil de usuario)\r\n1129=Converter selecionado para TIPO\r\n1130=Entre um nome para o novo macro: \r\n1131=Aquele nome contem caracteres invalidos.\r\n1132=Um macro com aquele nome ja existe.\r\n1133=Este macro sera apagado depois de gravado.\\nTem certeza que deseja gravar POR CIMA deste macro?\r\n1134=Tem certeza que voce deseja apagar PERMANENTEMENTE '{0}'?\\n(Isso nao pode ser desfeito)\r\n1135=Inserir Pausa/Esperar...\r\n1136=Inserir Ultimo Alvo...\r\n1137=Mover para Cima\r\n1138=Mover para Baixo\r\n1139=Remove Action\r\n1140=Comecar gravar aqui\r\n1141=O arquivo '{0}' nao foi encontrado.\r\n1142=Voce tem certeza\r\n1143=AVISO: Os seguinte(s) {0} arquivo{1} nao pode(m) ser deletados:\\n{2}\r\n1144=Essa mudanca vai ser habilitada a proxima vez que voce iniciar o razor.\r\n1145=Habilitando essa opcao vai fazer com que as senhas sejam salvas como parte de seu perfil.\\nEles serao encriptados, mas qualquer pessoa com acesso ao seu arquivo xml podera usa-lo.\\nTem certeza que voce deseja habilitar esta opcao?\r\n1146=Voce precisa espeficicar uma porta valida.\r\n1147=Ignorando acoes requisitadas (Ja na fila).\r\n1148=Colocando acoes requisitadas na fila {0}... {1} restante.\r\n1149=Terminado {0} acoes na fila em {1:F1} segundos.\r\n1150=Use Once Agente\r\n1151=Adic. (Alvo)...\r\n1152=Adic. Container (Alvo)...\r\n1153=Remover (Alvo)...\r\n1154=Limpar Lista\r\n1155=Selecione um item para adicionar\r\n1156=Selecione um container.\r\n1157=Selecione um item para remover.\r\n1158=Item adicionado.\r\n1159=Item remivido.\r\n1160={0} iten(s) adicionados para o agente Use Once.\r\n1161=A fila do UseOnce esta vazia!\r\n1162=Usando '{0}'.  ({1} iten(s) restante na fila do UseOnce)\r\n1163=Aqui exite um problema com os UseOnce itens, tentando o proximo.\r\n1164=Agente de Vendas: Vendendo automaticamente {0} item(s) por {1}gp.\r\n1165=Remover\r\n1166=Container setado com sucesso.\r\n1167=Limpar\r\n1168=(Aperte para desativar)\r\n1169=(Aperta para Ativar)\r\n1170=Selecione a Mochila\r\n1171=Limpar Mochila\r\n1172=Agente Organizador\r\n1173=Organizer\r\n1174=Organizar agora\r\n1175=Container nao setado.\r\n1176=Razor nao pode encontrar sua mochila.\r\n1177=Agente organizador na fila {0} item(s) para serem movidos. (Isso pode demorar uns momentos)\r\n1178=Agente organizador nao encontrou nenhum item para mover.\r\n1179=Aquele item ja esta na lista.\r\n1180=AutoSearchExemptions\r\n1181=Agente de Compras comprou {0} item(s) por {1}gp.\r\n1182=O angente de comprar nao conseguiu comprar alguns itens por que voce nao tem dinheiro.\r\n1183=Entre uma quantia:\r\n1184=Prioridade de Processamento do Client {0}\r\n1185=A hora atual e: {0}\r\n1186=Voce esta na {0} em '{1}'\r\n1187=Mochila para Desvestir nao foi encotnrada ou eta muito longe, usando sua mochila.\r\n1188={0} item(s) na fila para semrem desequipados.\r\n1189={0} item(s) na fila para serem equipados.\r\n1190={0} item(s) ja estao equipados.\r\n1191={0} item(s) nao foram encontrados. (Ou muito longes)\r\n1192=AVISO: Spells.def nao foi encontrado, o formato das magias nao serao mostrados.\r\n1193=Passos em Stealth: {0}\r\n1194=Agora Contando Passos em Stealth.\r\n1195=Limpar fila de Alvos\r\n1196=Atacar ultimo combatente\r\n1197=Alvo na fila limpo.\r\n1198=Selecione um novo 'Last Target'\r\n1199=Last Target setado.\r\n1200=Novo alvo setado.\r\n1201=No one matching that was found on your screen.\r\n1202=Fila para si mesmo.\r\n1203=Fila para ultimo alvo.\r\n1204=O Servidor enviou um novo alvo, cancelando o alvo do razor.\r\n1205=Alvo por tipo {0}\r\n1206=Scavenger\r\n1207=Tem certeza que voce deseja deletar isso?\r\n1208=Selecione uma pasta para guardar as Fotos tiradas pelo razor.\r\n1209=Atalhos\r\n1210=Itens\r\n1211=Alvos\r\n1212=Agentes\r\n1213=Vestir\r\n1214=Macros\r\n1215=Magias\r\n1216=Skills\r\n1217=Variados\r\n// 1219 - 1250 reserved\r\n1251=1st\r\n1252=2nd\r\n1253=3rd\r\n1254=4th\r\n1255=5th\r\n1256=6th\r\n1257=7th\r\n1258=8th\r\n// 1259 not used\r\n1260=Necromancy\r\n// 1261 - 1269 not used\r\n1270=Chivalry\r\n1271=Pocoes\r\n1272=Special Moves\r\n// 1273 - 1299 reserved\r\n1373=UseOnce\r\n1301=Sell\r\n1302=Buy\r\n1303=Dado Requerido\r\n1304=Lista de Comandos do Razor\r\n1305=Usar Wand de Identificacao\r\n1306=Voce precisa desarmar alguma coisa antes de armar isso.\r\n1307=(Des)Vestir mao direita\r\n1308=(Des)vestir mao esquerda\r\n1309=Jogar o que estiver segurando.\r\n\r\n1311=> Habilitar/Desabilitar Atalhos\r\n1312=Atalhos habilitados (Pressione {0} para desabilitar)\r\n1313=Atalhos desabilitados(Pressione {0} para habilitar)\r\n1314=Atalhos Abilitados\r\n1315=Atalhos desabilitados\r\n1316=Ande: {0}\r\n1317=Adicionar tipo (Target)...\r\n1318=Alvo muito longe, ao no executada!\r\n1319=Vender Maximo: {0}"
  },
  {
    "path": "etc/Language/Razor_lang.bg",
    "content": "// Razor English/ENU Language Pack\r\n// Last Modified 12/16/03\r\n::CliLoc=enu\r\n\r\n[controls]\r\nWelcomeForm::Text=   Razor!\r\nWelcomeForm::label5=   Razor:\r\nWelcomeForm::groupBox3=\r\nWelcomeForm::newProfile=...\r\nWelcomeForm::label2= :\r\nWelcomeForm::groupBox2=\r\nWelcomeForm::label3=:\r\nWelcomeForm::label4=:\r\nWelcomeForm::groupBox1=  \r\nWelcomeForm::makeDef=    \r\nWelcomeForm::browse=...\r\nWelcomeForm::label1= :\r\nWelcomeForm::patchEncy=Patch   \r\nWelcomeForm::showAtStart=     Razor\r\nWelcomeForm::quit=&\r\nWelcomeForm::okay=&\r\nMainForm::generalTab=\r\nMainForm::label7=:\r\nMainForm::logPackets=   \r\nMainForm::rememberPwds=  \r\nMainForm::systray= tray \r\nMainForm::taskbar=Taskbar\r\nMainForm::label11=:\r\nMainForm::groupBox4=\r\nMainForm::delProfile=\r\nMainForm::newProfile=&...\r\nMainForm::showWelcome= Welcome \r\nMainForm::alwaysTop= -  \r\nMainForm::groupBox1=\r\nMainForm::opacityLabel= : 100%\r\nMainForm::moreOptTab= \r\nMainForm::incomingCorpse=   /  \r\nMainForm::incomingMob=     /\r\nMainForm::setHarmHue=\r\nMainForm::setNeuHue=\r\nMainForm::lblHarmHue=\r\nMainForm::lblNeuHue=\r\nMainForm::lblBeneHue=\r\nMainForm::setBeneHue=\r\nMainForm::setSpeechHue=\r\nMainForm::setWarnHue=\r\nMainForm::setMsgHue=\r\nMainForm::setExHue=\r\nMainForm::autoStackRes=. stack-  Ore/Fish/Logs  .\r\nMainForm::queueTargets=Queue-  LastTarget  TargetSelf\r\nMainForm::actionStatusMsg= Action-Queue   \r\nMainForm::spamFilter=   ()\r\nMainForm::label4=\r\nMainForm::openCorpses=   \r\nMainForm::showNotoHue= \"noto hue\"  {char}  TitleBar-\r\nMainForm::lblWarnHue= \r\nMainForm::lblMsgHue= \r\nMainForm::lblExHue=Search Exemption \r\nMainForm::chkStealth=   stealth\r\nMainForm::label6=.\r\nMainForm::label5= delay:\r\nMainForm::QueueActions=Auto-Queue    Delay \r\nMainForm::chkForceSpellHue=   . :\r\nMainForm::chkForceSpeechHue=   \r\nMainForm::label3=  . :\r\nMainForm::displayTab=/\r\nMainForm::highlightSpellReags=   \r\nMainForm::titlebarImages=    \r\nMainForm::sortCounters=  ./.\r\nMainForm::checkNewConts=.    \r\nMainForm::warnCount=    :\r\nMainForm::groupBox3=  Titlebar\r\nMainForm::showInBar=    Titlebar-:\r\nMainForm::groupBox2=\r\nMainForm::delCounter=/\r\nMainForm::addCounter=...\r\nMainForm::recount=\r\nMainForm::dressTab=\r\nMainForm::groupBox6= \r\nMainForm::dressDelSel=\r\nMainForm::undressBag=   \r\nMainForm::undressList= \r\nMainForm::dressUseCur= \r\nMainForm::targItem= ()\r\nMainForm::dressNow= \r\nMainForm::groupBox5=  \r\nMainForm::removeDress=\r\nMainForm::addDress=...\r\nMainForm::undressConflicts=.  \"\" \r\nMainForm::skillsTab=\r\nMainForm::dispDelta= \r\nMainForm::skillCopyAll= \r\nMainForm::skillCopySel= \r\nMainForm::label1= :\r\nMainForm::setlocks=  :\r\nMainForm::resetDelta=  +/-\r\nMainForm::screenshotTab=\r\nMainForm::capNow= \r\nMainForm::radioUO=  \r\nMainForm::radioFull= \r\nMainForm::screenAutoCap=.   \r\nMainForm::setScnPath=...\r\nMainForm::dispTime= \r\nMainForm::hotkeysTab= \r\nMainForm::dohotkey= \r\nMainForm::groupBox8= \r\nMainForm::chkPass=   \r\nMainForm::label2=:\r\nMainForm::unsetHK=\r\nMainForm::setHK=\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=\r\nMainForm::macroActGroup=\r\nMainForm::loopMacro=\r\nMainForm::recMacro=\r\nMainForm::playMacro=\r\nMainForm::delMacro=\r\nMainForm::newMacro=...\r\nMainForm::agentsTab=\r\nMainForm::statusTab= && \r\nMainForm::visitForums= &&  \r\nMainForm::visitHome=Razor \r\nMainForm::visitGuide=Razor \r\nHueEntry::Text= \r\nHueEntry::cancel=\r\nHueEntry::okay=&\r\nHueEntry::preview=\r\nHueEntry::inGame=  \r\nHueEntry::label1=  :\r\nAddCounter::Text=  \r\nAddCounter::delete=\r\nAddCounter::target= \r\nAddCounter::cancel=\r\nAddCounter::Add=&\r\nAddCounter::label4= ( .: -1):\r\nAddCounter::label3= ID:\r\nAddCounter::label2=:\r\nAddCounter::label1=:\r\nMacroInsertWait::Text= \r\nMacroInsertWait::radioMenu=     \r\nMacroInsertWait::cancel=&\r\nMacroInsertWait::radioStat=  \r\nMacroInsertWait::radioTarg=  \r\nMacroInsertWait::radioGump=  gump\r\nMacroInsertWait::label1=\r\nMacroInsertWait::radioPause= :\r\nMacroInsertWait::insert=&\r\n\r\n\r\n[strings]\r\n1001= - \r\n1002=  \r\n1003= \r\n1004= \r\n1005= \r\n1006= \r\n1007=Spirit Speak \r\n1008=    \r\n1009=\r\n1010= \r\n1011=  \r\n1012= AOS \r\n1013=   (AOS)\r\n1014=   (AOS)\r\n1015=/ Stun (Pre-AOS)\r\n1016=/ Disarm/ (Pre-AOS)\r\n1017=   {0}\r\n1018=AOS  .\r\n1019= \r\n1020=  \r\n1021=  \r\n1022=  \r\n1023= \r\n1024= \r\n1025=  \r\n1026= LastTarget\r\n1027= ( )\r\n1028= Heal\r\n1029= Cure\r\n1030= Refresh\r\n1031= Night Sight\r\n1032=\"\" Explosion\r\n1033= Strength\r\n1034= Agility\r\n1035= \r\n1036=   : {0}!\r\n1037=Double Click ({0})\r\n1038= \r\n1039=  DClick  .\r\n1040=    .\r\n1041=:     :\\n{0}\r\n1042= :    ! ( ).\r\n1043= {1} - {0}\r\n1044=  \"\"  \r\n1045= :   .\r\n1046=  {0}\r\n1047=  {0} (@{1})\r\n1048=   \r\n1049= () @({0},{1},{2})\r\n1050=Gump  ( {0})\r\n1051= Gump\r\n1052=  {0}\r\n1053=:   ,       ! (    'WaitForTarget')\r\n1054= \r\n1055=  LastTarget\r\n1056=   {0}\r\n1057=  ({0},{1},{2})\r\n1058=Last Target\r\n1059=Target Self\r\n1060= Last Target\r\n1061=   (red)\r\n1062=   (gray)\r\n1063=   (blue)\r\n1064=   (orange)\r\n1065=   (green)\r\n1066=  - (hmm..:)\r\n1067= \"{0}\"\r\n1068=  {0}\r\n1069=  {0}\r\n1070=  {0}\r\n1071=: {0}\r\n1072=: {0}\r\n1073= Layer {0}\r\n1074=   (Any)\r\n1075=   (#{0})\r\n1076=...\r\n1077=  Gump (Any)\r\n1078=  Gump (#{0})\r\n1079=  \r\n1080= {0:#.00}sec\r\n1081=  {0} {1} {2}\r\n1082= '{0}'...\r\n1083=>  \r\n1084=: {0}\r\n1085=  '{0}'...\r\n1086= '{0}' .\r\n1087=Razor   .   :\\n\r\n1088=Description: Could not find the client Window Handle.\\nPossible Cause: The Client may not have initialized properly.\r\n1089=Description: Could not find the Client's ThreadID\\nPossible Cause: The Client may not have initialized Properly.\r\n1090=Description: Could not create Windows Hooks.\\nPossible Cause: Internal error.\r\n1091=Description: Could not create or access Razor shared memory.\\nPossible Cause: Windows Error or invalid permissions.\r\n1092=Description: Crypt.dll has disabled itself.\\nPossible Cause: Version mismatch.\r\n1093=Description: Could not patch the client's Winsock functions.\\nPossible Cause: Internal error, Windows Error, or Incompatible Version.\r\n1094=\r\n1095=:     /    .\\nRazor      ,       .        ?\\n\\n :           Razor.\r\n1096= {0}   {1}{2:F1},    {3:F1}.\r\n1097= .\r\n1098=  ID.\r\n1099= .\r\n1100=   .\r\n1101=   '{0}'!\\n    .\r\n1102= {0}     .\r\n1103= counters.xml    .\r\n1104=   . .    ,        be .\r\n1105=: {0}   {1}!\r\n1106= ,   .\r\n1107=  !\r\n//1108=:\\n{char} - \\n{shard} - \\n{str}/{hp}/{hpmax} -  \\n{dex}/{stam}/{stammax} -  \\n{int}/{mana}/{manamax} - \\n{weight}/{maxweight} -  \\n{gold} -    \\n{AR} -  \\n{tithe} - Tithing \\n{bandage} -     \\n{statbar}/{mediumstatbar}/{largestatbar} -  \\n{crimtime} -    \\n{stealthsteps} - Stealth  |   r - HTML  : '~#rrggbb' ('~#~'  )\\n {Format}    \r\n1109=Razor Version: {0}\\n  : {1}\\n: {2} ({3}/s)\\n: {4} ({5}/s)\\n  {6}\\n\\n  : 0x{7:X8}\\n  : 0x{8:X8}\\n\\n : {9}\\n  Mobs: {10}\\n\r\n1110=: \r\n1111=: \r\n1112=\r\n1113=  ,     ? \"{0}\"?\\n      .\r\n1114=  \"{0}\" ?\r\n1115=    .\r\n1116=    .\r\n1117=   : \r\n1118=    !\\n :    .\\n\\n      ? \r\n1119=    :\r\n1120=   ?\r\n1121={0:X} (  )\r\n1122=     ?\r\n1123=     '{0}' .\r\n1124=    .\r\n1125=   ,   .\r\n1126=      '{0}'.\\n  '{1}'?\r\n1127=  .\r\n1128=!\\n  .    ,  Razor     !\\n\\nRazor-                 .\\n\\n  ,     ?\\n(      .)\r\n1129=  \r\n1130=   : \r\n1131= .\r\n1132=   .\r\n1133=     .\\n ,   ?\r\n1134=   '{0}'?\\n(   )\r\n1135= ...\r\n1136= LastTarget\r\n1137= \r\n1138= \r\n1139= \r\n1140=   \r\n1141= '{0}'   .\r\n1142=  ?\r\n1143=:  {0} {1}    !:\\n{2}\r\n1144=         Razor.\r\n1145=          .\\n   ,          ,        .\\n     ?\r\n1146=    .\r\n1147=  ( queued).\r\n1148=Queuing   {0}... {1} .\r\n1149= {0} queued  {1:F1} .\r\n1150=  \r\n1151= ()...\r\n1152=  ()...\r\n1153= ()...\r\n1154= \r\n1155=   .\r\n1156= .\r\n1157= ,   .\r\n1158=  .\r\n1159=  .\r\n1160={0} ()    .\r\n1161=Queue     !\r\n1162= '{0}'.  ({1} () ())\r\n1163=       ,   .\r\n1164= :  {0} ()  {1}.\r\n1165=\r\n1166=   .\r\n1167=\r\n1168=()\r\n1169=()\r\n1170= \" \"\r\n1171= \" \"\r\n1172=\r\n1173=\r\n1174= !\r\n1175=   .\r\n1176=Razor     .\r\n1177=  {0} ()  . (   .)\r\n1178=     .\r\n1179=    .\r\n1180=.  - Exemptions ()\r\n1181=   {0} ()  {1}.\r\n1182=    ,    .\r\n1183= :\r\n1184=   - {0}\r\n1185= : {0}\r\n1186=   {0}  '{1}'\r\n1187=       ,    .\r\n1188={0} () ()  .\r\n1189={0} () ()  .\r\n1190={0} ()  ().\r\n1191={0} ()  / (). ( )\r\n1192=: Spells.def   ,         .\r\n1193=Stealth : {0}\r\n1194= stealth .\r\n1195=  Target Queue\r\n1196=   (AttackLast)\r\n1197=Target queue .\r\n1198=  'Last Target'\r\n1199=Last Target .\r\n1200=  .\r\n1201=   .\r\n1202=  queue target self.\r\n1203=  queue last target.\r\n1204=   ,   Razor .\r\n1205=   {0}\r\n1206=.  (scavenger)\r\n1207=  ,     ?\r\n1208=   .\r\n1209= \r\n1210=\r\n1211=\r\n1212=\r\n1213=\r\n1214=\r\n1215=\r\n1216=\r\n1217=\r\n// 1219 - 1250 reserved\r\n1251=1\r\n1252=2\r\n1253=3\r\n1254=4\r\n1255=5\r\n1256=6\r\n1257=7\r\n1258=8\r\n// 1259 not used\r\n1260=\r\n// 1261 - 1269 not used\r\n1270= - \r\n1271=\r\n1272=\r\n// 1273 - 1299 reserved\r\n1373= \r\n1301=\r\n1302=\r\n1303=  \r\n1304=Razor  \r\n1305=   \r\n1306=  ,     .\r\n1307=/  \r\n1308=/  \r\n1309=  .\r\n\r\n1311=> /  \r\n1312=   ( {0}  )\r\n1313=   ( {0}  )\r\n1314=  \r\n1315=  \r\n1316= : {0}\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.cht",
    "content": "// Razor Traditional Chinese/CHT Language Pack\r\n// Last modified Date: 2007-7-19\r\n// Based on Simplified Chinese language file.\r\n// Translated by Cloud, E-mail: linhongjun@hotmail.com, Blog: http://blog.plaync.jp/linhongjun/55934\r\n// If Razor can not load skillnames with this language file, please replace \"Cliloc.chs\" with \"Cliloc.enu\" under UO installation directory. Becuase there's no corresponding entry in localization file of simplified chinese. Make sure you have made a copy of original file before doing this.\r\n// TOޯW٥iHT,Х\"Cliloc.enu\"UOw˥ؿU\"Cliloc.chs\",]NORl\"Cliloc.chs\",MW\"Cliloc.enu\"\"Cliloc.chs\".eOA@~tΥ²餤.t~c餤媩\"Cliloc.cht\",pG㪺ܤ]iHi,̭Ƨ׫ܰ.pGưoӤ譱]vT,jP˨ϥ.eаȥnƥl.\r\n// Special string used in the game such as LastTarget, LastObject will not be translated in order to match with UO.\r\n// LastTarget,LastObjectoON|i½Ķ,ɶqOPUO]w@P.\r\n// UseOnceȶȪܤ@ʪNz,LSONq,Ȯɤ@½ĶҼ{.\r\n// This CHT language pack is converted by tool. Please contact me for any problem or suggestion.\r\n// cyqLuഫMiyչӦ,py½ĶWPΰDp,HK.\r\n// HWɻ,HUy󤺮e:\r\n::Encoding=BIG5\r\n::CliLoc=CHT\r\n\r\n[controls]\r\nWelcomeForm::Text=wϥRazor - UOaQb!\r\nWelcomeForm::groupBox3=UOw˸|(w]۰ʰ)\r\nWelcomeForm::dataBrowse=s...\r\nWelcomeForm::label5=y:\r\nWelcomeForm::groupBox2=A\r\nWelcomeForm::label3=A:\r\nWelcomeForm::label4=f:\r\nWelcomeForm::groupBox1=Ȥݳ]w(w]۰ʰ)\r\nWelcomeForm::useEnc=ϥOSI[K\r\nWelcomeForm::makeDef=OseȬw]tm\r\nWelcomeForm::browse=s...\r\nWelcomeForm::label1=[Ȥ:\r\nWelcomeForm::patchEncy=ѱKȤ(DOSI)\r\nWelcomeForm::showAtStart=Ұʮܥ\r\nWelcomeForm::quit=(&Q)\r\nWelcomeForm::okay=Ұ(&O)\r\n\r\nMainForm::Text=Razor v{0}\r\nMainForm::generalTab=@\r\nMainForm::btnMap=}UOwt\r\nMainForm::label10=ˬds:\r\nMainForm::systray=tγqϰ\r\nMainForm::taskbar=\r\nMainForm::smartCPU=}ҴCPUϥ\r\nMainForm::label7=y:\r\nMainForm::label11=ܩ:\r\nMainForm::groupBox4=ӤHtmɮ(OsProfilesؿU)\r\nMainForm::delProfile=R\r\nMainForm::newProfile=إ(&N)...\r\nMainForm::showWelcome=wɭ(|vTҦΤ)\r\nMainForm::alwaysTop=}Ҵ೻\r\nMainForm::groupBox1=Lo\r\nMainForm::opacityLabel=z: 100%\r\nMainForm::moreMoreOptTab=h]w\r\nMainForm::blockHealPoison=bؼФrɶiv\r\nMainForm::potionEquip=ϥĤɦ۰ʸѰ/s˳\r\nMainForm::label17=RazorT:\r\nMainForm::QueueActions=۰ʶCƥؼЩɰʧ@\r\nMainForm::spellUnequip=Ikɦ۰ʸѰ˳\r\nMainForm::autoOpenDoors=۰ʶ}(ɤK)\r\nMainForm::alwaysStealth=`OܼB\r\nMainForm::autoFriend=Nζn\r\nMainForm::chkStealth=pB\r\nMainForm::rememberPwds=OKX()\r\nMainForm::showtargtext=ܥؼЪA\r\nMainForm::preAOSstatbar=ϥPre-AOSA\r\nMainForm::logPackets=}Ҹƥ]O()\r\nMainForm::rangeCheckLT=LastTargetOZ˴\r\nMainForm::actionStatusMsg=ܰʧ@CAT\r\nMainForm::label5=ؼаʧ@:\r\nMainForm::label9=w]Cuv:\r\nMainForm::label8=B\r\nMainForm::label6=ms\r\nMainForm::label18=x\r\nMainForm::gameSize=jCjp:\r\nMainForm::smartLT=}ҴLastTargetO\r\nMainForm::moreOptTab=]w\r\nMainForm::smoothWalk=Ʀ樫\r\nMainForm::negotiate=PAӹCS\r\nMainForm::setLTHilight=]w\r\nMainForm::lthilight=GLastTarget\r\nMainForm::filterSnoop=LosT\r\nMainForm::incomingCorpse=ܫW()\r\nMainForm::incomingMob=ܤHW/ͪW()\r\nMainForm::setHarmHue=]w\r\nMainForm::setNeuHue=]w\r\nMainForm::lblHarmHue=`\r\nMainForm::lblNeuHue=\r\nMainForm::lblBeneHue=q\r\nMainForm::setBeneHue=]w\r\nMainForm::setSpeechHue=]w\r\nMainForm::setWarnHue=]w\r\nMainForm::setMsgHue=]w\r\nMainForm::setExHue=]w\r\nMainForm::autoStackRes=۰ʩ}Unq//\r\nMainForm::queueTargets=CLastTargetMTargetSelfO\r\nMainForm::spamFilter=LoƨtΰT\r\nMainForm::label4=B\r\nMainForm::openCorpses=}s\r\nMainForm::showNotoHue=ܷe⪺CD(,,,,)\r\nMainForm::lblWarnHue=ĵiTC\r\nMainForm::lblMsgHue=RazorTC\r\nMainForm::lblExHue=jѰC\r\nMainForm::blockDis=ԪҦU\r\nMainForm::chkForceSpellHue=j]kGyC:\r\nMainForm::chkForceSpeechHue=jy奻C\r\nMainForm::label3=Gy榡:\r\n\r\nMainForm::displayTab=/p\r\nMainForm::warnCount=pƾCpUƭȮĵi:\r\nMainForm::excludePouches=û۰ʷjp]\r\nMainForm::highlightSpellReags=IkɰG]kħ(D)\r\nMainForm::titlebarImages=DHϧΤ覡ܸ귽\r\nMainForm::checkNewConts=۰ʷjse\r\nMainForm::groupBox3=ܼD\r\nMainForm::showInBar=UODܦpUT:\r\nMainForm::groupBox2=귽pƾ\r\nMainForm::counters::0=W(榡)\r\nMainForm::counters::1=ƶq\r\nMainForm::delCounter=R/s\r\nMainForm::addCounter=sW...\r\nMainForm::recount=sp\r\nMainForm::dressTab=˳/\r\nMainForm::groupBox6=˳/۪~\r\nMainForm::clearDress=MŦC\r\nMainForm::dressDelSel=\r\nMainForm::undressBag=窫s]\r\nMainForm::undressList=h窫\r\nMainForm::dressUseCur=K[e\r\nMainForm::targItem=K[(ؼ)\r\nMainForm::dressNow=˳\r\nMainForm::groupBox5=˳/窫\r\nMainForm::removeDress=\r\nMainForm::addDress=K[...\r\nMainForm::undressConflicts=۰ʲUĬ𪫫~\r\nMainForm::skillsTab=ޯ\r\nMainForm::dispDelta=ܧޯPA\r\nMainForm::skillCopyAll=ƻs\r\nMainForm::skillCopySel=ƻsҿ\r\nMainForm::label1=򥻧ޯM:\r\nMainForm::setlocks=]wޯ:\r\nMainForm::resetDelta=m+/-\r\nMainForm::skillList::0=ޯW\r\nMainForm::skillList::1=ƭ\r\nMainForm::skillList::2=\r\nMainForm::skillList::3=+/-\r\nMainForm::skillList::4=W\r\nMainForm::skillList::5=w\r\nMainForm::agentsTab=Nz\r\nMainForm::hotkeysTab=\r\nMainForm::dohotkey=ҿ\r\nMainForm::groupBox8=\r\nMainForm::chkPass=ǰeUO\r\nMainForm::label2=:\r\nMainForm::unsetHK=]w\r\nMainForm::setHK=]w\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=\r\nMainForm::macroActGroup=ʧ@\r\nMainForm::loopMacro=`\r\nMainForm::recMacro=O\r\nMainForm::playMacro=\r\nMainForm::delMacro=\r\nMainForm::newMacro=إ...\r\nMainForm::screenshotTab=^\r\nMainForm::label12=Ϲ:\r\nMainForm::capNow=ߧY^\r\nMainForm::radioUO=ȭUO\r\nMainForm::radioFull=ù\r\nMainForm::screenAutoCap=`ɦ۰^\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Ϲ]tIɶ\r\nMainForm::videoTab=W\r\nMainForm::recFolder=...\r\nMainForm::label13=WOsƧ:\r\nMainForm::groupBox7=PacketVideoO\r\nMainForm::vidRec=}lOPacketVideo\r\nMainForm::groupBox10=AVIvO\r\nMainForm::flipVidVert=\r\nMainForm::flipVidHoriz=\r\nMainForm::recAVI=}lOAVIv...\r\nMainForm::label16=ѪR:\r\nMainForm::label15=FPS:\r\nMainForm::label19=½:\r\nMainForm::groupBox9=PacketVideo^\r\nMainForm::rpvTime=00:00/00:00\r\nMainForm::label14=t:\r\nMainForm::vidClose=\r\nMainForm::vidPlayStop=\r\nMainForm::vidPlay=\r\nMainForm::vidOpen=}...\r\nMainForm::statusTab=UPA\r\nMainForm::forumsLink=RazorQװ\r\nMainForm::homeLink=RazorD\r\nMainForm::userGuideLink=RazorΤU\r\n\r\nHueEntry::Text=C\r\nHueEntry::cancel=\r\nHueEntry::okay=Tw(&O)\r\nHueEntry::preview=w\r\nHueEntry::inGame=C\r\nHueEntry::label1=CNX:\r\n\r\nAddCounter::Text=K[@ӭpƾ\r\nAddCounter::delete=R\r\nAddCounter::target=ؼ\r\nAddCounter::cancel=\r\nAddCounter::Add=Tw(&O)\r\nAddCounter::label4=C(:-1):\r\nAddCounter::label3=~ID:\r\nAddCounter::label2=榡:\r\nAddCounter::label1=W:\r\n\r\nMacroInsertWait::Text=J/Ȱ...\r\nMacroInsertWait::radioMenu=­檺/ܮ\r\nMacroInsertWait::cancel=(&C)\r\nMacroInsertWait::radioStat=\r\nMacroInsertWait::radioTarg=ݥؼ\r\nMacroInsertWait::radioGump=ݹܮ\r\nMacroInsertWait::label1=ms\r\nMacroInsertWait::radioPause=Ȱ:\r\nMacroInsertWait::insert=J(&I)\r\n\r\nMacroInsertIf::Text=JIf...\r\nMacroInsertIf::label1=If:\r\nMacroInsertIf::cancel=(&C)\r\nMacroInsertIf::insert=J(&I)\r\n\r\nInputBox::cancel=\r\nInputBox::ok=Tw(&O)\r\n\r\n[strings]\r\n1001=`A\r\n1002=uC֤H\r\n1003=sn\r\n1004=ߥsn\r\n1005=sn\r\n1006=ϥsn\r\n1007=Fyn\r\n1008=]kn\r\n1009=Ѯ\r\n1010=ܭpƾ\r\n1011=sp\r\n1012=MAOSO\r\n1013=}ҭO(AOS)\r\n1014=}ҦO(AOS)\r\n1015=}ҷwt(Pre-AOS)\r\n1016=}ҸѰZ(Pre-AOS)\r\n1017=]wO{0}\r\n1018=AOSOw.\r\n1019=UҦ˳\r\n1020=U˳\r\n1021=U˳\r\n1022=Uk˳\r\n1023=UUl\r\n1024=U\r\n1025=^avۤv\r\n1026=^aLastTarget\r\n1027=ϥ^a(Lp)\r\n1028=ϥHeal\r\n1029=ϥCure\r\n1030=ϥRefresh\r\n1031=ϥNight Sight\r\n1032=ϥExplosion\r\n1033=ϥStrength\r\n1034=ϥAgility\r\n1035=o{^a\r\n1036=o{w~{0}!\r\n1037=({0})\r\n1038=swؼ\r\n1039=ഫ\r\n1040=Ӱʧ@ܤ@ӷsؼ.\r\n1041=ĵi:[ӤHtmɮݩʮɵoͷN~:\\n{0}\r\n1042=ĵi:Lk쪫~(WXd).\r\n1043=_{1} - {0}\r\n1044=ഫ_\r\n1045=ĵi:˳ƥ󪫫~.\r\n1046=˳ƨ{0} (L:{1})\r\n1047=ʨ{0} (@{1})\r\n1048=ഫ۹m\r\n1049=(۹)@({0},{1},{2})\r\n1050=ܮT({0})\r\n1051=ܮ\r\n1052=T{0}\r\n1053=ĵi:ݭnؼ,OAoeؼ!(Aݭn@WaitForTarget(ݥؼ)O?)\r\n1054=ؼп\r\n1055=ഫLastTarget\r\n1056=ھܥؼ\r\n1057=sܥؼЦm({0},{1})\r\n1058=LastTarget\r\n1059=TargetSelf\r\n1060=]wLastTarget\r\n1061=VHo(W)\r\n1062=VHäH(ǦW)\r\n1063=VHqH(ŦW)\r\n1064=VHĤH\r\n1065=VHͤH\r\n1066=VHDͤH\r\n1067=\"{0}\"\r\n1068=ϥΧޯ{0}\r\n1069=ϥ]k{0}\r\n1070=ϥίO{0}\r\n1071=˳:{0}\r\n1072=U:{0}\r\n1073=Ѱ˳{0}\r\n1074=ݵ(N)\r\n1075=ݵ(#{0})\r\n1076=s...\r\n1077=ݹܮ(N)\r\n1078=ݹܮ(#{0})\r\n1079=WaitForTarget\r\n1080=Ȱ{0:#.00}\r\n1081={0} {1} {2}\r\n1082=['{0}'...\r\n1083=>e\r\n1084=:{0}\r\n1085=񥨶'{0}'...\r\n1086='{0}'w.\r\n1087=RazorLkl.~NX:\r\n1088=yz:LkȤݵfy`.\\n]:Ȥݥ`l(RazorLkЫبDf,нTOȤݥ`Ұ).\r\n1089=yz:LkȤݶi{ID\\n]:Ȥݥ`l(RazorҰʫLkPȤݱ_,oq`OѩȤݦbҰʹL{ɪYҾɭP,нTOȤݥ`Ұ).\r\n1090=yz:LkЫبtα_.\\n]:f~.\r\n1091=yz:LkЫةŪRazor@ɰO.\\n]:tο~εLĳ\\i.\r\n1092=yz:Crypt.dllwQ۰ʸT.\\n]:(Crypt.dllla,ЭswRazor,åBϥέlCrypt.dll).\r\n1093=yz:LkץWinsock\\.\\n]:~,tο~,ۮeʰD(ЭswRazor{).\r\n1094=yz:LİѼƳQǰe[.\\n]:ǰtDLL󪩥(ЭswRazor{).\r\n1095=ĵi:LkqȤݽƻs]שΥ[KT.\\nRazoriHϥγoǰTӹB,@ǥ\\NLk`B@.AQ~ҰRazor?\\n\\n]:AȤݪPRazorݮe(кɧ֧sRazor5.0.0ΥHWHTOiH`u@).\r\n1096=Aޯ{0}wgF{4}{5:F1},{bO{3:F1}({1}{2:F1}).\r\n1097=LY.\r\n1098=LĪ~ID.\r\n1099=LC.\r\n1100=ܤ@Ӫ~ӭp.\r\n1101=['{0}'~!\\nӭӤHtmɮפwglaåBLkϥ.\r\n1102=ݩ{0}bӭӤHtmɮפLk.\r\n1103=Acounters.xmlwglaåBLkϥ.\r\n1104=]A۰ʮej]wBA,A{bs}Ҧ]HKpƾiHs.\r\n1105=ĵi:{0}ƶq{bO{1}!\r\n1106=ܧAQϥΪC.\r\n1107=ߧY^\r\n1108=iΰѼƩέ:\\n{char} - W\\n{shard} - W\\n{str}/{hp}/{hpmax} - dA\\n{dex}/{stam}/{stammax} - ӱA\\n{int}/{mana}/{manamax} - OA\\n{weight}/{maxweight} - tT\\n{gold} - \\n{AR} - ˥/ O\\n{tithe} - |A\\n{followers}/{followersmax} - Hqƶq̤j\\n{bandage} - ^ap\\n{statbar}/{mediumstatbar}/{largestatbar} - A(p//j)\\n{crimtime} - oǮɶ\\n{stealthsteps} - Bƭpƾ\\n{physresist} - z\\n{coldresist} - BNܩ\\n{fireresist} - ܩ\\n{energyresist} - qܩ\\n{poisonresist} - rܩ\\n{luck} - B\\n{damage} - ˮ` Min-Max(̤p-̤j)\\nC - HTML16iNX:'~#rrggbb'(J'~#~'CNX)\\nΪ̱qpƾCϥ{Format}榡\r\n1109={:{0}\\nsϥ:{1}\\noe:{2} ({3}/s)\\n:{4} ({5}/s)\\nsɶ:{6}\\naǸ:0x{7:X8}\\nI]Ǹ:0x{8:X8}\\nܪ~:{9}\\nܥͪ:{10}\\n\\nc餤:Cloud (linhongjun@hotmail.com)\\nsɶ:2007/03/11\\n`Nƶ:pYǰTX{~εLk(p]kW,ޯW),ХΤ奻sn󥴶}Razor\\Language\\URazor_lang.chs\\ŪԲӻ.\r\n1110=]wޯ:W\r\n1111=]wޯ:U\r\n1112=]wޯ:w\r\n1113=AT{npƾ\"{0}\"?\\noN|vTҦӤHtmɮ.\r\n1114={b[ӤHtmɮ\"{0}\"?\r\n1115=ŪӤHtmɮ׮ɵoͿ~.\r\n1116=AiHRw]ӤHtmɮ.\r\n1117=JsӤHtmɮתW:\r\n1118=LkЫطsӤHtmɮ!\\n]:ӭӤHtmɮפwsb.\\n\\nAQ{bN[ӭӤHtmɮ׶?\r\n1119=Js窫CW:\r\n1120=RӦ窫C?\r\n1121={0:X}(~WXd)\r\n1122=q窫CRӪ~?\r\n1123=ܤ@ӥ]ΨӨUC'{0}'~.\r\n1124=]wU~s].\r\n1125=~,οܤFLĪ~.\r\n1126=զXwgsb'{0}'.\\nݭnאּ'{1}'?\r\n1127=Ʀ\\Os.\r\n1128=ĵi!\\nOƥ]i|CRazorʯ.O|vWj,ORazor|۰ʲ.\\n\\nRazorưOi|]tӤHTҦpKX,åBoǤӵAHH.\\n\\nAT{n}Ҹƥ]O?\\n(oӤ|OsAӤHtmɮפ)\r\n1129=Nܪؼഫ\r\n1130=JsW:\r\n1131=ӦW٥]tLĦr.\r\n1132=PWwsb.\r\n1133=ӥbOeN|QM.\\nAT{nNOл\\ӥ?\r\n1134=AT{nä[R'{0}'?\\n(oNOifާ@)\r\n1135=JȰ/...\r\n1136=J]wLastTarget\r\n1137=W\r\n1138=U\r\n1139=ʧ@\r\n1140=}lO\r\n1141='{0}'.\r\n1142=AT{?\r\n1143=ĵi:HU{0}{1}LkQR:\\n{2}\r\n1144=N|bUҰRazorɥͮ.\r\n1145=}Ҹӳ]wN|ɭPRazorOsAKXӤHtmɮפ.\\nޱKXwgQ[K,LHMi.\\nAT{n}Ҹӥ\\?\r\n1146=Aw@ӦĪf.\r\n1147=ʧ@ШD(wgB󶤦C).\r\n1148=Cʧ@ШD{0}...{1}Ѿl.\r\n1149={0}ӶCʧ@{1:F1}.\r\n1150=UseOnceNz\r\n1151=K[(ؼ)...\r\n1152=K[e(ؼ)...\r\n1153=(ؼ)...\r\n1154=MŦC\r\n1155=V@Ӫ~HK[.\r\n1156=V@Ӯe.\r\n1157=V@Ӫ~H.\r\n1158=~wK[.\r\n1159=~w.\r\n1160={0}Ӫ~wgK[UseOnceNz.\r\n1161=UseOnceCw!\r\n1162=ϥ'{0}'.({1}Ӫ~dUseOnceC)\r\n1163=AYUseOnce~sbD,դU@.\r\n1164=cNz:۰ʥH{1}gpc{0}Ӫ~.\r\n1165=\r\n1166=e]w\\.\r\n1167=M\r\n1168=(HT)\r\n1169=(H})\r\n1170=]w]\r\n1171=M]\r\n1172=zNz\r\n1173=z\r\n1174={bz\r\n1175=e]w.\r\n1176=RazorLkAI].\r\n1177=zNzo{{0}Ӫ~ݭn.(oݭn@Ǯɶ)\r\n1178=zNzLkiHʪ~.\r\n1179=Ӫ~wBC.\r\n1180=۰ʷjѰ\r\n1181=ʶRNzH{1}gpʶR{0}Ӫ~.\r\n1182=ʶRNzLkʶRAC@Ǫ~,]AS.\r\n1183=Jƶq:\r\n1184=Ȥݵ{uv]w{0}\r\n1185=eɶO:{0}\r\n1186=AҳBme{0},'{1}'\r\n1187=U]o{ζWXd,ϥέI]N.\r\n1188={0}Ӫ~B󶤦CNQU.\r\n1189={0}Ӫ~B󶤦CNQ˳.\r\n1190={0}Ӫ~w˳.\r\n1191={0}Ӫ~o{.(WXd)\r\n1192=ĵi:Spells.def󥼧,]kGy榡奻N|.\r\n1193=B:{0}\r\n1194={bOB.\r\n1195=MؼжC\r\n1196=̫ѥ[԰\r\n1197=ؼжCwM.\r\n1198=V@ӷsLastTarget\r\n1199=LastTargetw]w.\r\n1200=sؼФw]w.\r\n1201=ŦX󤧥ؼЩù.\r\n1202=C[JTargetSelf.\r\n1203=C[JLastTarget.\r\n1204=Aoesؼ,Razor]wؼ.\r\n1205=]wؼ{0}\r\n1206=MD\r\n1207=AT{nRoӶ?\r\n1208=ܤ@ӸƧxs^.\r\n1209=\r\n\r\n1210=~\r\n1211=ؼ\r\n1212=Nz\r\n1213=窫\r\n1214=\r\n1215=]k\r\n1216=ޯ\r\n1217=\r\n1251=1st\r\n1252=2nd\r\n1253=3rd\r\n1254=4th\r\n1255=5th\r\n1256=6th\r\n1257=7th\r\n1258=8th\r\n1260=Ův\r\n1270=Mh\r\n1271=Ĥ\r\n1272=S\r\n1290=Zh\r\n1300=Ԫ\r\n1301=\r\n1302=R\r\n1303=ݭnJ\r\n1304=RazorOC\r\n1305=ϥΤ⤤~\r\n1306=bA˳ƤeAU@Ǹ˳.\r\n1307=˳/Uk⪫~\r\n1308=˳/U⪫~\r\n1309=UeϥΤ~\r\n1310=A˳ƥ󪫫~.\r\n1311=>}/TRazor\r\n1312=w}( {0} T)\r\n1313=wT( {0} })\r\n1314=w}\r\n1315=wT\r\n1316=樫:{0}\r\n1317=K[(ؼ)...\r\n1318=ШDؼжWXd,LastTargetO|Q!\r\n1319=̤jƶq:{0}\r\n1320=sT\r\n1321=I]\r\n1322=J\"If\"\r\n1323=J\"Else\"\r\n1324=J\"End If\"\r\n1325=]wƶq\r\n1326=ɵ\r\n1327={bɵ\r\n1328=ɵNz\r\n1329=V@ӮeӸɵΫVۤvӨϥλȦ.\r\n1330=ؼЮeL.\r\n1331=ɵ,w[JC{0}~{1}.\r\n1332=eؼ\r\n1333={n󪺷s.\\n\\nAQXRazoräUs{?\r\n1334=s[\r\n1335=Os\r\n1336=ĵi:eؼФ\\ANؼЫVa.LastTargetON|ͮ.\r\n1337=sPBȤ\r\n1338=UQ.\r\n1339=}lRazor\"PacketVideo\"s\r\n1340=\"PacketVideo\"s/\r\n1341=}lsɵoͿ~.\\nN~wgQO.\r\n1342=Ӥ󤣾AΩ󦹪{.T{Aww˳̷sRazor.\r\n1343=Ӽvwla.\\niण,ΤwgQק.\\nӤLk.\r\n1344=ŪɵoͿ~.ӤiwlaΤ.\r\n1345=JOW:\r\n1346=ؿLkQR.TOӥؿ.\r\n1347=LkЫإؿ.TOAJOTMAs.\r\n1348=Lkʥ.TOAJOOĪ.\r\n1349=n\r\n// 1350 to 1359 reserved (max length 15!)\r\n1350=w\r\n1351=\r\n1352=C?\r\n1353=QF\r\n1354=QzF?\r\n1355=QAF\r\n1356=QFF?\r\n1357=өBF!\r\n1358=AJF\r\n1359=!\r\n1360=V@Ӫaå[JnͦC.\r\n1361=V@ӪañqnͦC.\r\n1362=nͤwK[.\r\n1363=nͤw.\r\n1364=Scy\r\n1365=J\"For Loop\"\r\n1366=J\"End For\"\r\n1367=JƦ:\r\n1368=MŲMDҪws\r\n1369=LastSpell(̫]kGy)\r\n1370=LastSkill(̫ޯ)\r\n1371=LastObject(̫ؼ)\r\n1372=AllNames(ܩҦH/ͪW)\r\n1373=UseOnce\r\n1374=VHĹH\r\n1375=VHäH\r\n1376=VHLoH\r\n1377=VHoǤH\r\n1378=VHo\r\n1379=ĵi:W!⤤~JI].\r\n1380=AsҰRazorMȤݨӽTOͮ.\r\n1381=AnXC,M᭫snJ~TOͮ.\r\n1382=ШDC{0}...{1}Ѿl.\r\n1383=ɵШDi椤...\r\n1384=AOqwgF{0}{1},{bO{2}.\r\n1385=AӱwgF{0}{1},{bO{2}.\r\n1386=AOwgF{0}{1},{bO{2}.\r\n1387=ŧO\r\n1388=vQ(ؼФwr)!\r\n1389=Mũ񶤦C\r\n1390={b\r\n1391=>v/v¡ۤv\r\n1392=NextTarget\r\n1393=]wɵ]\r\n1394=K[UseOnce\r\n1395=LastTarget\r\n1396=sW...\r\n1397=Ae󪫫~.\r\n1398=\\\r\n1399=\\\r\n1400=PAӪS:\r\n1401=ҦSʳQ\\.\r\n1402=ѮLo\r\n1403=ŧOLo\r\n1404=LastTarget\r\n1405=d˴LastTarget\r\n1406=۰ʶ}\r\n1407=Ikɨ˳\r\n1408=۰ʨϥĤ,˳\r\n1409=rɪv\r\n1410=`\r\n1411=UseOnceNz\r\n1412=ɵNz\r\n1413=PNz\r\n1414=ʶRNz\r\n1415=Ĥ\r\n1416=Hؼ\r\n1417=d/A\r\n// up to 1465: reserved\r\n1466=SʤQA\\\r\n1467=ӯSʳQeCAT.\\nAiHܩAҤ\\S,iHb]wҤUi]w.\\n\\ndݳQTSʦC,ЦbUPAҤU]w.\r\n1468=J\r\n1469=K[n\r\n1470=n\r\n1471=>gAv¡/vۤv\r\n1472=pGAbϥΤwѱKȤ,AӸT\"[K\"\\.ӥ\\ȭϥΦbݭnȤݥ[KA(ҦpOSI/EAxA).\\npGATwӦp,ФnܸӶ.\\n\\nATwnȤݸѱK?\r\n1473=U\r\n1474=/æaϵ\r\n1475=Zӻ.\r\n1476=񶤦Cw!еy.\r\n1477=԰/MҦ\r\n1478=ܮ\r\n1479=wCjpL,Эs.\r\n1480=(MDҥ])\r\n1481=(ɵNz] {0})\r\n1482=(UseOnceNz #{0})\r\n1483=(cNz])\r\n1484=(zNz {0} ])\r\n1485=AwAa}LkѪR,нT{a}JO_T.\r\n1486=ζ:ܽ\r\n1487=ζ:ڵܽ\r\n1488=͵ؼ\r\n1489=Ĺؼ\r\n1490=(Razorn)\r\n1491=qBi\r\n1492=lƤ...\r\n1493=b[̷sӤHtmɮ...\r\n1494=b[Ȥ...\r\n1495=ݫȤݱҰʤ...\r\n1496=Oo٧U!\r\n1497=wϥRazor!\r\n1498=2DȤ(۰ʰ)\r\n1499=3DȤ(۰ʰ)\r\n1500=(۰ʰ)\r\n1501=z: {0}%\r\n1502=ЫwӰʧ@Wɮɶ():\r\n1503=w\r\n1504=W\r\n1505=JW\r\n1506=L.\r\n1507=u~\r\n1508={0} A\r\n1509=γQI]īG\r\n1510=V̪\r\n1511=V̪äH\r\n1512=V̪񴶳qH\r\n1513=V̪ĤH\r\n1514=V̪ͤH\r\n1515=V̪DͤH\r\n1516=V̪ĹHΪ\r\n1517=V̪iäHΪ\r\n1518=V̪񴶳qHΪ\r\n1519=V̪ǸoHΪ\r\n1520=V̪o\r\n1521=ĵi:tmɮ'{0}'bQ䥦Razor{i{ҨϥΤ!\\npGAɮ׶iFק,i०wgla.ĳAbC@Razor{i{ϥοWߪ(ΤP)ӤHtmɮ.\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.deu",
    "content": "// Razor English/DEU Language Pack\r\n// Last modified $Date: 2006/01/17 22:02:20 $\r\n::CliLoc=DEU\r\n\r\n[controls]\r\nWelcomeForm::Text=Willkommen bei Razor!\r\nWelcomeForm::groupBox3=UO Data Ordner\r\nWelcomeForm::dataBrowse=Suchen...\r\nWelcomeForm::label5=Sprache:\r\nWelcomeForm::groupBox2=Server\r\nWelcomeForm::label3=Server:\r\nWelcomeForm::label4=Port:\r\nWelcomeForm::groupBox1=Client Optionen\r\nWelcomeForm::useEnc=Benutze OSI Verschluesselung\r\nWelcomeForm::makeDef=Zu Standardeinstellungen machen\r\nWelcomeForm::browse=Suchen...\r\nWelcomeForm::label1=Welchen Client laden?:\r\nWelcomeForm::patchEncy=Client Verschluesselung patchen\r\nWelcomeForm::showAtStart=Startanzeige\r\nWelcomeForm::quit=&Beenden\r\nWelcomeForm::okay=&Okay\r\n\r\nMainForm::Text=Razor v{0}\r\nMainForm::generalTab=Allgemein\r\nMainForm::label10=Updatepruefung:\r\nMainForm::systray=System Tray\r\nMainForm::taskbar=Taskbar\r\nMainForm::smartCPU=Nutze intelligente CPU-Auslastung\r\nMainForm::label7=Sprache:\r\nMainForm::label11=Anzeigen in:\r\nMainForm::groupBox4=Profile\r\nMainForm::delProfile=Loeschen\r\nMainForm::newProfile=&Neu...\r\nMainForm::showWelcome=Willkommens-Nachricht anzeigen?\r\nMainForm::alwaysTop=Nutze intelligentes \"Immer im Vordergrund\"\r\nMainForm::groupBox1=Filter\r\nMainForm::opacityLabel=Sichtbarkeit: 100%\r\nMainForm::moreMoreOptTab=Mehr Optionen\r\nMainForm::blockHealPoison=Heilen blockieren wenn Ziel vergiftet\r\nMainForm::potionEquip=Auto-freimachen Haende fuer Traenke\r\nMainForm::label17=Razor Meldungen:\r\nMainForm::QueueActions=Auto-Warteschl. fuer Aktionen \r\nMainForm::spellUnequip=autom.es Haendefreimachen zum Zaubern\r\nMainForm::autoOpenDoors=Tueren autom. oeffnen\r\nMainForm::alwaysStealth=Immer Unsichtbar Laufen \r\nMainForm::autoFriend=Partymitglieder sind 'Freunde'\r\nMainForm::chkStealth=Unsichtbare Laufschritte zaehlen\r\nMainForm::rememberPwds=Passwort merken \r\nMainForm::showtargtext=Zielzustand mit Einzelklick anzeigen\r\nMainForm::preAOSstatbar=altes Vor-AOS-Statusfenster benutzen\r\nMainForm::logPackets=Paketspeicherung aktivieren\r\nMainForm::rangeCheckLT=Entfernung zu 'letztes Ziel' ueberpruefen:\r\nMainForm::actionStatusMsg=Aktions-Warteschl. Meldungen anzeigen\r\nMainForm::label5=Gegenstandsverzoegerung:\r\nMainForm::label9=Standard Client-CPU-Prioritaet:\r\nMainForm::label8=tiles\r\nMainForm::label6=ms\r\nMainForm::label18=x\r\nMainForm::gameSize=Fenstergroesse erzwingen:\r\nMainForm::smartLT=Benutze intelligentes 'letztes Ziel'\r\nMainForm::moreOptTab=Optionen\r\nMainForm::negotiate=Funktionen mit Server aushandeln\r\nMainForm::setLTHilight=Setze\r\nMainForm::lthilight='letztes Ziel' Hervorhebung:\r\nMainForm::filterSnoop=Schnueffler-Text filtern\r\nMainForm::incomingCorpse=Neue Leichennamen anzeigen\r\nMainForm::incomingMob=Sich naehernde Spieler/Monster anzeigen\r\nMainForm::setHarmHue=Setze\r\nMainForm::setNeuHue=Setze\r\nMainForm::lblHarmHue=Boese\r\nMainForm::lblNeuHue=Neutral\r\nMainForm::lblBeneHue=Gut\r\nMainForm::setBeneHue=Setze\r\nMainForm::setSpeechHue=Setze\r\nMainForm::setWarnHue=Setze\r\nMainForm::setMsgHue=Setze\r\nMainForm::setExHue=Setze\r\nMainForm::autoStackRes=Auto-Stapeln von Fisch und Erz vor Spielfigur\r\nMainForm::queueTargets=Warteschl. 'Selbstziel' und 'Letztes Ziel'\r\nMainForm::spamFilter=Systemmeldungsspam filtern\r\nMainForm::label4=tiles\r\nMainForm::openCorpses=oeffne Leichen Umkreis:\r\nMainForm::showNotoHue=Status des Spielers im Fensterbalken\r\nMainForm::lblWarnHue=Warnungsmeldungen\r\nMainForm::lblMsgHue=Razormeldungen\r\nMainForm::lblExHue=Such-Ausnahme\r\nMainForm::blockDis=Absatteln im Kampf blocken\r\nMainForm::chkForceSpellHue=Zauberworte:\r\nMainForm::chkForceSpeechHue=Gesprochener Text\r\nMainForm::label3=Zauber-Format:\r\nMainForm::displayTab=Anzeige/Zaehler\r\nMainForm::warnCount=Warnen wenn Zaehler unter Wert faellt:\r\nMainForm::excludePouches=Beutel nie autom. durchsuchen\r\nMainForm::highlightSpellReags=Reagenzien beim Zaubern zeigen\r\nMainForm::titlebarImages=Zaehler mit Bildchen anzeigen\r\nMainForm::checkNewConts=Neue Behaelter autom. durchsuchen\r\nMainForm::groupBox3=Fensterbalkenanzeige\r\nMainForm::showInBar=Dies im UO-Fensterbalken anzeigen:\r\nMainForm::groupBox2=Zaehler\r\nMainForm::delCounter=Loeschen/Bearbeiten\r\nMainForm::addCounter=Hinzufuegen...\r\nMainForm::recount=Neu zaehlen\r\nMainForm::dressTab=Bewaffnen/Ankleiden\r\nMainForm::groupBox6=Bewaffnen/Ankleiden mit diesen Gegenstaenden\r\nMainForm::clearDress=Liste leeren\r\nMainForm::dressDelSel=Entfernen\r\nMainForm::undressBag=Kleiderbeutel aendern\r\nMainForm::undressList=Entkleiden\r\nMainForm::dressUseCur=Derzeitigen Behaelter hinzufuegen\r\nMainForm::targItem=Hinzufuegen (Ziel)\r\nMainForm::dressNow=Ankleiden\r\nMainForm::groupBox5=Bewaffnen/Ankleiden Auswahl\r\nMainForm::removeDress=Entfernen\r\nMainForm::addDress=Hinzufuegen...\r\nMainForm::undressConflicts=autom. kollidierende Gegenstaende entfernen\r\nMainForm::skillsTab=Faehigkeiten\r\nMainForm::dispDelta=Faehigkeits- und Statistikaenderungen anzeigen\r\nMainForm::skillCopyAll=Alle kopieren\r\nMainForm::skillCopySel=Ausgewaehlte kopieren\r\nMainForm::label1=Basis Gesamt:\r\nMainForm::setlocks=Alle Schloesser setzen:\r\nMainForm::resetDelta=Zuruecksetzen  +/-\r\nMainForm::agentsTab=Agenten\r\nMainForm::hotkeysTab=Funktionstasten\r\nMainForm::dohotkey=Auswahl ausfuehren\r\nMainForm::groupBox8=Funktionstaste\r\nMainForm::chkPass=An UO uebertragen\r\nMainForm::label2=Taste:\r\nMainForm::unsetHK=Loeschen\r\nMainForm::setHK=Setze\r\nMainForm::chkCtrl=Strg\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Makros\r\nMainForm::macroActGroup=Aktionen\r\nMainForm::loopMacro=Wiederholung\r\nMainForm::recMacro=Aufnehmen\r\nMainForm::playMacro=Wiedergeben\r\nMainForm::delMacro=Entfernen\r\nMainForm::newMacro=Neu...\r\nMainForm::screenshotTab=Bildschirmfotos\r\nMainForm::label12=Bildformat:\r\nMainForm::capNow=Jetzt ein Bildschirmfoto machen\r\nMainForm::radioUO=Nur das UO Fenster\r\nMainForm::radioFull=Gesamter Bildschirm\r\nMainForm::screenAutoCap=autom.es Bildschirmfoto bei Tod\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Zeit-/Datumsstempel aktivieren\r\nMainForm::videoTab=Videoaufnahme\r\nMainForm::recFolder=...\r\nMainForm::label13=Aufnahme-Ordner:\r\nMainForm::groupBox7=PacketVideo Aufnahme\r\nMainForm::vidRec=PacketVideo Aufnehmen\r\nMainForm::groupBox10=AVI Video Aufnahme\r\nMainForm::flipVidVert=Vetikal\r\nMainForm::flipVidHoriz=Horizontal\r\nMainForm::recAVI=Record AVI Video...\r\nMainForm::label16=Aufloesung:\r\nMainForm::label15=Bilder pro Sekunde:\r\nMainForm::label19=Drehen:\r\nMainForm::groupBox9=PacketVideo Wiedergabe\r\nMainForm::label14=Geschicklichkeit:\r\nMainForm::vidClose=Schliessen\r\nMainForm::vidPlayStop=Stop\r\nMainForm::vidPlay=Wiedergabe\r\nMainForm::vidOpen=oeffnen...\r\nMainForm::statusTab=Hilfe && Status\r\nMainForm::forumsLink=Razor Diskussionsforum\r\nMainForm::homeLink=Razor Website\r\nMainForm::userGuideLink=Razor Gebrauchsanweisung (engl.)\r\n\r\nHueEntry::Text=Einfaerbung auswaehlen\r\nHueEntry::cancel=Abbrechen\r\nHueEntry::okay=&Okay\r\nHueEntry::preview=Vorschau\r\nHueEntry::inGame=im Spiel auswaehlen\r\nHueEntry::label1=Farbe Nummer:\r\n\r\nAddCounter::Text=Zaehler hinzufuegen\r\nAddCounter::delete=Loeschen\r\nAddCounter::target=Ziel \r\nAddCounter::cancel=Abbrechen\r\nAddCounter::Add=&Okay\r\nAddCounter::label4=Farbe (Egal: -1):\r\nAddCounter::label3=Gegenstands ID:\r\nAddCounter::label2=Format:\r\nAddCounter::label1=Name:\r\n\r\nMacroInsertWait::Text=Warten/Pause einfuegen...\r\nMacroInsertWait::radioMenu=Warte auf altes Menue/Dialog\r\nMacroInsertWait::cancel=&Abbrechen\r\nMacroInsertWait::radioStat=Warte auf \r\nMacroInsertWait::radioTarg=Warte auf Ziel\r\nMacroInsertWait::radioGump=Warte auf Fenster\r\nMacroInsertWait::label1=Millisekunden\r\nMacroInsertWait::radioPause=Pausieren fuer:\r\nMacroInsertWait::insert=&Einfuegen\r\n\r\nMacroInsertIf::Text=Einfuegen 'Wenn'...\r\nMacroInsertIf::label1=Wenn:\r\nMacroInsertIf::cancel=&Abbrechen\r\nMacroInsertIf::insert=&Einfuegen\r\n\r\n[strings]\r\n1001=Tod Graufaerbung\r\n1002=Bardenmusik\r\n1003=Hundegeraeusche\r\n1004=Katzengeraeusche\r\n1005=Pferdegeraeusche\r\n1006=Schafgeraeusche\r\n1007=Geistersprachegeraeusche\r\n1008=Zauberfehlschlaggeraeusche\r\n1009=Wetter\r\n1010=Zaehler anzeigen\r\n1011=Zaehler neu zaehlen\r\n1012=AOS Faehigkeiten abschalten\r\n1013=Erste Faehigkeit setzen (AOS)\r\n1014=Zweite Faehigkeit setzen (AOS)\r\n1015=Betaeubungsschlag an/aus (Pre-AOS)\r\n1016=Entwaffnen an/aus (Pre-AOS)\r\n1017=Faehigkeit gesetzt auf {0}\r\n1018=AOS Faehigkeiten deaktiviert.\r\n1019=Alles Entkleiden\r\n1020=Beide Haende leeren\r\n1021=Linke Hand leeren\r\n1022=Rechte hand leeren\r\n1023=Hut entkleiden\r\n1024=Schmuck entkleiden\r\n1025=Selbstbandagieren\r\n1026=Bandage an 'letztes Ziel' benutzen\r\n1027=Benutze Bandage (keine Zeitbegrenzung)\r\n1028=Heiltrank trinken\r\n1029=Entgiftungstrank trinken\r\n1030=Erfrischungstrank trinken\r\n1031=Nachtsichttrank trinken\r\n1032=Explosionstrank benutzen\r\n1033=Staerketrank trinken\r\n1034=Geschicklichkeitstrank trinken\r\n1035=Keine Bandagen gefunden!\r\n1036=Keinen Gegenstand des Typs {0} gefunden!\r\n1037=Doppelklick ({0})\r\n1038=Ziel neu bestimmen\r\n1039=Zu Doppelklick-Typ konvertieren\r\n1040=Neues Ziel fuer diese Aktion auswaehlen.\r\n1041=WARNUNG: Ausnahmefehler beim Laden dieser Einstellung:\\n{0}\r\n1042=Makro-Warnung: Der Gegenstand ist ausser Reichweite!\r\n1043=Aufheben {1} - {0}\r\n1044=Konvertiere zu Aufheben nach Typ\r\n1045=Makro-Warnung: Du hast nichts in den Haenden!\r\n1046=Wohin ankleiden/bewaffnen {0} (L:{1})\r\n1047=Wohin ablegen {0} (@{1})\r\n1048=Konvertiere zu relativer Position\r\n1049=Ablegen (relativ) @({0},{1},{2})\r\n1050=Dialogantwort (Knopf {0})\r\n1051=Dialog schliessen\r\n1052=Menueantwort {0}\r\n1053=Warnung: Das Makro hat nach einem Ziel verlangt, aber der Server hat keins uebertragen! (Brauchst Du ein 'AufZielWarten'?)\r\n1054=Konkretes Ziel\r\n1055=Zu 'letztes Ziel' konvertieren\r\n1056=Zu 'Ziel nach Typ' konvertieren\r\n1057=Relative Position anvisieren ({0},{1})\r\n1058=Letztes Ziel\r\n1059=Selbstziel\r\n1060=Setze Letztes Ziel\r\n1061=Ziel auf zufaelligen roten Spieler\r\n1062=Ziel auf zufaelligen grauen Spieler\r\n1063=Ziel auf zufaelligen blauen Spieler\r\n1064=Ziel auf zufaelligen Feind\r\n1065=Ziel auf zufaelligen Freund\r\n1066=Ziel auf zufaelligen Aggressor\r\n1067=Sprich \"{0}\"\r\n1068=BenutzeFaehigkeit {0}\r\n1069=BenutzeZauber {0}\r\n1070=SetzeFaehigkeit {0}\r\n1071=Ankleiden: {0}\r\n1072=Entkleiden: {0}\r\n1073=Ebene abruesten {0}\r\n1074=Auf Menue warten (Egal)\r\n1075=Auf Menue warten (#{0})\r\n1076=Bearbeiten...\r\n1077=Auf Dialogabfrage warten (Egal)\r\n1078=Auf Dialogabfrage warten (#{0})\r\n1079=Warte auf Ziel\r\n1080=Pause {0:#.00}sek\r\n1081=Warte auf {0} {1} {2}\r\n1082=Laedt '{0}'...\r\n1083=> Laufendes Makro anhalten\r\n1084=Wiedergabe: {0}\r\n1085=Makro laeuft '{0}'...\r\n1086=Makro '{0}' beendet.\r\n1087=Razor konnte das nicht durchfuehren.  Fehlermeldung:\\n\r\n1088=Beschreibung: Could not find the client Window Handle.\\nPossible Cause: The Client may not have initialized properly.\r\n1089=Beschreibung: Could not find the Client's ThreadID\\nPossible Cause: The Client may not have initialized Properly.\r\n1090=Beschreibung: Could not create Windows Hooks.\\nPossible Cause: Internal error.\r\n1091=Beschreibung: Could not create or access Razor shared memory.\\nPossible Cause: Windows Error or invalid permissions.\r\n1092=Beschreibung: Crypt.dll has disabled itself.\\nPossible Cause: Version mismatch.\r\n1093=Beschreibung: Could not patch the client's Winsock functions.\\nPossible Cause: Internal error, Windows Error, or Incompatible Version.\r\n1094=Beschreibung: An invalid parameter was passed to the loade.\\nPossible Cause: Mismatched DLL versions.\r\n1095=Warnung: Could not copy packet lengths and/or encryption information from the client.\\nRazor may be able to run without this information, though some features may not function correctly.  Would you like to start Razor anyway?\\n\\nPossible Cause: Your client version may not be compatible with this version of Razor.\r\n1096=Deine Faehigkeit in {0} hat sich um {4}{5:F1} geaendert, sie ist jetzt bei {3:F1} ({1}{2:F1}).\r\n1097=Nicht erlaubte Abkuerzung.\r\n1098=Nicht erlaubte Gegenstands ID.\r\n1099=Nicht erlaubte Farbe.\r\n1100=Waehle einen Gegenstand aus, der gezaehlt werden soll.\r\n1101=Fehler beim Laden von '{0}'!\\nDieses Benutzerprofil ist fehlerhaft und nicht mehr benutzbar.\r\n1102=Die Eigenschaft {0} wurde in diesem Profil nicht gefunden.\r\n1103=Deine counters.xml Datei ist fehlerhaft und unbenutzbar.\r\n1104=Da Du 'autom.es Durchsuchen' deaktiviert hast, musst Du jetzt alle Behaelter oeffnen, damit sie katalogisiert werden koennen.\r\n1105=ACHTUNG: Die Anzahl von {0} ist jetzt bei {1}!\r\n1106=Waehle die Farbe aus, die Du dafuer benutzen moechtest.\r\n1107=Jetzt Bildschirmfoto machen\r\n1108=Moegliche Werte:\\n{char} - Figurname\\n{shard} - Servername\\n{str}/{hp}/{hpmax} - Gesundheitsstatus\\n{dex}/{stam}/{stammax} - Geschicklichkeitsstatus\\n{int}/{mana}/{manamax} - Intelligenzstatus\\n{weight}/{maxweight} - Gewicht\\n{gold} - Goldvermoegen der Spielfigur\\n{AR} - Ruestungsklasse / Koerperliche Resistenz\\n{tithe} - Zehntelpunkte\\n{followers}/{followersmax} - Gefolgsleute\\n{bandage} - Bandagencountdown\\n{statbar}/{mediumstatbar}/{largestatbar} - Statusanzeige\\n{crimtime} - Wie lange du schon 'kriminell' bist\\n{stealthsteps} - Zaehler fuer Unsichtbare Schritte\\n{physresist} - Koerperliche Resistenz\\n{coldresist} - Kaelteresistenz\\n{fireresist} - Feuerresistenz\\n{energyresist} - Energieresistenz\\n{poisonresist} - Giftresistenz\\n{luck} - Glueck\\n{damage} - Schaden Min./Max.\\nFarbe - HTML hex color code: '~#rrggbb' ('~#~' zum beenden des codes)\\nOder ein {Format} aus der Liste der Zaehler\r\n1109=Razor Version: {0}\\nArbeitsspeichernutzung: {1}\\nSenden: {2} ({3}/s)\\nEmpfangen: {4} ({5}/s)\\nVerbunden seit {6}\\n\\nSpielfigurnummer: 0x{7:X8}\\nGepaecknummer: 0x{8:X8}\\n\\nGegenstaendeueberwachung: {9}\\nMonsterueberwachung: {10}\\n\r\n1110=Setze Schloss: RAUF\r\n1111=Setze Schloss: RUNTER\r\n1112=Setze Schloss: GESCHLOSSEN\r\n1113=Bist Du sicher, dass Du den Zaehler \"{0}\" entfernen willst?\\nDies hat Auswirkung auf alle Profile.\r\n1114=Lade jetzt das Profil \"{0}\"?\r\n1115=Beim Laden des Profils ist ein Fehler aufgetreten.\r\n1116=Das Standardprofil kann nicht geloescht werden.\r\n1117=Gib einen neuen Namen fuer das Profil ein: \r\n1118=Kann kein neues Profil erstellen!\\n Grund: Dieser Profilname existiert bereits.\\n\\nMoechtest Du dieses Profil jetzt laden?\r\n1119=Gib einen Namen fuer die neue Bekleidungsliste ein:\r\n1120=Diese Bekleidungsliste loeschen?\r\n1121={0:X} (Gegenstand ausser Reichweite)\r\n1122=Diesen Gegenstand aus der Bekleidungsliste entfernen?\r\n1123=Klicke auf einen Behaelter, in den die Bekleidungsliste '{0}' entkleidet werden soll.\r\n1124=Entkleidungsbehaelter gesetzt.\r\n1125=Gegenstand nicht gefunden oder nicht erlaubter Gegenstand ausgewaehlt.\r\n1126=Diese Tastenkombination ist bereits dafuer in Benutzung: '{0}'.\\nIn '{1}' aendern?\r\n1127=Daten erfolgreich gespeichert.\r\n1128=WARNUNG!\\nPaketspeicherung kann die Geschicklichkeit von Razor reduzieren. Log Dateien koennen auch sehr schnell sehr gross werden\\n, und Razor loescht diese nicht selbstaendig.\\n\\nRazor's Paketspeicherung kann sensible Daten wie z.B. Passwoerter enthalten\\, und sollte daher nicht an unvertrauenswuerdige Personen gegeben werden.\\n\\nBist Du sicher, dass Du Paketspeicherung aktivieren willst?\\n(Dies wird nicht in Deinem Benutzerprofil gespeichert)\r\n1129=Konvertiere zu Auswahl nach TYP\r\n1130=Gib einen neuen Namen fuer das Makro ein: \r\n1131=Dieser Name enthaelt nicht erlaubte Zeichen.\r\n1132=Ein Makro mit diesem Namen existiert bereits.\r\n1133=Das Makro wird beim Aufnehmen ueberschrieben.\\nBist Du sicher, dass Du dieses Makro ueberschreiben willst?\r\n1134=Bist Du sicher, dass du '{0}' PERMANENT loeschen willst?\\n(Dies kann nicht rueckgaengig gemacht werden)\r\n1135=Pause/Warten einfuegen...\r\n1136=Setze 'letztes Ziel' einfuegen\r\n1137=Nach oben verschieben\r\n1138=Nach unten verschieben\r\n1139=Aktion entfernen\r\n1140=Aufnahme hier starten\r\n1141=Die Datei '{0}' wurde nicht gefunden.\r\n1142=Bist Du sicher?\r\n1143=Warnung: {0} Datei{1} konnte nicht geloescht werden:\\n{2}\r\n1144=Diese aenderung wird erst nach einem Neustart von Razor wirksam.\r\n1145=Die Aktivierung dieser Option veranlasst Razor zur Speicherung Deines Passworts als Teil des Profils.\\nObwohl Passwoerter verschluesselt sind, kann jemand es entschluesseln, falls er/sie Zugriff zu den XML-Dateien Deines Profils erlangt.\\nBist Du sicher, dass Du diese Option einschalten moechtest?\r\n1146=Du musst einen gueltigen Port eingeben.\r\n1147=Aktionsbefehl ignoriert (zur Warteschl. hinzugefuegt).\r\n1148=Aktion in Warteschl. {0}... {1} uebrig.\r\n1149={0} Aktionen aus der Warteschl. in {1:F1} Sekunden abgearbeitet.\r\n1150=Einmal-Benutzen Agent\r\n1151=Hinzufuegen (Ziel)...\r\n1152=Hinzufuegen Behaelter (Ziel)...\r\n1153=Entfernen (Ziel)...\r\n1154=Liste leeren\r\n1155=Klicke auf einen Gegenstand, der hinzugefuegt werden soll.\r\n1156=Klicke auf einen Behaelter.\r\n1157=Klicke auf einen Gegenstand, der entfernt werden soll.\r\n1158=Gegenstand hinzugefuegt.\r\n1159=Gegenstand entfernt.\r\n1160={0} Gegenstaend(e) wurden zum Einmal-Benutzen Agent hinzugefuegt.\r\n1161=Die Einmal-Benutzen Warteschl. ist leer!\r\n1162=Benutze '{0}'.  ({1} Gegenstaend(e) aus der Einmal-Benutzen Warteschl.)\r\n1163=Es gab ein Problem mit einem Gegenstand in der Einmal-Benutzen Warteschl., versuche den Naechsten.\r\n1164=VerkaufenAgent: autom.es Verkaufen von {0} Gegenstaend(en) fuer {1}gold.\r\n1165=Entfernen\r\n1166=Behaelter erfolgreich gesetzt.\r\n1167=Leeren\r\n1168=(Ausschalten)\r\n1169=(Einschalten)\r\n1170=Setze 'Ziel Beutel'\r\n1171=Entferne 'Ziel Beutel'\r\n1172=OrganisierAgent\r\n1173=Organisierer\r\n1174=Organisiere Jetzt\r\n1175=Behaelter nicht gesetzt.\r\n1176=Razor konnte Dein Gepaeck nicht finden.\r\n1177=OrganisierAgent hat {0} zu bewegende Gegenstaend(e) in die Warteschl. gesetzt. (Dies kann einen Moment dauern)\r\n1178=OrganisierAgent hat keine zu bewegenden Gegenstaend(e) gefunden.\r\n1179=Dieser Gegenstand ist bereits in der Liste.\r\n1180=AutoSucheAusnahmen\r\n1181=KaufAgent hat {0} Gegenstaend(e) fuer {1} gold gekauft.\r\n1182=Der KaufAgent hat einige Gegenstaende wegen Goldmangels nicht kaufen koennen.\r\n1183=Gib die Anzahl ein:\r\n1184=Client CPU-Auslastungsprioritaet auf {0} gesetzt.\r\n1185=Die Uhrzeit ist: {0}\r\n1186=Du bist bei den Koordinaten {0} in '{1}'\r\n1187=Entkleidungsbeutel wurde nicht gefunden. Stattdessen wurde Dein Gepaeck verwendet um die Sachen zu verstauen.\r\n1188={0} Gegenstaend(e) zur Entkleidung in Warteschl. aufgenommen.\r\n1189={0} Gegenstaend(e) zur Bekleidung in Warteschl. aufgenommen.\r\n1190={0} Gegenstaend(e) sind bereits ausgeruestet.\r\n1191={0} Gegendstaend(e) wurden nicht gefunden. (Ausser Reichweite)\r\n1192=Warnung: Spells.def nicht gefunden, Zauberformat-Text wird nicht angezeigt!\r\n1193=Unsichtbare Schritte: {0}\r\n1194=Zaehle unsichtbare Schritte.\r\n1195=Ziel-Warteschl. leeren\r\n1196=Letzten Gegner anvisieren\r\n1197=Ziel-Wareschlange geleert.\r\n1198=Visiere neues 'letztes Ziel' an\r\n1199='Letztes Ziel' gesetzt.\r\n1200=Neues Ziel gesetzt.\r\n1201=Es wurde niemand dieser Art auf Deinem Bildschirm gefunden.\r\n1202=Selbstziel in Warteschl. aufgenommen.\r\n1203='Letztes Ziel' in Warteschl. aufgenommen.\r\n1204=Server hat neues Ziel gesendet, Razor Ziel abgebrochen.\r\n1205=Ziel nach TYP {0}\r\n1206=Sammler\r\n1207=Bist Du sicher, dass Du dies loeschen willst?\r\n1208=Waehle einen Ordner zum Speichern der Bildschirmfotos.\r\n1209=Funktionstasten\r\n\r\n1210=Gegenstaende\r\n1211=Ziele\r\n1212=Agenten\r\n1213=Kleidung\r\n1214=Makros\r\n1215=Zaubersprueche\r\n1216=Faehigkeiten\r\n1217=Verschiedenes\r\n1251=Erste(s)\r\n1252=Zweite(s)\r\n1253=Dritte(s)\r\n1254=Vierte(s)\r\n1255=Fuenfte(s)\r\n1256=Sechste(s)\r\n1257=Siebente(s)\r\n1258=Achte(s)\r\n1260=Necromancy\r\n1270=Chivalry\r\n1271=Traenke\r\n1272=Spezial Faehigkeiten\r\n1290=Bushido\r\n1300=Ninjitsu\r\n1301=Verkaufen\r\n1302=Kaufen\r\n1303=Eingabe erforderlich\r\n1304=Razor Befehlsliste\r\n1305=Benutze Gegenstand in der Hand\r\n1306=Du musst etwas ablegen bevor Du es ausruesten kannst.\r\n1307=Ausruesten/Ablegen Rechte Hand\r\n1308=Ausruesten/Ablegen Linke Hand\r\n1309=Lass gehaltenen Gegenstand fallen\r\n1310=Spellweaving\r\n1311=> Razor Funktionstasten an/aus\r\n1312=Funktionstasten an (Druecke {0} zum Ausschalten)\r\n1313=Funktionstasten aus (Druecke {0} zum Anschalten)\r\n1314=Funktionstasten aktiviert\r\n1315=Funktionstasten deaktiviert\r\n1316=Laufen: {0}\r\n1317=Typ hinzufuegen (Ziel)...\r\n1318=Das angeforderte Ziel ist ausser Reichweite. Aktion abgebrochen!\r\n1319=Max Verkaufen: {0}\r\n1320=Schnueffler Meldungen\r\n1321=Gepaeckgeraeusche\r\n1322=Einfuegen \"Wenn\" Abfrage\r\n1323=Einfuegen \"Oder\"\r\n1324=Einfuegen \"Ende wenn\"\r\n1325=Setze Anzahl\r\n1326=Auffuellen\r\n1327=Jetzt auffuellen\r\n1328=AuffuellAgent\r\n1329=Klicke auf einen Behaelter von dem aus aufgefuellt werden soll,\\n oder klicke auf Dich selbst um Deine Bank-Kiste zu benutzen.\r\n1330=Dieser Behaelter ist unzulaessig.\r\n1331=Auffuellen fertig, {0} Gegenstaende{1} in Warteschl.\r\n1332=Derzeitiges Ziel aufheben\r\n1333=Eine neuere Version von Razor ist auf der Website verfuegbar.\\n\\nMoechtest Du jetzt die Website besuchen um die neue Version herunterzuladen?\r\n1334=Neu laden\r\n1335=Speichern\r\n1336=Warnung: Das derzeitige Ziel erlaubt keine Zielerfassung des Bodens.  Letztes Ziel nicht ausgefuehrt.\r\n1337=Client synchronisieren\r\n1338=Absatteln blockiert.\r\n1339=Razor \"PacketVideo\" Aufnahme starten\r\n1340=Razor \"PacketVideo\" Aufnahme/Wiedergabe anhalten\r\n1341=Es gab bei der Aufnamhe einen Fehler.\\nDer Ausnahmefehler wurde im Log notiert.\r\n1342=Diese Datei ist nicht mit dieser Version von Razor kompatibel.  Lade die neueste Version von Razor herunter.\r\n1343=Diese Video-Datei ist beschaedigt.\\nSie ist entweder unvollstaendig oder wurde bearbeitet.\\nDie Datei kann nicht wiedergegeben werden.\r\n1344=Es gab ein Problem beim Lesen der Datei. Sie ist entweder beschaedigt oder unvollstaendig.\r\n1345=Gib einen Kategorie-Namen ein:\r\n1346=Der Ordner konnte nicht geloescht werden.  Stelle sicher, dass er leer ist.\r\n1347=Der Ordner konnte nicht erstellt werden.  Stelle sicher, dass der verwendete Name zulaessig ist und versuch es noch einmal.\r\n1348=Konnte Makro-Datei nicht verschieben.  Stelle sicher, dass die eingegebene Kategorie zulaessig ist.\r\n1349=Freunde\r\n// 1350 to 1359 reserved (max length 15!)\r\n1350=Beendet\r\n1351=Ende\r\n1352=Game Over?\r\n1353=ker-pwned\r\n1354=Got corp por?\r\n1355=bamboozled\r\n1356=pwned?\r\n1357=Jesus <3s you\r\n1358=Kal Vas Pwned\r\n1359=SMACKDOWN\r\n1360=Klicke auf einen Spieler um ihn zur Freundesliste hinzuzufuegen.\r\n1361=Klicke auf einen Spieler um ihn aus der Freundesliste zu entfernen.\r\n1362=Freund hinzugefuegt.\r\n1363=Freund entfernt.\r\n1364=Spezielle Konstrukte\r\n1365=Einfuegen \"FOR Wiederholungsschleife\"\r\n1366=Einfuegen \"FOR Ende\"\r\n1367=Gib die Anzahl der Wiederholungen ein:\r\n1368=Sammlerpuffer leeren\r\n1369=Letzter Zauber\r\n1370=Letzte Faehigkeit\r\n1371=Letzter Gegenstand\r\n1372=Alle Namen\r\n1373=Einmal-Benutzen\r\n1374=Visiere zufaelligen feindlichen Mensch an\r\n1375=Visiere zufaelligen grauen Mensch an\r\n1376=Visiere zufaelligen unschuldigen Mensch an\r\n1377=Visiere zufaelligen kriminellen Mensch an\r\n1378=Visiere zufaelligen Kriminellen an\r\n1379=WARNUNG: Ziehen/Fallenlassen Zeitueberschreitung! Gehaltener Gegenstand wurde im Gepaeck abgelegt.\r\n1380=Du musst Razor und den Client neu starten um diese aenderung wirksam werden zu lassen.\r\n1381=Du musst ausloggen und Dich neu einloggen um diese Einstellung zu aktivieren.\r\n1382=Ziehen/Fallenlassen Anforderung in Warteschleife aufgenommen {0}... {1} uebrig.\r\n1383=Auffuellen-Anforderung in Bearbeitung....\r\n1384=Deine Staerke hat sich um {0}{1} geaendert, sie ist jetzt bei {2}.\r\n1385=Deine Geschicklichkeit hat sich um {0}{1} geaendert, sie ist jetzt bei {2}.\r\n1386=Deine Intelligenz hat sich um {0}{1} geaendert, sie ist jetzt bei {2}.\r\n1387=Lichtstaerke\r\n1388=Heilung blockiert (das Ziel ist vergiftet)!\r\n1389=Ziehen/Fallenlassen Warteschl. leeren\r\n1390=Jetzt anhalten\r\n1391=>Selbst Heilen/Entgiften\r\n1392=Naechstes Ziel\r\n1393=Setze Auffuellen-Ziel-Behaelter\r\n1394=Zu Einmal-Benutzen hinzufuegen\r\n1395=Letztes Ziel angreifen\r\n1396=Zeitlimit editieren...\r\n1397=Du haeltst nichts in Haenden.\r\n1398=NICHT gestattet\r\n1399=Gestattet\r\n1400=Funktionen mit Server ausgehandelt:\r\n1401=Alle Funktionen erlaubt.\r\n1402=Wetter filter\r\n1403=Lichtstaerke filter\r\n1404=Intelligentes 'Letztes Ziel'\r\n1405=Entfernungsueberwachung 'Letztes Ziel'\r\n1406=oeffne Tueren autom.\r\n1407=Vorm Zaubern Haende freimachen\r\n1408=Auto-Trankbenutzung\r\n1409=Heilung blockieren wenn vergiftet\r\n1410=Wiederhole Makros\r\n1411=Einmal-BenutzenAgent\r\n1412=AuffuellenAgent\r\n1413=VerkaufenAgent\r\n1414=KaufenAgent\r\n1415=Trank Funktionstasten\r\n1416=Zufaellige Ziele\r\n// 1417 to 1465 reserved\r\n1466=Funktion vom Server nicht zugelassen\r\n1467=Diese Funktion ist von diesem Server nicht zugelassen.\\nDu kannst in den 'Optionen' die zu ignorierenden Funktionen ueberpruefen.\\n\\nUm eine Liste der nicht-erlaubten Funktionen zu sehen, ueberpruefe \"Hilfe & Status\".\r\n1468=Kommentar einfuegen\r\n1469=Freund hinzufuegen\r\n1470=Freund entfernen\r\n1471=>Mini-Selbstheilung/-entgiftung\r\n1472=Du solltest die Patch-Verschluesselung nur deaktivieren, wenn Dein Client diese Funktion bereits deaktiviert hat.Diese Option sollte ausgeschaltet bleiben, selbst auf Server mit Patch-Verschluesselung (z.B. OSI/EA offizielle Server).\\nWenn Du Dir nicht sicher bist, schalte diese Option NICHT ab!\\n\\nBist Du sicher, dass Du Client-seitige Patch-Verschluesselung deaktivieren willst?\r\n1473=Absatteln\r\n1474=Zeige/Verstecke Kartenuebersicht\r\n1475=Das ist zu weit weg.\r\n1476=Ziehen/Fallenlassen Warteschl. voll. Bitte warten.\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.enu",
    "content": "// Razor English/ENU Language Pack\n// Last modified $Date: 2006/01/17 22:02:20 $\n::CliLoc=ENU\n\n[controls]\nWelcomeForm::Text=Welcome to Razor!\nWelcomeForm::dataBrowse=Browse...\nWelcomeForm::label5=Language:\nWelcomeForm::groupBox2=Server\nWelcomeForm::selectServerLbl=Select Server:\nWelcomeForm::serverHostLbl=Server Host/IP:\nWelcomeForm::serverNameLbl=Server Name:\nWelcomeForm::portLabel=Port:\nWelcomeForm::groupBox1=Client Options\nWelcomeForm::browse=Browse...\nWelcomeForm::label1=Load UO Client:\nWelcomeForm::patchEncy=Patch client encryption\nWelcomeForm::showAtStart=Show this when Razor starts\nWelcomeForm::quit=&Quit\nWelcomeForm::okay=&Launch UO\n\nMainForm::Text=Razor v{0}\nMainForm::generalTab=General\nMainForm::btnMap=UOPS\nMainForm::systray=System Tray\nMainForm::taskbar=Taskbar\nMainForm::smartCPU=Use smart CPU usage reduction\nMainForm::label7=Language:\nMainForm::label11=Show in:\nMainForm::groupBox4=Profiles\nMainForm::delProfile=Delete\nMainForm::newProfile=&New...\nMainForm::showWelcome=Show Welcome Screen\nMainForm::alwaysTop=Use Smart Always on Top\nMainForm::groupBox1=Filters\nMainForm::opacityLabel=Opacity: 100%\nMainForm::label9=Default Client Priority:\nMainForm::moreOptTab=Options\nMainForm::preAOSstatbar=Use Pre-AOS status window\nMainForm::negotiate=Negotiate features with server\nMainForm::setLTHilight=Set\nMainForm::lthilight=Last Target Highlight:\nMainForm::filterSnoop=Filter snooping messages\nMainForm::incomingCorpse=Show New/Incoming Corpses\nMainForm::incomingMob=Show Incoming People/Creatures\nMainForm::setHarmHue=Set\nMainForm::setNeuHue=Set\nMainForm::lblHarmHue=Harmful\nMainForm::lblNeuHue=Neutral\nMainForm::lblBeneHue=Beneficial\nMainForm::setBeneHue=Set\nMainForm::setSpeechHue=Set\nMainForm::setWarnHue=Set\nMainForm::setMsgHue=Set\nMainForm::setExHue=Set\nMainForm::autoStackRes=Auto-Stack Ore/Fish/Logs at Feet\nMainForm::queueTargets=Queue LastTarget and TargetSelf\nMainForm::spamFilter=Filter repeating system messages\nMainForm::label4=tiles\nMainForm::openCorpses=Open new corpses within\nMainForm::lblWarnHue=Warning Message Hue\nMainForm::lblMsgHue=Razor Message Hue\nMainForm::lblExHue=Search Exemption Hue\nMainForm::blockDis=Block dismount in war mode\nMainForm::chkForceSpellHue=Override Spell Hues:\nMainForm::chkForceSpeechHue=Override Speech Hue\nMainForm::label3=Spell Format:\nMainForm::moreMoreOptTab=More Options\nMainForm::label10=Health Format:\nMainForm::showHealthOH=Show health above people/creatures\nMainForm::blockHealPoison=Block heal if target is poisoned\nMainForm::potionEquip=Auto Unequip for potions\nMainForm::reequipHandsPotion=Re-equip\nMainForm::label17=Razor messages:\nMainForm::QueueActions=Auto-Queue Object Delay actions\nMainForm::spellUnequip=Auto Unequip hands before casting\nMainForm::autoOpenDoors=Auto-open doors\nMainForm::alwaysStealth=Always show stealth steps\nMainForm::autoFriend=Treat party members as 'Friends'\nMainForm::chkStealth=Count stealth steps\nMainForm::rememberPwds=Remember passwords\nMainForm::showtargtext=Show target flag on single click\nMainForm::logPackets=Enable packet logging\nMainForm::rangeCheckLT=Range check Last Target:\nMainForm::actionStatusMsg=Show Action-Queue status messages\nMainForm::label5=Object delay:\nMainForm::label8=tiles\nMainForm::label6=ms\nMainForm::label18=x\nMainForm::smartLT=Use Smart Last Target\nMainForm::gameSize=Force Game Size:\nMainForm::chkPartyOverhead=Show mana/stam above party members\nMainForm::displayTab=Display/Counters\nMainForm::showNotoHue=Show noto hue on {char} in TitleBar\nMainForm::warnCount=Warn when below:\nMainForm::excludePouches=Never auto-search pouches\nMainForm::highlightSpellReags=Highlight Spell Reagents on Cast\nMainForm::titlebarImages=Show Images with Counters\nMainForm::checkNewConts=Auto search new containers\nMainForm::groupBox3=Title Bar Display\nMainForm::showInBar=Show in UO title bar:\nMainForm::groupBox2=Counters\nMainForm::counters::0=Name (Format)\nMainForm::counters::1=Count\nMainForm::delCounter=Del/Edit\nMainForm::addCounter=Add...\nMainForm::recount=Recount\nMainForm::dressTab=Arm/Dress\nMainForm::groupBox6=Arm/Dress Items\nMainForm::clearDress=Clear List\nMainForm::dressDelSel=Remove\nMainForm::undressBag=Change Undress Bag\nMainForm::undressList=Undress\nMainForm::dressUseCur=Add Current\nMainForm::targItem=Add (Target)\nMainForm::dressNow=Dress\nMainForm::groupBox5=Arm/Dress Selection\nMainForm::removeDress=Remove\nMainForm::addDress=Add...\nMainForm::undressConflicts=Auto-move conflicts\nMainForm::skillsTab=Skills\nMainForm::dispDelta=Show skill/stat changes\nMainForm::skillCopyAll=Copy All\nMainForm::skillCopySel=Copy Selected\nMainForm::label1=Base Total:\nMainForm::setlocks=Set all locks:\nMainForm::resetDelta=Reset  +/-\nMainForm::skillList::0=Skill Name\nMainForm::skillList::1=Value\nMainForm::skillList::2=Base\nMainForm::skillList::3=+/-\nMainForm::skillList::4=Cap\nMainForm::skillList::5=Lock\nMainForm::agentsTab=Agents\nMainForm::hotkeysTab=Hot Keys\nMainForm::dohotkey=Execute Selected\nMainForm::groupBox8=Hot Key\nMainForm::chkPass=Pass to UO\nMainForm::label2=Key:\nMainForm::unsetHK=Unset\nMainForm::setHK=Set\nMainForm::chkCtrl=Ctrl\nMainForm::chkAlt=Alt\nMainForm::chkShift=Shift\nMainForm::macrosTab=Macros\nMainForm::macroActGroup=Actions\nMainForm::loopMacro=Loop\nMainForm::recMacro=Record\nMainForm::playMacro=Play\nMainForm::delMacro=Remove\nMainForm::newMacro=New...\nMainForm::screenshotTab=Screen Shots\nMainForm::label12=Image Format:\nMainForm::capNow=Take Screen Shot Now\nMainForm::radioUO=UO Only\nMainForm::radioFull=Full Screen\nMainForm::screenAutoCap=Auto Death Screen Capture\nMainForm::setScnPath=...\nMainForm::dispTime=Include Timestamp on images\nMainForm::statusTab=Help && Status\nMainForm::mleLink=Free Desktop Wallpapers\nMainForm::forumsLink=Razor Discussion Forum\nMainForm::homeLink=Razor Homepage\nMainForm::userGuideLink=Razor User Guide\nMainForm::dataDir=Open Data Directory\nMainForm::showTargetMessagesOverChar=Show Target Self/Last/Clear Overhead\nMainForm::showOverheadMessages=Enabled\nMainForm::goldPerDisplay=Enable Gold Per Sec/Min/Hour Counters\nMainForm::stealthOverhead=Overhead\nMainForm::trackIncomingGold=Enable gold per sec/min/hour tracker\nMainForm::objectDelay=Object Delay:\nMainForm::showBuffDebuffOverhead=Show Buff/Debuff Overhead\nMainForm::lblBuffDebuff=Format:\nMainForm::blockOpenCorpsesTwice=Block opening corpses twice\nMainForm::trackDps=Enable damage tracker\nMainForm::filterSystemMessages=Filter repeating system messages\nMainForm::filterRazorMessages=Filter repeating Razor messages\nMainForm::filterOverheadMessages=Filter repeating overhead messages\nMainForm::overrideSpellFormat=Override spell format\nMainForm::buyAgentIgnoreGold=Buy Agents ignore player gold\n\nHueEntry::Text=Select a Hue\nHueEntry::cancel=Cancel\nHueEntry::okay=&OK\nHueEntry::preview=Preview\nHueEntry::inGame=Select in Game\nHueEntry::label1=Hue Number:\n\nAddCounter::Text=Add a Counter\nAddCounter::delete=Delete\nAddCounter::target=Target\nAddCounter::cancel=Cancel\nAddCounter::Add=&OK\nAddCounter::label4=Color (Any: -1):\nAddCounter::label3=Item ID:\nAddCounter::label2=Format:\nAddCounter::label1=Name:\n\nMacroInsertWait::Text=Insert Wait/Pause...\nMacroInsertWait::radioMenu=Wait for old-style Menu/Dialog\nMacroInsertWait::cancel=&Cancel\nMacroInsertWait::radioStat=Wait for\nMacroInsertWait::radioTarg=Wait for Target\nMacroInsertWait::radioGump=Wait for Gump\nMacroInsertWait::label1=milliseconds\nMacroInsertWait::radioPause=Pause for:\nMacroInsertWait::insert=&Insert\n\nMacroInsertIf::Text=Insert If...\nMacroInsertIf::label1=If:\nMacroInsertIf::cancel=&Cancel\nMacroInsertIf::insert=&Insert\n\nInputBox::cancel=Cancel\nInputBox::ok=&OK\n\n[strings]\n1001=Death Status\n1002=Bards' Music\n1003=Dog Sounds\n1004=Cat Sounds\n1005=Horse Sounds\n1006=Sheep Sounds\n1007=Spirit Speak Sound\n1008=Spell Fizzle Sound\n1009=Weather\n1010=Display Counters\n1011=Recount Counters\n1012=Clear AOS Ability\n1013=Set Primary Ability (AOS)\n1014=Set Secondary Ability (AOS)\n1015=Toggle Stun (Pre-AOS)\n1016=Toggle Disarm (Pre-AOS)\n1017=Setting ability {0}\n1018=AOS Abilities cleared.\n1019=Undress All\n1020=Undress Both Hands\n1021=Undress Left Hand\n1022=Undress Right Hand\n1023=Undress Hat\n1024=Undress Jewelry\n1025=Bandage Self\n1026=Bandage LastTarget\n1027=Use Bandage (No Timer)\n1028=Drink Heal\n1029=Drink Cure\n1030=Drink Refresh\n1031=Drink Night Sight\n1032=Drink Explosion\n1033=Drink Strength\n1034=Drink Agility\n1035=No bandages found\n1036=No item of type {0} found!\n1037=Double Click ({0})\n1038=Re-Target\n1039=Convert to DClick by Type\n1040=Select a new target this Action.\n1041=WARNING: Exception while loading profile property:\\n{0}\n1042=Macro Warning: Cannot find that item (Out of Range).\n1043=Lift {1} - {0}\n1044=Convert to Lift by Type\n1045=Macro Warning: Not holding anything.\n1046=Equip to {0} (L:{1})\n1047=Drop to {0} (@{1})\n1048=Convert to Relative Location\n1049=Drop (Relative) @({0},{1},{2})\n1050=GumpResponse (Button {0})\n1051=Close Gump\n1052=MenuResponse {0}\n1053=Warning: Macro requested target, but no target sent from server! (Do you need a 'WaitForTarget'?)\n1054=Absolute Target\n1055=Convert to LastTarget\n1056=Convert to Target by Type\n1057=Target RelLoc ({0},{1})\n1058=Last Target\n1059=Target Self\n1060=Set Last Target\n1061=Target Random Murderer\n1062=Target Random Grey\n1063=Target Random Innocent\n1064=Target Random Enemy\n1065=Target Random Friendly\n1066=Target Random Non-Friendly\n1067=Say \"{0}\"\n1068=UseSkill {0}\n1069=CastSpell {0}\n1070=SetAbility {0}\n1071=Dress: {0}\n1072=Undress: {0}\n1073=Unequip Layer {0}\n1074=Wait for Menu (Any)\n1075=Wait for Menu (#{0})\n1076=Edit...\n1077=Wait For Gump (Any)\n1078=Wait for Gump (#{0})\n1079=Wait for Target\n1080=Pause {0:#.00}sec\n1081=Wait for {0} {1} {2}\n1082=Loading '{0}'...\n1083=> Stop Current Macro\n1084=Play: {0}\n1085=Playing Macro '{0}'...\n1086=Macro '{0}' finished.\n1087=Razor was unable to initialize. Error code:\n1088=Description: Could not find the client Window Handle.\\nCause: The client did not creeate its main window. Check to make sure your client started up properly.\n1089=Description: Could not find the Client's ThreadID\\nThis error means that Razor was unable to hook the client after it started. This is usually caused by errors in the client which cause it to crash to terminate before it has finished starting up. Check to make sure your client is starting up properly.\n1090=Description: Could not create Windows Hooks.\\nCause: Internal windows error.\n1091=Description: Could not create or access Razor shared memory.\\nCause: Windows Error or invalid permissions.\n1092=Description: Crypt.dll has disabled itself.\\nCause: Version mismatch. Reinstall Razor and use the original Crypt.dll that comes with the installation. Your Crypt.dll is corrupted.\n1093=Description: Could not patch the client's Winsock functions.\\nCause: Internal error, Windows Error, or Incompatible Version. Reinstall Razor.\n1094=Description: Could not copy packet lengths and/or encryption information from the client.\\nCause: Your client version may not be compatible with this version of Razor. You must update your client to at least version 4.0.0.\n1095=Description: An invalid parameter was passed to the loader.\\nCause: Mismatched DLL versions. Reinstall Razor.\n1096=Your skill in {0} has changed by {4}{5:F1}, it is now {3:F1} ({1}{2:F1}).\n1097=Invalid abbreviation.\n1098=Invalid item ID.\n1099=Invalid hue.\n1100=Select an item to count.\n1101=Error loading '{0}'!\\nThis profile is corrupt and cannot be used.\n1102=The property {0} was not found in this profile.\n1103=Your counters.xml file is corrupt and cannot be used.\n1104=Because you have Auto Search Containers off, you must now reopen all of your bags so that your counters can be updated.\n1105=Warning: {0} amount is now {1}!\n1106=Select the hue you wish to use.\n1107=Take ScreenShot Now\n1108=Possible values:\\n{char} - Character name\\n{shard} - Shard name\\n{str}/{hp}/{hpmax} - Health status\\n{dex}/{stam}/{stammax} - Dex status\\n{int}/{mana}/{manamax} - Int status\\n{weight}/{maxweight} - Weight information\\n{gold} - Total Gold on character\\n{AR} - Armor Rating / Physical Resistance\\n{tithe} - Tithing points\\n{followers}/{followersmax} - Followers slots\\n{bandage} - Bandage Timer\\n{statbar}/{mediumstatbar}/{largestatbar} - Status bar\\n{crimtime} - How long you have been a criminal\\n{stealthsteps} - Stealth steps counter\\n{physresist} - Physical Resistance\\n{coldresist} - Cold Resistance\\n{fireresist} - Fire Resistance\\n{energyresist} - Energy Resistance\\n{poisonresist} - Poison Resistance\\n{luck} - Luck\\n{damage} - Damage Min-Max\\nColor - HTML hex color code: '~#rrggbb' ('~#~' to terminate)\\nOr a {Format} from the Counters list\\n{skill} - Skill usage timer\n1109=Razor Version: {0}\\nMemory Used: {1}\\nSend: {2} ({3}/s)\\nRecv: {4} ({5}/s)\\nConnected for {6}\\n\\nPlayer Serial: 0x{7:X8}\\nBackpack Serial: 0x{8:X8}\\n\\nTracking Items: {9}\\nTracking Mobs: {10}\\n\n1110=Set Lock: UP\n1111=Set Lock: DOWN\n1112=Set Lock: LOCKED\n1113=Are you sure you want to remove the counter \"{0}\"?\\nThis will effect all profiles.\n1114=Load profile \"{0}\" now?\n1115=There was an error loading that profile.\n1116=You cannot delete the default profile.\n1117=Enter a name for the new profile:\n1118=Cannot create a new profile!\\n Reason: A profile with that name already exists.\\n\\nWould you like to load that profile now?\n1119=Enter a name for the new Dress List:\n1120=Delete this dress list?\n1121={0:X} (Item out of Range)\n1122=Delete this item from the dress list?\n1123=Target a bag to undress the list '{0}' into.\n1124=Undress bag set.\n1125=Item not found, or invalid item selected.\n1126=That key combination already belongs to '{0}'.\\nChange it to '{1}'?\n1127=Data saved successfully.\n1128=Warning!\\nLogging packets may reduce Razor's performance. Log files can also\\neasily grow very large, and Razor will not automatically remove them.\\n\\nRazor's packet log files may contain personal information such as\\npasswords, and should be not be given to people you do not trust.\\n\\nAre you sure you want to enable packet logging?\\n(This will not be saved in your user profile)\n1129=Convert Selected to TYPE\n1130=Enter a name for the new macro:\n1131=That name contains invalid characters.\n1132=A macro with that name already exists.\n1133=This macro will be cleared before recording.\\nAre you sure you want to record over this macro?\n1134=Are you sure you want to PERMANENTLY delete '{0}'?\\n(This cannot be undone)\n1135=Insert Pause/Wait...\n1136=Insert Set LastTarget\n1137=Move Up\n1138=Move Down\n1139=Remove Action\n1140=Begin Recording Here\n1141=The file '{0}' was not found.\n1142=Are you sure?\n1143=WARNING: The following {0} file{1} count not be deleted:\\n{2}\n1144=This change will take effect the next time you start Razor.\n1145=Enabling this option will cause Razor to save your passwords as part of your profile.\\nEven though the passwords are encrypted it may be possible for someone to use them if the gain access to your profile's xml file.\\nAre you sure you want to enable this feature?\n1146=You must specify a valid port.\n1147=Ignoring action request (already queued).\n1148=Queuing action request {0}... {1} left.\n1149=Finished {0} queued actions in {1:F1} seconds.\n1150=Use Once Agent\n1151=Add (Target)...\n1152=Add Container (Target)...\n1153=Remove (Target)...\n1154=Clear List\n1155=Target an item to add.\n1156=Target a Container.\n1157=Target an item to remove.\n1158=Item added.\n1159=Item removed.\n1160={0} item(s) added to the Use Once agent.\n1161=The UseOnce queue is empty!\n1162=Using '{0}'.  ({1} item(s) left in the UseOnce queue)\n1163=There was a problem with one of your UseOnce items, trying the next one.\n1164=SellAgent: Automatically selling {0} item(s) for {1}gp.\n1165=Remove\n1166=Container set successfully.\n1167=Clear\n1168=(Push to Disable)\n1169=(Push to Enable)\n1170=Set Hot Bag\n1171=Clear Hot Bag\n1172=Organizer Agent\n1173=Organizer\n1174=Organize Now\n1175=Container not set.\n1176=Razor could not find your backpack.\n1177=Organize Agent queued {0} item(s) to be moved. (This may take a few moments)\n1178=Organize Agent did not find any items to move.\n1179=That item is already in the list.\n1180=AutoSearchExemptions\n1181=Buy Agent bought {0} item(s) for {1}gp.\n1182=The Buy Agent did not attempt to buy some items in your buy list because you do not have enough gold.\n1183=Enter the amount:\n1184=Client Process Priority set to {0}\n1185=The current time is: {0}\n1186=You are at {0} in '{1}'\n1187=Undress bag was not found or out of range, using your backpack instead.\n1188={0} item(s) queued to be de-equipped.\n1189={0} item(s) queued to be equipped.\n1190={0} item(s) already equipped.\n1191={0} item(s) were not found. (Out of Range)\n1192=Warning: Spells.def not found, spell format text will not be shown\n1193=Stealth Steps: {0}\n1194=Now counting stealth steps.\n1195=Clear Target Queue\n1196=Attack Last Combatant\n1197=Target queue cleared.\n1198=Target a new 'Last Target'\n1199=Last Target set.\n1200=New target set.\n1201=No one matching that was found on your screen.\n1202=Queued target self.\n1203=Queued last target.\n1204=Server sent new target, canceling Razor target.\n1205=Target by Type {0}\n1206=Scavenger\n1207=Are you sure you want to delete this?\n1208=Select a folder to store Razor's screen shots.\n1209=Hot Keys\n1210=Items\n1211=Targets\n1212=Agents\n1213=Dress\n1214=Macros\n1215=Spells\n1216=Skills\n1217=Misc\n1218=Friends\n1219=Scripts\n1251=1st\n1252=2nd\n1253=3rd\n1254=4th\n1255=5th\n1256=6th\n1257=7th\n1258=8th\n1260=Necromancy\n1270=Chivalry\n1271=Potions\n1272=Special Moves\n1290=Bushido\n1300=Ninjitsu\n1301=Sell\n1302=Buy\n1303=Input Required\n1304=Razor Commands List\n1305=Use Item in Hand\n1306=You must disarm something before you can arm it.\n1307=Arm/Disarm Right Hand\n1308=Arm/Disarm Left Hand\n1309=Drop What You are Currently Holding\n1310=Spellweaving\n1311=> Enable/Disable Razor HotKeys\n1312=Hot Keys Enabled (Press {0} to disable)\n1313=Hot Keys Disabled (Press {0} to enable)\n1314=Hot Keys Enabled\n1315=Hot Keys Disabled\n1316=Walk: {0}\n1317=Add Type (Target)...\n1318=The requested target is out of range, last target not executed!\n1319=Max Sell: {0}\n1320=Snooping Messages\n1321=Backpack Sounds\n1322=Insert \"If\" Conditional\n1323=Insert \"Else\"\n1324=Insert \"End If\"\n1325=Set Amount\n1326=Restock\n1327=Restock Now\n1328=Restock Agent\n1329=Target a container to restock from, or target yourself to use your bank box.\n1330=That container is invalid.\n1331=Restock done, queued {0} item{1}.\n1332=Cancel Current Target\n1333=A newer version of razor is availible for download from the Razor website.\\n\\nDo you wish to visit the Razor website now to download the new version?\n1334=Reload\n1335=Save\n1336=Warning: The current target does not allow you to target the ground.  Last Target not performed.\n1337=Resynchronize Client\n1338=Dismount blocked.\n1339=Begin Razor \"PacketVideo\" Recording\n1340=Stop \"PacketVideo\" Recording/Playback\n1341=There was an error starting the recording.\\nThe exception has been logged.\n1342=This file is not compatible with this version of Razor.  Make sure you have the latest Razor version.\n1343=This video file is corrupt.\\nIt may be incomplete, or it may have been tampered with.\\nThe file cannot be played.\n1344=There was a problem reading the file.  It may be damaged or incomplete.\n1345=Enter category name:\n1346=The directory could not be deleted.  Make sure it is empty.\n1347=Could not create directory.  Make sure the name you entered is valid and try again.\n1348=Could not move macro file.  Make sure the category you entered was valid.\n1349=Friends\n// 1350 to 1359 reserved (max length 15!)\n1350=Stopped\n1351=The End\n1352=Game Over?\n1353=ker-pwned\n1354=Got corp por?\n1355=bamboozled\n1356=pwned?\n1357=Jesus <3s you\n1358=Kal Vas Pwned\n1359=SMACKDOWN\n1360=Target a player to add to your friends list.\n1361=Target a player to remove from your friends list.\n1362=Friend added.\n1363=Friend removed.\n1364=Special Constructs\n1365=Insert \"For Loop\"\n1366=Insert \"End For\"\n1367=Enter the number of iterations:\n1368=Clear Scavenger Cache\n1369=Last Spell\n1370=Last Skill\n1371=Last Object\n1372=All Names\n1373=UseOnce\n1374=Target Random Enemy Humanoid\n1375=Target Random Grey Humanoid\n1376=Target Random Innocent Humanoid\n1377=Target Random Criminal Humanoid\n1378=Target Random Criminal\n1379=WARNING: Drag/Drop timeout! Dropping item in hand to backpack.\n1380=You must restart Razor and the client for this change to take effect.\n1381=You must go into your Paperdoll, click Options and then click Apply for this to take effect.\n1382=Queuing dragdrop request {0}... {1} left.\n1383=Restock request in progress....\n1384=Your strength has changed by {0}{1}, it is now {2}.\n1385=Your dexterity has changed by {0}{1}, it is now {2}.\n1386=Your intelligence has changed by {0}{1}, it is now {2}.\n1387=Light Levels\n1388=Heal blocked (the target is poisoned)!\n1389=Clear Drag/Drop Queue\n1390=Stop Now\n1391=> Smart Heal/Cure Self\n1392=Next Target\n1393=Set Restock HotBag\n1394=Add to UseOnce\n1395=Attack Last Target\n1396=Edit Timeout...\n1397=You are not holding anything.\n1398=NOT allowed\n1399=allowed\n1400=Features negotiated with server:\n1401=All features allowed.\n1402=Weather filter\n1403=Light Level filter\n1404=Smart LastTarget\n1405=Range Check LastTarget\n1406=Auto-Open Doors\n1407=Unequip Before Spell Cast\n1408=Auto-Potion Equip\n1409=Block Heal when Poisoned\n1410=Looping Macros\n1411=Use Once Agent\n1412=Restock Agent\n1413=Sell Agent\n1414=Buy Agent\n1415=Potion Hotkeys\n1416=Random Targets\n1417=Closest Targets\n1418=Overhead Health/Stats Display\n1419=Autoloot Agent\n1420=Bone cutter Agent\n1421=Advanced Macros\n1422=Auto remount\n1423=Automatic Bandage\n1424=Enemy Target Sharing\n1425=Filter Seasons\n1426=Spell Target Sharing\n1427=Humanoid Health Checks\n1428=Journal speech checks\n// up to 1465: reserved\n1466=Feature Disallowed by Server\n1467=This feature is not allowed by the current game server.\\nYou may choose to ignore the server's allowed features on the \"Options\" tab.\\n\\nTo see a list of disallowed features, check the \"Help & Status\" tab.\n1468=Insert Comment\n1469=Add Friend\n1470=Remove Friend\n1471=> Mini-Heal/Cure Self\n1472=You should only disable the \"Patch Encryption\" option if you are using a client that already has encryption disabled.  This option should remain enabled even on servers which use client encryption (such as OSI/EA official servers).\\nIf you are not sure what to do, do NOT uncheck this box.\\n\\nAre you sure you want to turn off client-side encryption patching?\n1473=Dismount\n1474=Show/Hide Map Window\n1475=That is too far away.\n1476=Drag drop queue is FULL! Please wait.\n1477=Toggle War/Peace\n1478=Rewards Gump\n1479=The game window size you selected is invalid. Try again.\n1480=(Scavenger HotBag)\n1481=(Restock HotBag {0})\n1482=(UseOnce #{0})\n1483=(Sell Agent HotBag)\n1484=(Organizer {0} HotBag)\n1485=The server address you entered could not be resolved.\n1486=Party: Accept Invitation\n1487=Party: Decline Invitation\n1488=Harmful Target\n1489=Beneficial Target\n1490=(Razor Friend)\n1491=Play from Here\n1492=Initializing...\n1493=Loading most recent profile...\n1494=Loading Client...\n1495=Waiting for client to start...\n1496=Don't forget to donate!\n1497=Welcome to Razor!\n1498=2D Client (Auto Detect)\n1499=3D Client (Auto Detect)\n1500=(Auto Detect)\n1501=Opacity: {0}%\n1502=Enter new timeout value for this action (in seconds):\n1503=not assigned\n1504=Change Timeout\n1505=Enter a Name\n1506=Invalid.\n1507=Staff Only Items\n1508={0}'s Stats\n1509=Eat Enchanted Apple\n1510=Target Closest Murderer\n1511=Target Closest Grey\n1512=Target Closest Innocent\n1513=Target Closest Enemy\n1514=Target Closest Friendly\n1515=Target Closest Non-Friendly\n1516=Target Closest Enemy Humanoid\n1517=Target Closest Grey Humanoid\n1518=Target Closest Innocent Humanoid\n1519=Target Closest Criminal Humanoid\n1520=Target Closest Criminal\n1521=Warning: The profile '{0}' is in use by another instance of Razor!\\nIf you make changes to this profile it may become corrupted. It is recommended that you use a different profile for each instance of Razor.\n1522=Waiting... Timeout:\n1523=Razor was unable to locate and load a suitable UO cliloc file, some text may not be displayed. Please manually set your UO Data Directory or verify that it is correct.\n1524=No CliLoc\n1525=Bulk Order Deed\n1526=Launch BOD Agent\n1527=Next Humanoid Target\n1528=Spells\n1529=Warning: AOSAbilities.def not found, weapon move hotkeys will be unavailable\n1530=Enter new text:\n1531=Razor was unable to locate your UO client automatically. Please manually set your UO Data Directory or verify that it is correct.\n1532=Failed to find client\n1533=Unable to launch the client specified. (Error: {2})\\n{0}: \"{1}\"\n1534=Failed to launch client\n1537=Target Random Innocent Monster\n1538=Target Random Criminal Monster\n1541=Target Closest Innocent Monster\n1542=Target Closest Criminal Monster\n1543=Next Monster Target\n1927=Mysticism\n1950=A Razor macro has been detected in your clipboard.\\nWould you like to create this macro based on the clipboard data?\n1951=Macro has been copied to the clipboard\n1952=Deer Sounds\n1953=Enter new macro name\n1954=Enter new variable name\n1955=Target Closest Grey Monster\n1956=Target Closest Enemy Monster\n1957=Target Random Grey Monster\n1958=Target Random Enemy Monster\n1959=Cyclops/Titan Sounds\n1960=Next Enemy Humanoid Target\n1961=Unable to open macro file\n1962=> Pause Current Macro\n1963=Macro paused..\n1964=Macro resuming..\n1965=Stun ready\n1966=Stun successful\n1967=Stun disabled\n1968=Stun failed\n1969=All Corpses\n1970=All Mobiles\n1971=Bull Sounds\n1972=Dragon Sounds\n1973=Set Sell HotBag\n1974=Add UseOnce Container\n1975=Chicken Sounds\n1976=Toggle JMap Visibility\n1977=Scavenger Enable/Disable\n1978=Scavenger Set Hot Bag\n1979=Scavenger Add Target\n1980=Toggle GPS/GPM/GPM Tracker\n1981=Enter new text\n1982=This version of Razor is portable and your profiles and macros are stored within the Razor folder. Would you like to import your existing Profiles and Macros? This process will not effect your existing macros from your previous version.\n1983=Set Organizer HotBag\n1984=Set container label\n1985=Add to ignore list\n1986=Remove from ignore list\n1987=(Razor Ignored)\n1988=IgnoreList\n1989=Previous Target\n1990=Previous Enemy Humanoid Target\n1991=Previous Humanoid Target\n1992=Use Last Gump Response\n1993=Set container alias\n1994=> Interrupt\n1995=Capture Last Opened BOD\n1996=Toggle Damage Tracker\n1997=>> Enable Razor HotKeys\n1998=>> Disable Razor HotKeys\n1999=Your UO data directory and UO client path do not match. This can cause issues such as missing animations and graphics.\n2000=Target Random Mobile\n2001=Target Closest Murderer Monster\n2002=Target Closest Murderer Humanoid\n2003=Target Closest Mobile\n2004=Target Random Murderer Humanoid\n2005=Target Random Murderer Monster\n2006=Target Random Non-Friendly Humanoid\n2007=Target Random Non-Friendly Monster\n2008=Target Random Friendly Humanoid\n2009=Target Random Friendly Monster\n2010=Target Random Innocent Monster\n2011=Target Random Criminal Monster\n2012=Target Closest Non-Friendly Humanoid\n2013=Target Closest Non-Friendly Monster\n2014=Target Closest Friendly Humanoid\n2015=Target Closest Friendly Monster\n2016=Target Closest Innocent Monster\n2017=Target Closest Criminal Monster\n2018=Next Monster Target\n2019=Previous Monster Target\n2020=Add All Mobiles As Friends\n2021=All Come\n2022=All Follow Me\n2023=All Follow\n2024=All Guard Me\n2025=All Guard\n2026=All Kill\n2027=All Stay\n2028=All Stop\n2029=Pet Commands\n2030=Friend\n2031=Str: {0}{1} - {2}\n2032=Dex: {0}{1} - {2}\n2033=Int: {0}{1} - {2}\n2034=[{0}] {4}{5:F1} {3:F1} ({1}{2:F1})\n2035=Grab Item\n2036=Set Grab Item HotBag\n2037=Target item to grab\n2038=(Grab Item HotBag)\n2039=Next Criminal Humanoid Target\n2040=Next Murderer Humanoid Target\n2041=Next Innocent Humanoid Target\n2042=Previous Criminal Humanoid Target\n2043=Previous Murderer Humanoid Target\n2044=Previous Innocent Humanoid Target  \n2045=> Criminal Targets\n2046=> Enemy Targets\n2047=> Friendly Targets\n2048=> Grey Targets\n2049=> Innocent Targets\n2050=> Murderer Targets\n2051=> Non-Friendly Targets\n2052=Next Friendly Humanoid Target\n2053=Next Grey Humanoid Target\n2054=Next Non-Friendly Humanoid Target\n2055=Previous Friendly Humanoid Target\n2056=Previous Grey Humanoid Target\n2057=Previous Non-Friendly Humanoid Target\n2058=Toggle War Only\n2059=Toggle Peace Only\n2060=> Greater Heal/Cure Self\n2061=Set Last Target (Beneficial)\n2062=Set Last Target (Harmful)\n2063=Last Beneficial Target Set\n2064=Last Harmful Target Set\n2065=Target Closest Friend\n2066=Target Random Friend\n2067=Next Friend Target\n2068=Previous Friend Target\n2069=Use Item in Right Hand\n2070=Use Item in Left Hand\n2071=Insert Overhead Message\n2072=Insert Wait For Target\n2073=Add All Humanoids As Friends\n2074=Next Enemy Monster Target\n2075=Next Criminal Monster Target\n2076=Next Murderer Monster Target\n2077=Next Innocent Monster Target\n2078=Previous Criminal Monster Target\n2079=Previous Murderer Monster Target\n2080=Previous Innocent Monster Target\n2081=Next Friendly Monster Target\n2082=Next Grey Monster Target\n2083=Next Non-Friendly Monster Target\n2084=Previous Enemy Monster Target\n2085=Previous Friendly Monster Target\n2086=Previous Grey Monster Target\n2087=Previous Non-Friendly Monster Target\n2088=Target a new 'Beneficial Target'\n2089=Target a new 'Harmful Target'\n2090=Bird Sounds\n2091=AddAllMobilesTargetFilter\n2092=AddAllMobilesHumanoidTargetFilter\n2093=Insert \"While Loop\"\n2094=Insert \"End While\"\n2095=Insert \"Do\"\n2096=Insert \"Do While Loop\"\n2097=Play Script: {0}\n2098=Enter new script variable name\n2099=Playing script '{0}'...\n2100=Script '{0}' finished\n2101=> Stop Current Script\n2102=Party: Add\n2103=Mysticism\n2104=Masteries\n2105=Waypoint: Next\n2106=Waypoint: Previous\n2107=Waypoint: Hide\n2108=Insert Clear SysMessages\n2109=Clear SysMessages\n2110=Next Non-Friendly Target\n2111=Prev Non-Friendly Target\n2112=Set Hue\n2113=Script: Get 'dclicktype' command\n2114=Script: Get 'targettype' command\n2115=Script: '{0}' copied to the clipboard\n2116=Gump: Item/Mobile Info\n2117=Gump: System Messages\n2118=Gump: Hot Keys\n2119=Gump: Boat Control\n2120=Buy Agent attempted to buy {0} item(s) for {1}gp.\n2121=Next Friendly Target\n2122=Previous Friendly Target\n2123=> Pause Current Script\n2124=Script resuming from line {0}\n2125=Script pausing on line {0}\n2126=Script '{0}' finished ({1}ms)"
  },
  {
    "path": "etc/Language/Razor_lang.esp",
    "content": "// Razor Espaol/ESP Languaje Pack\r\n// Ultima modificacion 05/01/04\r\n::CliLoc=ESP\r\n\r\n[controls]\r\nWelcomeForm::Text=Bienvenido al Razor!\r\nWelcomeForm::label5=Lenguaje por defecto:\r\nWelcomeForm::groupBox3=Perfil\r\nWelcomeForm::newProfile=Nuevo...\r\nWelcomeForm::label2=Cargar:\r\nWelcomeForm::groupBox2=Servidor\r\nWelcomeForm::label3=IP:\r\nWelcomeForm::label4=Port:\r\nWelcomeForm::groupBox1=Opciones de Cliente\r\nWelcomeForm::makeDef=Marcar como defecto\r\nWelcomeForm::browse=Examinar\r\nWelcomeForm::label1=Cliente:\r\nWelcomeForm::patchEncy=Patch client encriptado\r\nWelcomeForm::showAtStart=Mostrar siempre al ejecutar\r\nWelcomeForm::quit=&Salir\r\nWelcomeForm::okay=&Entrar\r\nMainForm::generalTab=General\r\nMainForm::label7=Lenguaje:\r\nMainForm::logPackets=Activar logeo de paquete\r\nMainForm::rememberPwds=Recordar clave\r\nMainForm::systray=System Tray\r\nMainForm::taskbar=Barra\r\nMainForm::label11=Mostrar:\r\nMainForm::groupBox4=Perfiles\r\nMainForm::delProfile=Borrar\r\nMainForm::newProfile=&Nuevo\r\nMainForm::showWelcome=Mostrar mensaje bienvenida\r\nMainForm::alwaysTop=Marcar para siempre visible\r\nMainForm::groupBox1=Filtros\r\nMainForm::opacityLabel=Opacity: 100%\r\nMainForm::moreOptTab=Mas Opciones\r\nMainForm::incomingCorpse=Mostrar los nombres de los cadaveres\r\nMainForm::incomingMob=Mostrar nombres de gente y criaturas\r\nMainForm::setHarmHue=Set\r\nMainForm::setNeuHue=Set\r\nMainForm::lblHarmHue=Agresibo\r\nMainForm::lblNeuHue=Neutral\r\nMainForm::lblBeneHue=Beneficial\r\nMainForm::setBeneHue=Set\r\nMainForm::setSpeechHue=Set\r\nMainForm::setWarnHue=Set\r\nMainForm::setMsgHue=Set\r\nMainForm::setExHue=Set\r\nMainForm::autoStackRes=Dejar Minerales y Peces al suelo\r\nMainForm::queueTargets=Espera de acciones para realizar\r\nMainForm::actionStatusMsg=Ver aciones en el mensaje de estado\r\nMainForm::spamFilter=Filtrar Publicidad\r\nMainForm::label4=casillas\r\nMainForm::openCorpses=Abrir nuevos objetos en\r\nMainForm::showNotoHue=Ver los Hues en la barra de titulo\r\nMainForm::lblWarnHue=Mensaje de Peligro\r\nMainForm::lblMsgHue=Mensaje Sistema\r\nMainForm::lblExHue=Buscar Excepcion\r\nMainForm::chkStealth=Contar Pasos Escondido\r\nMainForm::label6=ms\r\nMainForm::label5=Tiempo de:\r\nMainForm::QueueActions=Activar Tiempo acciones objetos \r\nMainForm::chkForceSpellHue=Color del Hechizo:\r\nMainForm::chkForceSpeechHue=Sobrescritura msg\r\nMainForm::label3=Formato:\r\nMainForm::displayTab=Mostrar/Contenido\r\nMainForm::highlightSpellReags=Mostrar regs usados en el hechizo\r\nMainForm::titlebarImages=Mostrar imagenes en barra\r\nMainForm::sortCounters=Contador para ordenacion de listas\r\nMainForm::checkNewConts=Auto buscar nuevos contenedores\r\nMainForm::warnCount=Advertir cuando quedan:\r\nMainForm::groupBox3=Mostrar barra superior\r\nMainForm::showInBar=Mostrar contenido en barra:\r\nMainForm::groupBox2=Contenidos\r\nMainForm::delCounter=Del/Edit\r\nMainForm::addCounter=Agregar\r\nMainForm::recount=Recuento\r\nMainForm::dressTab=Arm/Dress\r\nMainForm::groupBox6=Arm/Dress Objetos\r\nMainForm::dressDelSel=Borrar\r\nMainForm::undressBag=Cambiar Undress Bolsa\r\nMainForm::undressList=Undress Ahora\r\nMainForm::dressUseCur=Add Current\r\nMainForm::targItem=Agregar (Objetivo)\r\nMainForm::dressNow=Dress Ahora\r\nMainForm::groupBox5=Arm/Dress Seleccion\r\nMainForm::removeDress=Borrar\r\nMainForm::addDress=Nuevo\r\nMainForm::undressConflicts=Mover los objetos que estan en conflicto\r\nMainForm::skillsTab=Habilidades\r\nMainForm::dispDelta=Mostrar Cambi\r\nMainForm::skillCopyAll=Copiar Todos\r\nMainForm::skillCopySel=Copiar Seleccion\r\nMainForm::label1=Base Total:\r\nMainForm::setlocks=Fijar todos a:\r\nMainForm::resetDelta=Reset  +/-\r\nMainForm::screenshotTab=Imagenes\r\nMainForm::capNow=Take SS Now\r\nMainForm::radioUO=Solo UO\r\nMainForm::radioFull=Imagen Completa\r\nMainForm::screenAutoCap=Capturar pantalla al morir\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Incluir tiempo en imagenes\r\nMainForm::hotkeysTab=Teclas\r\nMainForm::dohotkey=Ejecutar seleccion\r\nMainForm::groupBox8=Tecla\r\nMainForm::chkPass=Pasar al UO\r\nMainForm::label2=Key:\r\nMainForm::unsetHK=Unset\r\nMainForm::setHK=Set\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Macros\r\nMainForm::macroActGroup=Acciones\r\nMainForm::loopMacro=Continuo\r\nMainForm::recMacro=Grabar\r\nMainForm::playMacro=Play\r\nMainForm::delMacro=Borrar\r\nMainForm::newMacro=Nuevo\r\nMainForm::agentsTab=Agentes\r\nMainForm::statusTab=Ayuda && Estado\r\nMainForm::visitForums=Ayuda && Foros de Soporte\r\nMainForm::visitHome=Razor Homepage\r\nMainForm::visitGuide=Razor Guia Usuario\r\nHueEntry::Text=Select a Hue\r\nHueEntry::cancel=Cancelar\r\nHueEntry::okay=&Entrar\r\nHueEntry::preview=Preview\r\nHueEntry::inGame=Seleccionar en Juego\r\nHueEntry::label1=Hue Numero:\r\nAddCounter::Text=Editar Contador\r\nAddCounter::delete=Borrar\r\nAddCounter::target=Objetivo \r\nAddCounter::cancel=Cancelar\r\nAddCounter::Add=&Agregar\r\nAddCounter::label4=Color (Any: -1):\r\nAddCounter::label3=Item ID:\r\nAddCounter::label2=Formato:\r\nAddCounter::label1=Nombre:\r\nMacroInsertWait::Text=Insertar Espera/Pausa...\r\nMacroInsertWait::radioMenu=Esperar para Menu\r\nMacroInsertWait::cancel=&Cancelar\r\nMacroInsertWait::radioStat=Espera para\r\nMacroInsertWait::radioTarg=Espera para Objetivo\r\nMacroInsertWait::radioGump=Espera para Gump\r\nMacroInsertWait::label1=milisegundos\r\nMacroInsertWait::radioPause=Parar por:\r\nMacroInsertWait::insert=&Insertar\r\n\r\n\r\n[strings]\r\n1001=Estado de muerte\r\n1002=Musica de Bardo\r\n1003=Sonido de perro\r\n1004=Sonido de gato\r\n1005=Sonido de caballo\r\n1006=Sonido de oveja\r\n1007=Sonido Spirit Speak\r\n1008=Sonido fracaso conjuro\r\n1009=Tiempo\r\n1010=Mostrar Contadores\r\n1011=Recontar Contadores\r\n1012=Clear AOS Ability\r\n1013=Set Primary Ability (AOS)\r\n1014=Set Secondary Ability (AOS)\r\n1015=Toggle Stun (Pre-AOS)\r\n1016=Toggle Disarm (Pre-AOS)\r\n1017=Setting ability {0}\r\n1018=AOS Abilities cleared.\r\n1019=Undress Todo\r\n1020=Undress Ambas Manos\r\n1021=Undress Mano izquierda\r\n1022=Undress Mano derecha\r\n1023=Undress Sombrero\r\n1024=Undress Joyeria\r\n1025=Bendarte\r\n1026=Bendar ultimo objetivo\r\n1027=Usar bendas (No Tiempo)\r\n1028=Botella Curacion\r\n1029=Botella Antidoto\r\n1030=Botella Resistencia\r\n1031=Botella Vision Nocturna\r\n1032=Botella Explosion\r\n1033=Botella Fuerza\r\n1034=Botella Agilidad\r\n1035=Ninguna benda encontrada\r\n1036=Ningun objeto del tipo {0} encontrado!\r\n1037=Doble Click ({0})\r\n1038=Re-Target\r\n1039=Convertir el DClick por Tipo\r\n1040=Seleccione un nuevo objetivo de accion.\r\n1041=ADVERTENCIA: Excepcion mientras cargaba las caracteristicas del perfil: \\n{0}\r\n1042=Advertencia macro: No puede encontrar ese objeto (Fuera de Rango).\r\n1043=Elevacion {1} - {0}\r\n1044=Convertir elevacion por tipo\r\n1045=Advertencia macro: No lleva nada a cabo.\r\n1046=Equipar a {0}\r\n1047=Desequipar a {0} (@{1})\r\n1048=Convertir a localizacion relativa\r\n1049=Soltar (Relativo) @({0},{1},{2})\r\n1050=GumpResponse (Button {0})\r\n1051=Cerrar Gump\r\n1052=MenuResponse {0}\r\n1053=Advertencia: No se encontro el objetivo (Necesitas un 'WaitForTarget'?)\r\n1054=Unico Objetivo\r\n1055=Combertir a Ultimo Objetivo\r\n1056=Objetivo por tipo {0}\r\n1057=Objetivo RelLoc ({0},{1},{2})\r\n1058=Ultimo objetivo\r\n1059=Ser el Objetivo\r\n1060=Marcar ultimo Objetivo\r\n1061=Objetivo al azar Rojo\r\n1062=Objetivo al azar Gris\r\n1063=Objetivo al azar Azul\r\n1064=Objetivo al azar enemigo\r\n1065=Objetivo al azar amigo\r\n1066=Objetivo al azar no amigo\r\n1067=Decir \"{0}\"\r\n1068=UseSkill {0}\r\n1069=CastSpell {0}\r\n1070=SetAbility {0}\r\n1071=Dress: {0}\r\n1072=Undress: {0}\r\n1073=Unequip Layer {0}\r\n1074=Wait for Menu (Any)\r\n1075=Wait for Menu (#{0})\r\n1076=Editar\r\n1077=Wait For Gump (Any)\r\n1078=Wait for Gump (#{0})\r\n1079=Wait for Target\r\n1080=Parar {0:#.00}sec\r\n1081=Wait for {0} {1} {2}\r\n1082=Cargando '{0}'...\r\n1083=> Parar macro actual\r\n1084=Empezar: {0}\r\n1085=Empezar macro '{0}'...\r\n1086=Macro '{0}' terminado.\r\n1087=Razor no pudo iniciarse: Codigo de error:\\n\r\n1088=Descripcion: No pudo encontrar la ventana del juego.\\nPosible Causa: El cliente no pudo iniciarse correctamente.\r\n1089=Descripcion: No pudo encontrar el ThreadID del cliente\\nPosible Causa: El cliente no pudo iniciarse correctamente.\r\n1090=Descripcion: No pudo crear los enlaces de Windows.\\nPosible Causa: Error Interno.\r\n1091=Descripcion: No pudo crear o tener acceso al Razor compartiendo memoria.\\nPosible Causa: Windows Error o permiso invalido.\r\n1092=Descripcion: Crypt.dll se ha inhabilitado.\\nPosible Causa: Version defectuosa.\r\n1093=Descripcion: No pudo parchear las funciones de Winsock del cliente.\\nPosible Causa: Error Interno, Windows Error, o Version Incompatible.\r\n1094=\r\n1095=Advertencia: No pudo copiar el tamao del paquete y/o informacion del cifrado del cliente.\\nRazor puede funcionar sin esta informacion, aunque algunas caracteristicas pueden no funcionar correctamente.Quieres ejecutar el Razor de todos modos?\\n\\nCausa Posible: Su version del cliente puede no ser compatible con esta version del Razor.\r\n1096=Tu habilidad de {0} ha cambiado por {1}{2:F1}, ahora esta en {3:F1}.\r\n1097=Abreviatura invalida.\r\n1098=ID del objeto invalido.\r\n1099=Hue invalido.\r\n1100=Seleccione un articulo para contar.\r\n1101=Error al cargar '{0}'!\\nEste perfil esta corrupto y no puede ser utilizado.\r\n1102=La caracteristica {0} no fue encontrada en este perfil.\r\n1103=Su archivo counters.xml esta corrupto y no puede ser utilizado.\r\n1104=El auto buscador esta desconectado, tendras que abrir de nuevo todas las bolsas para que el contador pueda utilizarse.\r\n1105=Advertencia: {0} cantidades ahora estan {1}!\r\n1106=Selecciona la tonalidad que deseas utilizar.\r\n1107=Hacer imagen ahora\r\n//1108=Posibles variantes:\\n{char} - Nombre del Personaje\\n{shard} - Nombre del Servidor\\n{str}/{hp}/{hpmax} - Estado de salud\\n{dex}/{stam}/{stammax} - Estado de destreza\\n{int}/{mana}/{manamax} - Estado de inteligencia\\n{weight}/{maxweight} - Informacion del Peso\\n{gold} - Total de Oro en la mochila\\n{AR} - Grado de Armadura / Resistencia Fisica\\n{tithe} - Puntos de Paladin\\n{bandage} - Tiempo en aplicar bendas\\n{statbar}/{mediumstatbar}/{largestatbar} - Barra de estado\\n{crimtime} - Tiempo total en estado Criminal\\n{stealthsteps} - Stealth steps counterColor - HTML hex color code: '~#rrggbb' ('~#~' to terminate)\\nOr a {Format} from the Counters list\r\n1109=Razor Version: {0}\\nMemory Usada: {1}\\nEnviado: {2} ({3}/s)\\nRecivido: {4} ({5}/s)\\nConectado durante {6}\\n\\nPlayer Serial: 0x{7:X8}\\nBackpack Serial: 0x{8:X8}\\n\\nTracking Items: {9}\\nTracking Mobs: {10}\\n\r\n1110=Set Lock: UP\r\n1111=Set Lock: DOWN\r\n1112=Set Lock: LOCKED\r\n1113=Estas seguro que quieres quitar el contador \"{0}\"?\\nEsto afectara a todos los perfiles.\r\n1114=Cargar perfil \"{0}\" ahora?\r\n1115=Se encontro un error al cargar el perfil.\r\n1116=No puedes suprimir el perfil por defecto.\r\n1117=Meter nombre para nuevo perfil: \r\n1118=No puedes crear un nuevo perfil!\\n Razon: Ya existe un perfil con ese nombre.\\n\\nQuieres cargar ese perfil?\r\n1119=Nombre para nueva lista de vestuario:\r\n1120=Suprimir esta lista?\r\n1121={0:X} (Objeto fuera de rango)\r\n1122=Suprimir este objeto de la lista?\r\n1123=Seleccione un bolso para depositar '{0}'.\r\n1124=Accion Undress en la bolsa.\r\n1125=Objeto no encontrado, o objeto invalido seleccionado.\r\n1126=Esa tecla pertenece ya a '{0}'.\\nCambiarlo a '{1}'?\r\n1127=Datos salvados con exitos.\r\n1128=Advertencia!\\nLos paquetes de registro pueden reducir el funcionamiento del Razor. Los ficheros de diario pueden tambien\\ncrecer facilmente, y el Razor no los quitara automaticamente.\\n\\nRazor's puede contener la informacion personal\\nclaves, y no lo facilite si no confia en el.\\n\\nEstas seguro que deseas permitir el registro del paquete?\\n\r\n1129=Convert Selected to TYPE\r\n1130=Meter nombre para nuevo macro: \r\n1131=Ese nombre contiene caracteres invalidos.\r\n1132=Ya existe una macro con ese nombre\r\n1133=Esta macro ya existe.\\nEstas seguro que deseas sobreescribir esta macro?\r\n1134=Estas seguro de suprimir PERMANENTEMENTE '{0}'?\\n\r\n1135=Insertar Pausa/Espera...\r\n1136=Insertar anterior objetivo\r\n1137=Subir\r\n1138=Bajar\r\n1139=Borrar accion\r\n1140=Comienza a registrar aqui\r\n1141=El archivo '{0}' no fue encontrado.\r\n1142=Estas seguro?\r\n1143=ADVERTENCIA: El siguiente {0} archivo{1} cuenta no ser suprimido:\\n{2}\r\n1144=Esta opcion funcionara la proxima vez que inicie el Razor.\r\n1145=Permitiendo esta opcion hara que Razor guarde su clave en su perfil.\\nAunque no es recomendable ya que podrian acceder al archivo xml de su perfil.\\nDesea permitir esta opcion?\r\n1146=Debes especificar un puerto valido.\r\n1147=Ignorar accion de peticion.\r\n1148=Peticion de poner en cola {0}... {1} izquierda.\r\n1149=Finalizado {0} acciones en espera en {1:F1} segundos.\r\n1150=Agente UnUso\r\n1151=Agregar (Objetivo)...\r\n1152=Agregar bolsa (Objetivo)...\r\n1153=Borrar (Objetivo)...\r\n1154=Borrar lista\r\n1155=Seleccione un objeto para agregar.\r\n1156=Seleccione un envase.\r\n1157=Seleccione un objeto para quitar.\r\n1158=Objeto Agregado.\r\n1159=Objeto Robado.\r\n1160={0} objeto(s) agregados al agente de UnUso.\r\n1161=Cola llena de UnUso!\r\n1162=Usando '{0}'.  ({1} objeto(s) dejando en espera de UnUso)\r\n1163=Habia un problema con uno de los articulos de UnUso, intentando el siguiente\r\n1164=AgenteVenta: Venta automatica de {0} objeto(s) por {1}gp.\r\n1165=Borrar\r\n1166=Envase fijado con exito.\r\n1167=Borrar lista\r\n1168=(Inhabilitar)\r\n1169=(Permitir)\r\n1170=Bolsa determinada\r\n1171=Quitar Bolsa\r\n1172=Organizar Agente\r\n1173=Organizar\r\n1174=Organizar ahora\r\n1175=Envase no fijado.\r\n1176=Razor no lo encontro su backpack.\r\n1177=Agente Organizador en cola {0} objeto(s) para mover.\r\n1178=Agente Organizador no encontro ningun objeto para mover.\r\n1179=Ese objeto ya esta en la lista.\r\n1180=AutoBusquedaExepciones\r\n1181=Agente de compra comprando {0} objeto(s) por {1}gp.\r\n1182=El agente de compra no puedo comprar algunos objetos por falta de dinero.\r\n1183=Introduce la cantidad:\r\n1184=Sistema de prioridad de proceso del cliente a{0}\r\n1185=El tiempo actual es: {0}\r\n1186=Estas en {0} en '{1}'\r\n1187=Soltar en el bolso no se pudo al no encontrarse, usando su mochila en lugar de otro.\r\n1188={0} objeto(s) en espera para desequipar.\r\n1189={0} objeto(s) en espera para equipar.\r\n1190={0} objeto(s) equipados ya.\r\n1191={0} objeto(s) no fueron encontrados.\r\n1192=ADVERTENCIA: Spells.def no encontrado, el formato del hechizo no sera mostrado\r\n1193=Pasos en Stealth: {0}\r\n1194=Contar pasos en Stealth.\r\n1195=Borrar objetivos en espera.\r\n1196=Atacar ultimo combate\r\n1197=Borrar objetivos en espera.\r\n1198=Nuevo Objetivo 'Ultimo Objetivo'\r\n1199=Marcar Ultimo Objetivo.\r\n1200=Marcar Nuevo Objetivo.\r\n1201=Nada que emparejaba fue encontrada en su pantalla.\r\n1202=Accion de marcarte en espera.\r\n1203=Ultimo marcado en espera.\r\n1204=Enviado nuevo objetivo, cancelado el objetivo.\r\n1205=Objetivo por tipo {0}\r\n1206=Limpiador\r\n1207=Deseas borrar esto?\r\n1208=Seleccionar carpeta para imagenes\r\n1209=Teclas\r\n1210=Objetos\r\n1211=Objetivos\r\n1212=Agentes\r\n1213=Equipar\r\n1214=Macros\r\n1215=Hechizos\r\n1216=Habilidades\r\n1217=Misc\r\n// 1219 - 1250 reserved\r\n1251=1st\r\n1252=2nd\r\n1253=3rd\r\n1254=4th\r\n1255=5th\r\n1256=6th\r\n1257=7th\r\n1258=8th\r\n// 1259 not used\r\n1260=Necromancia\r\n// 1261 - 1269 not used\r\n1270=Paladin\r\n1271=Pociones\r\n1272=Movimientos Especiales\r\n// 1273 - 1299 reserved\r\n1373=UnUso\r\n1301=Vender\r\n1302=Comprar\r\n1303=Requiere Entrar\r\n1304=Lista de Comandos\r\n1305=Usar Objeto disponible\r\n1306=Hay que desarmarse para armarse otra vez.\r\n1307=Arm/Disarm Mano Derecha\r\n1308=Arm/Disarm Mano Izquierda\r\n1309=Soltar lo que sustienes actualmente\r\n\r\n1311=> Activar/Desactivar Teclas Razor \r\n1312=Teclas Habilitadas (Presiona {0} para inhabilitar)\r\n1313=Teclas Inhabilitadas (Presiona {0} para habilitar)\r\n1314=Teclas Habilitadas\r\n1315=Teclas Inhabilitadas\r\n1316=Caminado: {0}\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.ita",
    "content": "// Razor Italian/ITA Language Pack\r\n// Author: Metro\r\n::CliLoc=ENU\r\n\r\n[controls]\r\nWelcomeForm::Text=Benvenuto su Razor!\r\nWelcomeForm::label5=Lingua:\r\nWelcomeForm::groupBox3=Profilo\r\nWelcomeForm::newProfile=Nuovo...\r\nWelcomeForm::label2=Profilo:\r\nWelcomeForm::groupBox2=Server\r\nWelcomeForm::label3=Server:\r\nWelcomeForm::label4=Porta:\r\nWelcomeForm::groupBox1=Opzioni Client\r\nWelcomeForm::makeDef=Imposta come predefinito\r\nWelcomeForm::browse=Sfoglia...\r\nWelcomeForm::label1=Client:\r\nWelcomeForm::patchEncy=Crittazione Client \r\nWelcomeForm::showAtStart=Mostra quando avvii Razor\r\nWelcomeForm::quit=&Chiudi\r\nWelcomeForm::okay=&OK\r\nMainForm::Text=Razor v{0} (Beta)\r\nMainForm::generalTab=Generale\r\nMainForm::label7=Lingua:\r\nMainForm::rememberPwds=Ricorda password \r\nMainForm::systray=System Tray\r\nMainForm::taskbar=Taskbar\r\nMainForm::label11=Mostra:\r\nMainForm::groupBox4=Profili\r\nMainForm::delProfile=Elimina\r\nMainForm::newProfile=&Nuovo...\r\nMainForm::showWelcome=Mostra finestra di benvenuto\r\nMainForm::alwaysTop=Sempre in primo piano\r\nMainForm::groupBox1=Filtri\r\nMainForm::opacityLabel=Opaco: 100%\r\nMainForm::moreOptTab=Opzioni\r\nMainForm::logPackets=Abilita packet logging\r\nMainForm::incomingCorpse=Mostra nomi dei corpi\r\nMainForm::incomingMob=Mostra nomi delle creature\r\nMainForm::setHarmHue=Set\r\nMainForm::setNeuHue=Set\r\nMainForm::lblHarmHue=Malvagio\r\nMainForm::lblNeuHue=Neutrale\r\nMainForm::lblBeneHue=Buono\r\nMainForm::setBeneHue=Set\r\nMainForm::setSpeechHue=Set\r\nMainForm::setWarnHue=Set\r\nMainForm::setMsgHue=Set\r\nMainForm::setExHue=Set\r\nMainForm::autoStackRes=Auto-Posa Minerali/Pesce/Legna a terra\r\nMainForm::queueTargets=Accoda LastTarget e TargetSelf\r\nMainForm::spamFilter=Filtro spam (sperimentale)\r\nMainForm::label4=tile\r\nMainForm::openCorpses=Apri nuovi corpi da\r\nMainForm::showNotoHue=Mostra colori {char} Nella TitleBar\r\nMainForm::lblWarnHue=Colore Msg Pericolo\r\nMainForm::lblMsgHue=Colore Msg Razor\r\nMainForm::lblExHue=Colore Ricerca Items\r\nMainForm::chkStealth=Conta Passi in Stealth\r\nMainForm::chkForceSpellHue=Colori Spells:\r\nMainForm::chkForceSpeechHue=Colore Speech\r\nMainForm::label3=Formato:\r\nMainForm::moreMoreOptTab=Altre Opzioni\r\nMainForm::label8=tile\r\nMainForm::rangeCheckLT=Dist. check LastTarget:\r\nMainForm::spellUnequip=Auto-Libera mani prima di castare\r\nMainForm::actionStatusMsg=Mostra Messaggio Action-Queue\r\nMainForm::label6=ms\r\nMainForm::label5=Intervallo obj:\r\nMainForm::QueueActions=Auto-Accoda azioni intervallo oggetti \r\nMainForm::displayTab=Display/Contatori\r\nMainForm::highlightSpellReags=Evidenzia reagenti al cast\r\nMainForm::titlebarImages=Mostra immagini+contatori\r\nMainForm::sortCounters=Ordina i contatori\r\nMainForm::checkNewConts=Auto-cerca nuovi contenitori\r\nMainForm::warnCount=Avvisa quando un item e' a:\r\nMainForm::groupBox3=Display Barra titoli\r\nMainForm::showInBar=Mostra nella barra di UO:\r\nMainForm::groupBox2=Contatori\r\nMainForm::delCounter=Del/Edit\r\nMainForm::addCounter=Add...\r\nMainForm::recount=Recount\r\nMainForm::dressTab=Arm/Dress\r\nMainForm::groupBox6=Oggetti Arm/Dress\r\nMainForm::clearDress=Svuota Lista\r\nMainForm::dressDelSel=Rimuovi\r\nMainForm::undressBag=Cambia borsa Undress\r\nMainForm::undressList=Undress\r\nMainForm::dressUseCur=Aggiungi Item\r\nMainForm::targItem=Aggiungi(Target)\r\nMainForm::dressNow=Dress\r\nMainForm::groupBox5=Selezione Arm/Dress\r\nMainForm::removeDress=Rimuovi\r\nMainForm::addDress=Aggiungi\r\nMainForm::undressConflicts=Sposta items in conflitto\r\nMainForm::agentsTab=Agenti\r\nMainForm::hotkeysTab=Tasti\r\nMainForm::dohotkey=Esegui Selezionato\r\nMainForm::groupBox8=Tasto\r\nMainForm::chkPass=Passa ad UO\r\nMainForm::label2=Key:\r\nMainForm::unsetHK=Unset\r\nMainForm::setHK=Set\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Macro\r\nMainForm::macroActGroup=Azioni\r\nMainForm::loopMacro=Ripeti\r\nMainForm::recMacro=Record\r\nMainForm::playMacro=Usa\r\nMainForm::delMacro=Rimuovi\r\nMainForm::newMacro=Nuova...\r\nMainForm::skillsTab=Skills\r\nMainForm::dispDelta=Show Changes\r\nMainForm::skillCopyAll=Copia Tutto\r\nMainForm::skillCopySel=Copia Selezionato\r\nMainForm::label1=Totale base:\r\nMainForm::setlocks=Setta tutti:\r\nMainForm::resetDelta=Reset  +/-\r\nMainForm::screenshotTab=Screen Shots\r\nMainForm::capNow=Scatta\r\nMainForm::radioUO=Solo UO\r\nMainForm::radioFull=Tutto\r\nMainForm::screenAutoCap=Auto-Screen quando muori\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Aggiungi Tempo agli Screen\r\nMainForm::statusTab=Aiuto && Status\r\nMainForm::visitForums=Aiuto && Supporto Forum\r\nMainForm::visitHome=Razor Homepage\r\nMainForm::visitGuide=Guida a Razor\r\nHueEntry::Text=Selez. colore\r\nHueEntry::cancel=Cancel\r\nHueEntry::okay=&OK\r\nHueEntry::preview=Preview\r\nHueEntry::inGame=Selez. in Game\r\nHueEntry::label1=Numero:\r\nAddCounter::Text=Counter Editor\r\nAddCounter::delete=Delete\r\nAddCounter::target=Target \r\nAddCounter::cancel=Cancel\r\nAddCounter::Add=&OK\r\nAddCounter::label4=Colore(No: -1):\r\nAddCounter::label3=Item ID:\r\nAddCounter::label2=Formato:\r\nAddCounter::label1=Nome:\r\nMacroInsertWait::Text=Inserisci pausa...\r\nMacroInsertWait::radioMenu=Wait for old-style Menu/Dialog\r\nMacroInsertWait::cancel=&Cancel\r\nMacroInsertWait::radioStat=Wait for \r\nMacroInsertWait::radioTarg=Wait for Target\r\nMacroInsertWait::radioGump=Wait for Gump\r\nMacroInsertWait::label1=millisecondi\r\nMacroInsertWait::radioPause=Pausa:\r\nMacroInsertWait::insert=&Insert\r\n\r\n[strings]\r\n1001=Death Status\r\n1002=Bards' Music\r\n1003=Dog Sounds\r\n1004=Cat Sounds\r\n1005=Horse Sounds\r\n1006=Sheep Sounds\r\n1007=Spirit Speak Sound\r\n1008=Spell Fizzle Sound\r\n1009=Weather\r\n1010=Mostra Contatori\r\n1011=Riconta Contatori\r\n1012=Clear AOS Ability\r\n1013=Set Primary Ability (AOS)\r\n1014=Set Secondary Ability (AOS)\r\n1015=Toggle Stun (Pre-AOS)\r\n1016=Toggle Disarm (Pre-AOS)\r\n1017=Setting ability {0}\r\n1018=AOS abilities cleared.\r\n1019=Undress All\r\n1020=Undress Due Mani\r\n1021=Undress Mano Sinistra\r\n1022=Undress Mano Destra\r\n1023=Undress Cappello\r\n1024=Undress Gioielli\r\n1025=Bandage Self\r\n1026=Bandage LastTarget\r\n1027=Use Bandage (No Timer)\r\n1028=Drink Heal\r\n1029=Drink Cure\r\n1030=Drink Refresh\r\n1031=Drink Night Sight\r\n1032=Drink Explosion\r\n1033=Drink Strength\r\n1034=Drink Agility\r\n1035=Bende non trovate!\r\n1036=Nessun item {0} trovato!\r\n1037=Doppio Click ({0})\r\n1038=Re-Target\r\n1039=Converti a DClick by Type\r\n1040=Seleziona nuovo target per l'azione.\r\n1041=WARNING: Exception while loading profile property:\\n{0}\r\n1042=Macro Warning: Item non trovato (Fuori Range).\r\n1043=Lift {1} - {0}\r\n1044=Convert to Lift by Type\r\n1045=Macro Warning: Niente in mano.\r\n1046=Equip to {0}\r\n1047=Drop to {0} (@{1})\r\n1048=Converti a Relative Location\r\n1049=Drop (Relative) @({0},{1},{2})\r\n1050=GumpResponse (Button {0})\r\n1051=Close Gump\r\n1052=MenuResponse {0}\r\n1053=Warning: Macro requested target, but no target sent from server! (Do you need a 'WaitForTarget'?)\r\n1054=Absolute Target\r\n1055=Converti a LastTarget\r\n1056=Converti a Target by Type\r\n1057=Target RelLoc ({0},{1})\r\n1058=Last Target\r\n1059=Target Self\r\n1060=Set Last Target\r\n1061=Target Random Red\r\n1062=Target Random Grey\r\n1063=Target Random Blue\r\n1064=Target Random Enemy\r\n1065=Target Random Friendly\r\n1066=Target Random Non-Friendly\r\n1067=Say \"{0}\"\r\n1068=UseSkill {0}\r\n1069=CastSpell {0}\r\n1070=SetAbility {0}\r\n1071=Dress: {0}\r\n1072=Undress: {0}\r\n1073=Unequip Layer {0}\r\n1074=Wait for Menu (Any)\r\n1075=Wait for Menu (#{0})\r\n1076=Configura\r\n1077=Wait For Gump (Any)\r\n1078=Wait for Gump (#{0})\r\n1079=Wait for Target\r\n1080=Pause {0:#.00}sec\r\n1081=Wait for {0} {1} {2}\r\n1082=Loading '{0}'...\r\n1083=> Ferma Macro Corrente\r\n1084=Play: {0}\r\n1085=Macro '{0}' iniziata...\r\n1086=Macro '{0}' terminata.\r\n1087=Razor was unable to initialize.  Error code:\\n\r\n1088=Description: Could not find the client Window Handle.\\nPossible Cause: The Client may not have initialized properly.\r\n1089=Description: Could not find the Client's ThreadID\\nPossible Cause: The Client may not have initialized Properly.\r\n1090=Description: Could not create Windows Hooks.\\nPossible Cause: Internal error.\r\n1091=Description: Could not create or access Razor shared memory.\\nPossible Cause: Windows Error or invalid permissions.\r\n1092=Description: Crypt.dll has disabled itself.\\nPossible Cause: Version mismatch.\r\n1093=Description: Could not patch the client's Winsock functions.\\nPossible Cause: Internal error, Windows Error, or Incompatible Version.\r\n1094=\r\n1095=Warning: Could not copy packet lengths and/or encryption information from the client.\\nRazor may be able to run without this information, though some features may not function correctly.  Would you like to start Razor anyway?\\n\\nPossible Cause: Your client version may not be compatible with this version of Razor.\r\n1096=La tua skill {0} e' cambiata di {1}{2:F1}, ora e' {3:F1}.\r\n1097=Invalid abbreviation.\r\n1098=Invalid item id.\r\n1099=Invalid hue.\r\n1100=Seleziona item da contare.\r\n1101=Errore caricamento '{0}'!\\nQuesto profilo e' corrotto e non puo' essere usato.\r\n1102=La proprieta' {0} non e' stata trovata nel profilo.\r\n1103=Il file counters.xml e' corrotto e non puo' essere usato.\r\n1104=Siccome hai l'Auto Search Containers off, riapri le borse per far si' che il contatore si aggiorni.\r\n1105=Attenzione: la quantita' di {0} e' ora {1}!\r\n1106=Scegli il colore da usare.\r\n1107=Fotografa Ora\r\n//1108=Possible values:\\n{char} - nome Character\\n{shard} - nome Shard\\n{str}/{hp}/{hpmax} - Status Salute\\n{dex}/{stam}/{stammax} - Status Dex\\n{int}/{mana}/{manamax} - Status Int\\n{weight}/{maxweight} - Weight information\\n{gold} - Total Gold on character\\n{AR} - Armor Rating / Physical Resistance\\n{tithe} - Tithing points\\n{bandage} - Bandage Timer\\n{statbar}/{mediumstatbar}/{largestatbar} - Status bar\\n{crimtime} - How long you have been a criminal\\n{stealthsteps} - Stealth steps counterColor - HTML hex color code: '~#rrggbb' ('~#~' to terminate)\\nOr a {Format} from the Counters list\r\n1109=Versione Razor: {0} (ITA by Tyler - UOD)\\nMemoria usata: {1}\\nInv: {2} ({3}/s)\\nRicev: {4} ({5}/s)\\nConnesso da {6}\\n\\nPlayer Serial: 0x{7:X8}\\nBackpack Serial: 0x{8:X8}\\n\\nTracking Items: {9}\\nTracking Mobs: {10}\\n\r\n1110=Set Lock: UP\r\n1111=Set Lock: DOWN\r\n1112=Set Lock: LOCKED\r\n1113=Sei sicuro di voler rimuovere il counter \"{0}\"?\\nL'effetto avverra' su tutti i profili.\r\n1114=Caricare profilo \"{0}\" ora?\r\n1115=Errore nel caricamento del profilo.\r\n1116=Non puo cancellare il profilo Default.\r\n1117=Inserisci nome del nuovo profilo: \r\n1118=Impossibile creare nuovo profilo!\\n Motivo: Esiste gia' un profilo con questo nome.\\n\\nVuoi caricare quel profilo ora?\r\n1119=Inserire nome della nuova list:\r\n1120=Cancellare questa list?\r\n1121={0:X} (Item fuori range)\r\n1122=Cancellare questo item dalla list?\r\n1123=Seleziona borsa per l'Undress in '{0}'.\r\n1124=Settata borsa Undress.\r\n1125=Item non trovato o item non valido.\r\n1126=Questa combinazione appartiene a '{0}'.\\nCambiare a '{1}'?\r\n1127=Salvataggio effettuato.\r\n1128=Warning!\\nLogging packets may reduce Razor's performance. Log files can also\\neasily grow very large, and Razor will not automatically remove them.\\n\\nRazor's packet log files may contain personal information such as\\npasswords, and should be not be given to people you do not trust.\\n\\nAre you sure you want to enable packet logging?\\n(This will not be saved in your user profile)\r\n1129=Converti Selected a TYPE\r\n1130=Inserisci nome della nuova macro: \r\n1131=Il nome contiene caratteri non validi.\r\n1132=C'e' gia' una macro con questo nome.\r\n1133=Questa macro sara' pulita prima di registrare.\\nSei sicuro di voler registrare la macro?\r\n1134=Sei sicuro di voler cancellare definitvamente '{0}'?\r\n1135=Inserisci Pausa...\r\n1136=Inserisci Set LastTarget\r\n1137=Muovi su\r\n1138=Muovi giu\r\n1139=Rimuovi Azione\r\n1140=Registra da qui\r\n1141=Il file '{0}' non e' stato trovato.\r\n1142=Sei sicuro?\r\n1143=Attenzione: The following {0} file{1} count non e' cancellato:\\n{2}\r\n1144=Questo cambiamento avra' effetto al prossimo riavvio.\r\n1145=Abilitando questa opzione, Razor salvera' le tue password nel tuo profilo.\\nAnche se le password sono crittate, e' possibile usarle avendo accesso al file xml del profilo.\\nSei sicuro di voler attivare questa funzione?\r\n1146=Devi specificare una porta valida.\r\n1147=Ignorata richiesta di azione (gia' in coda).\r\n1148=Accodate {0}... {1} left.\r\n1149=Eseguite {0} azioni in {1:F1} secondi.\r\n1150=Use Once Agent\r\n1151=Aggiungi(Target)\r\n1152=Contenitore(Target)\r\n1153=Rimuovi(Target)\r\n1154=Pulisci Lista\r\n1155=Seleziona item da aggiungere.\r\n1156=Seleziona Contenitore.\r\n1157=Seleziona item da rimuovere.\r\n1158=Item aggiunto.\r\n1159=Item rimosso.\r\n1160={0} item(s) aggiunti all'UseOnce Agent.\r\n1161=La UseOnceQueue e' vuota!\r\n1162=Using '{0}'.  ({1} item(s) left in the UseOnce queue)\r\n1163=C'e' stato un problema con un UseOnce item, proviamo col prossimo.\r\n1164=SellAgent: Sta vendendo {0} item(s) per {1}gp.\r\n1165=Rimuovi\r\n1166=Container settato con successo.\r\n1167=Pulisci\r\n1168=(Premi per Disattivare)\r\n1169=(Premi per Attivare)\r\n1170=Setta Hot Bag\r\n1171=Pulisci HotBag\r\n1172=Organizer Agent\r\n1173=Organizer\r\n1174=Organizza Ora\r\n1175=Contenitore non settato.\r\n1176=Razor non trova il tuo backpack.\r\n1177=L'OrganizeAgent ha accodato {0} item(s) per essere mossi. (Puo' richiedere alcuni minuti)\r\n1178=L'OrganizeAgent non ha trovato item da muovere.\r\n1179=Questo item e' gia nella list.\r\n1180=AutoSearchExemptions\r\n1181=Buy Agent ha comprato {0} item(s) per {1}gp.\r\n1182=Il BuyAgent non puo' comprare gli oggetti della BuyList perche' non hai abbastanza soldi.\r\n1183=Inserisci num:\r\n1184=Priorita' Client settato a {0}\r\n1185=Il tempo e': {0}\r\n1186=Tu sei al {0} in '{1}'\r\n1187=Borsa Undress non trovata, usato il backpack.\r\n1188={0} item(s) accodato per essere non-equipaggiato.\r\n1189={0} item(s) accodato per essere equipaggiato.\r\n1190={0} item(s) gia' equipaggiato.\r\n1191={0} item(s) were not found. (Out of Range)\r\n1192=Attenzione: Spells.def non trovato, il formato di testo non sara' mostrato\r\n1193=Passi Stealth: {0}\r\n1194=Inizio conta passi Stealth.\r\n1195=Pulisci TargetQueue\r\n1196=AttackLast\r\n1197=TargetQueue pulita.\r\n1198=Seleziona un nuovo 'Last Target'\r\n1199=Last Target set.\r\n1200=New target set.\r\n1201=Nulla di corrispondente trovato.\r\n1202=Queued target self.\r\n1203=Queued last target.\r\n1204=Il Server ha inviato nuovo target, cancellato il target di Razor.\r\n1205=Target by Type {0}\r\n1206=Scavenger\r\n1207=Sei sicuro di voler cancellare questo?\r\n1208=Seleziona cartella per i Razor ScreenShot.\r\n1209=Tasti\r\n1210=Oggetti\r\n1211=Targets\r\n1212=Agenti\r\n1213=Dress\r\n1214=Macro\r\n1215=Spells\r\n1216=Skills\r\n1217=Misc\r\n// 1219 - 1250 reserved\r\n1251=1st\r\n1252=2nd\r\n1253=3rd\r\n1254=4th\r\n1255=5th\r\n1256=6th\r\n1257=7th\r\n1258=8th\r\n// 1259 not used\r\n1260=Necromancy\r\n// 1261 - 1269 not used\r\n1270=Chivalry\r\n1271=Potions\r\n1272=Special Moves\r\n// 1273 - 1299 reserved\r\n1373=UseOnce\r\n1301=Vendi\r\n1302=Compra\r\n1303=Input Richiesto\r\n1304=Lista Comandi Razor\r\n1305=Usa l'oggetto in mano\r\n1306=Devi disarmare l'oggetto prima di poterlo riarmare.\r\n1307=Arm/Disarm Mano Destra\r\n1308=Arm/Disarm Mano Sinistra\r\n1309=Lascia quel che stai tenendo\r\n\r\n1311=> Attiva/Disattiva Macro Razor\r\n1312=Macro Attivate({0} per disattivare)\r\n1313=Macro Disattivate ({0} per attivare)\r\n1314=MAcro Attive\r\n1315=Macro Inattive\r\n1316=Walk: {0}\r\n1317=Add Type (Target)...\r\n1318=Il target richiesto e' fuori range, LastTarget non eseguito!\r\n1319=Max Sell: {0}\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.pl",
    "content": "// Razor Polish/PL Language Pack\r\n// Last Modified August 5, 2007\r\n// Author: exile (exile(at)team-voe.com)\r\n::CliLoc=ENU\r\n\r\n[controls]\r\nWelcomeForm::Text=Razor wita!\r\nWelcomeForm::groupBox3=Katalog UO\r\nWelcomeForm::dataBrowse=Wskaz\r\nWelcomeForm::label5=Jezyk:\r\nWelcomeForm::groupBox2=Serwer\r\nWelcomeForm::label3=Serwer:\r\nWelcomeForm::label4=Port:\r\nWelcomeForm::groupBox1=Opcje klienta.\r\nWelcomeForm::useEnc=Uzywaj kodowania OSI\r\nWelcomeForm::makeDef=Zapisz domyslne ustawienia\r\nWelcomeForm::browse=Wskaz\r\nWelcomeForm::label1=Klient:\r\nWelcomeForm::patchEncy=Usun kodowanie\r\nWelcomeForm::showAtStart=Pokazuj to okno na poczatku\r\nWelcomeForm::quit=&Zamknij\r\nWelcomeForm::okay=&OK\r\n\r\nMainForm::Text=Razor\r\nMainForm::generalTab=Glowne\r\nMainForm::label10=Uaktualnij\r\nMainForm::systray=Tray systemowy\r\nMainForm::taskbar=Pasek zadan\r\nMainForm::smartCPU=Zmniejszenie obciazenia CPU\r\nMainForm::label7=Jezyk:\r\nMainForm::label11=Pokazuj na:\r\nMainForm::groupBox4=Profile\r\nMainForm::delProfile=Skasuj\r\nMainForm::newProfile=&Nowy...\r\nMainForm::showWelcome=Pokazuj ekran powitalny\r\nMainForm::alwaysTop=Zawsze na wierzchu\r\nMainForm::groupBox1=Filtry\r\nMainForm::opacityLabel=Przenikanie: 100%\r\nMainForm::moreOptTab=Opcje\r\nMainForm::setLTHilight=Ustaw\r\nMainForm::lthilight=Podswietlanie ostatniego celu:\r\nMainForm::filterSnoop=Filtruj komunikaty Snoopingu\r\nMainForm::incomingCorpse=Pokazuj nazwy zwlok\r\nMainForm::incomingMob=Pokazuj nazwy istot\r\nMainForm::setHarmHue=Ustaw\r\nMainForm::setNeuHue=Ustaw\r\nMainForm::lblHarmHue=Wrog\r\nMainForm::lblNeuHue=Neutralny\r\nMainForm::lblBeneHue=Sojusznik\r\nMainForm::setBeneHue=Ustaw\r\nMainForm::setSpeechHue=Ustaw\r\nMainForm::setWarnHue=Ustaw\r\nMainForm::setMsgHue=Ustaw\r\nMainForm::setExHue=Ustaw\r\nMainForm::autoStackRes=Automatycznie sortuj surowce\r\nMainForm::queueTargets=Kolejkuj LastTarget i TargetSelf\r\nMainForm::spamFilter=Filtruj powtarzajace sie wiadomosci\r\nMainForm::label4=kratek\r\nMainForm::openCorpses=Otworz ciala w zasiegu\r\nMainForm::showNotoHue=Koloruj imie na pasku tytulowym\r\nMainForm::lblWarnHue=Barwa ostrzezenia\r\nMainForm::lblMsgHue=Barwa wiadomosci Razora\r\nMainForm::lblExHue=Barwa Agenta przeszukiwania\r\nMainForm::blockDis=Blokuj zsiadanie w trybie walki\r\nMainForm::chkForceSpellHue=Kolor czarow:\r\nMainForm::chkForceSpeechHue=Kolor mowy:\r\nMainForm::label3=Format czarow:\r\nMainForm::moreMoreOptTab=Wiecej opcji\r\nMainForm::label18=Rozdzielczosc:\r\nMainForm::label17=Komunikaty Razora:\r\nMainForm::QueueActions=Auto-kolejkowanie czynnosci \r\nMainForm::spellUnequip=Czarowanie bez broni\r\nMainForm::autoOpenDoors=Auto-otwieranie drzwi\r\nMainForm::alwaysStealth=Pokazuj ilosc krokow stealth\r\nMainForm::autoFriend=Czlonek Party jako Przyjaciel\r\nMainForm::chkStealth=Licz kroki stealth\r\nMainForm::rememberPwds=Pamietaj hasla\r\nMainForm::showtargtext=Pokazuj typ celu po kliknieciu\r\nMainForm::smartLT=Uzyj sprytnego LastTarget\r\nMainForm::preAOSstatbar=Uzywaj malego statusu\r\nMainForm::logPackets=Logowanie pakietow\r\nMainForm::warnCount=Ostrzegaj gdy licznik ponizej:\r\nMainForm::rangeCheckLT=Zasieg LastTarget:\r\nMainForm::actionStatusMsg=Pokazuj komunikaty kolejki\r\nMainForm::label5=Opoznienie:\r\nMainForm::label9=Priorytet klienta:\r\nMainForm::label8=kratek\r\nMainForm::label6=ms\r\nMainForm::displayTab=Liczniki\r\nMainForm::excludePouches=Nie przeszukuj mieszkow\r\nMainForm::highlightSpellReags=Podswietlaj skladniki\r\nMainForm::titlebarImages=Pokazuj ikony przedmiotow\r\nMainForm::sortCounters=Sortuj wyswietlane rzeczy\r\nMainForm::checkNewConts=Przeszukuj nowe kontenery\r\nMainForm::groupBox3=Wyswietlanie na pasku\r\nMainForm::showInBar=Pokazuj na pasku UO:\r\nMainForm::groupBox2=Liczniki\r\nMainForm::delCounter=Usun/Edycja\r\nMainForm::addCounter=Dodaj\r\nMainForm::recount=Przelicz\r\nMainForm::dressTab=Ubieranie\r\nMainForm::groupBox6=Ubierz/Uzbroj\r\nMainForm::clearDress=Wyczysc liste\r\nMainForm::dressDelSel=Usun\r\nMainForm::undressBag=Zmien torbe na rzeczy\r\nMainForm::undressList=Rozbierz\r\nMainForm::dressUseCur=Dodaj obecne\r\nMainForm::targItem=Dodaj (Cel)\r\nMainForm::dressNow=Ubierz\r\nMainForm::groupBox5=Wybor\r\nMainForm::removeDress=Usun\r\nMainForm::addDress=Dodaj\r\nMainForm::undressConflicts=Przesun kolidujace przedmioty\r\nMainForm::skillsTab=Umiejetnosci\r\nMainForm::dispDelta=Pokaz zmiany\r\nMainForm::skillCopyAll=Kopiuj calosc\r\nMainForm::skillCopySel=Kopiuj wybor\r\nMainForm::label1=Suma:\r\nMainForm::setlocks=Blokuj:\r\nMainForm::resetDelta=Reset  +/-\r\nMainForm::agentsTab=Agenci\r\nMainForm::hotkeysTab=Klawiatura\r\nMainForm::dohotkey=Wykonaj wybrane\r\nMainForm::groupBox8=Klawisz\r\nMainForm::chkPass=Przekaz do UO\r\nMainForm::label2=Klawisz:\r\nMainForm::unsetHK=Usun\r\nMainForm::setHK=Ustaw\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Makra\r\nMainForm::macroActGroup=Akcje\r\nMainForm::loopMacro=Petla\r\nMainForm::recMacro=Nagraj\r\nMainForm::playMacro=Odtworz\r\nMainForm::delMacro=Usun\r\nMainForm::newMacro=Nowe\r\nMainForm::screenshotTab=Zrzut ekranu\r\nMainForm::label12=Format:\r\nMainForm::capNow=Zrob teraz\r\nMainForm::radioUO=Tylko UO\r\nMainForm::radioFull=Pelen ekran\r\nMainForm::screenAutoCap=Automatycznie przy smierci\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Dodaj date i czas\r\nMainForm::videoTab=Nagrywanie Video\r\nMainForm::recFolder=...\r\nMainForm::label13=Folder nagran:\r\nMainForm::groupBox7=Nagrywanie PacketVideo\r\nMainForm::vidRec=Nagraj PacketVideo\r\nMainForm::groupBox10=Nagrywanie AVI\r\nMainForm::recAVI=Nagraj AVI...\r\nMainForm::label16=Rozdzielczosc:\r\nMainForm::label15=FPS:\r\nMainForm::groupBox9=Odtwarzanie PacketVideo\r\nMainForm::label14=Predkosc:\r\nMainForm::vidClose=Zamknij\r\nMainForm::vidPlayStop=Stop\r\nMainForm::vidPlay=Pusc\r\nMainForm::vidOpen=Otworz...\r\nMainForm::statusTab=Pomoc\r\nMainForm::rebirth=Jedyny PreT2A Shard\r\nMainForm::visitForums=Forum Pomocy i wsparcia\r\nMainForm::visitHome=Strona Razor'a\r\nMainForm::visitGuide=Podrecznik Razor'a\r\n\r\nHueEntry::Text=Wybierz barwe\r\nHueEntry::cancel=Przerwij\r\nHueEntry::okay=&Okay\r\nHueEntry::preview=Podglad\r\nHueEntry::inGame=Wybierz w grze\r\nHueEntry::label1=Numer barwy:\r\n\r\nAddCounter::Text=Dodaj licznik\r\nAddCounter::delete=Skasuj\r\nAddCounter::target=Cel \r\nAddCounter::cancel=Przerwij\r\nAddCounter::Add=&Okay\r\nAddCounter::label4=Kolor (obojetnie: -1):\r\nAddCounter::label3=ID przedmiotu:\r\nAddCounter::label2=Format:\r\nAddCounter::label1=Nazwa:\r\n\r\nMacroInsertWait::Text=Insert Wait/Pause...\r\nMacroInsertWait::radioMenu=Wait for old-style Menu/Dialog\r\nMacroInsertWait::cancel=&Cancel\r\nMacroInsertWait::radioStat=Wait for \r\nMacroInsertWait::radioTarg=Wait for Target\r\nMacroInsertWait::radioGump=Wait for Gump\r\nMacroInsertWait::label1=millisekund\r\nMacroInsertWait::radioPause=Pause na:\r\nMacroInsertWait::insert=&Wstaw\r\n\r\nMacroInsertIf::Text=Wstaw If...\r\nMacroInsertIf::label1=If:\r\nMacroInsertIf::cancel=&przerwij\r\nMacroInsertIf::insert=&wstaw\r\n\r\n\r\n\r\n[strings]\r\n1001=Status smierci\r\n1002=Muzyka barda\r\n1003=Dzwiek psa\r\n1004=Dzwiek kota\r\n1005=Dzwiek konia\r\n1006=Dzwiek owcy\r\n1007=Dzwiek Spirit Speak\r\n1008=Dzwiek czaru\r\n1009=Pogoda\r\n1010=Wyswietl liczniki\r\n1011=Przelicz liczniki\r\n1012=Wyczysc Umiejetnosc AOS\r\n1013=Ustaw pierwsza umiejetnosc (AOS)\r\n1014=Ustaw druga umiejetnosc (AOS)\r\n1015=wlacz ogluszanie (Pre-AOS)\r\n1016=Wlacz rozbrajanie(Pre-AOS)\r\n1017=Ustawiam umiejetnosc {0}\r\n1018=Umiejetnosci AOS wyczyszczone.\r\n1019=Zdejmij wszystko\r\n1020=Oproznij obie rece\r\n1021=Oproznij lewa dlon\r\n1022=Oproznij prawa dlon\r\n1023=Zdejmij nakrycie glowy\r\n1024=Zdejmij nizuterie\r\n1025=Bandazuj siebie\r\n1026=Bandazuj Ostatni cel\r\n1027=Uzyj bandaza\r\n1028=Drink Heal\r\n1029=Drink Cure\r\n1030=Drink Refresh\r\n1031=Drink Night Sight\r\n1032=Drink Explosion\r\n1033=Drink Strength\r\n1034=Drink Agility\r\n1035=Brak bandazy\r\n1036=Brak przedmiotu typu {0}!\r\n1037=Double Click ({0})\r\n1038=Re-Target\r\n1039=Convert to DClick by Type\r\n1040=Select a new target this Action.\r\n1041=WARNING: Exception while loading profile property:\\n{0}\r\n1042=Macro Warning: Cannot find that item (Out of Range).\r\n1043=Lift {1} - {0}\r\n1044=Convert to Lift by Type\r\n1045=Macro Warning: Not holding anything.\r\n1046=Equip to {0} (L:{1})\r\n1047=Drop to {0} (@{1})\r\n1048=Convert to Relative Location\r\n1049=Drop (Relative) @({0},{1},{2})\r\n1050=GumpResponse (Button {0})\r\n1051=Close Gump\r\n1052=MenuResponse {0}\r\n1053=Warning: Macro requested target, but no target sent from server! (Do you need a 'WaitForTarget'?)\r\n1054=Absolute Target\r\n1055=Convert to LastTarget\r\n1056=Convert to Target by Type\r\n1057=Target RelLoc ({0},{1})\r\n1058=Ostatni Cel\r\n1059=Wskaz siebie\r\n1060=Wskaz Ostatni Cel\r\n1061=Wskaz dowolnego Reda\r\n1062=Wskaz dowolnego Crima\r\n1063=Wskaz dowolnego Blue\r\n1064=Wskaz dowolnego wroga\r\n1065=Wskaz dowolnego przyjaciela\r\n1066=Wskaz dowolnego nieprzyjaciela\r\n1067=Mow \"{0}\"\r\n1068=UseSkill {0}\r\n1069=CastSpell {0}\r\n1070=SetAbility {0}\r\n1071=Ubierz: {0}\r\n1072=Rozbierz: {0}\r\n1073=Unequip Layer {0}\r\n1074=Wait for Menu (Any)\r\n1075=Wait for Menu (#{0})\r\n1076=Edycja...\r\n1077=Wait For Gump (Any)\r\n1078=Wait for Gump (#{0})\r\n1079=Wait for Target\r\n1080=Pause {0:#.00}sec\r\n1081=Wait for {0} {1} {2}\r\n1082=Loading '{0}'...\r\n1083=> Zatrzymaj makro\r\n1084=Play: {0}\r\n1085=Makro '{0}'...\r\n1086=Makro '{0}' zakonczone.\r\n1087=Razor was unable to initialize.  Error code:\\n\r\n1088=Description: Could not find the client Window Handle.\\nPossible Cause: The Client may not have initialized properly.\r\n1089=Description: Could not find the Client's ThreadID\\nPossible Cause: The Client may not have initialized Properly.\r\n1090=Description: Could not create Windows Hooks.\\nPossible Cause: Internal error.\r\n1091=Description: Could not create or access Razor shared memory.\\nPossible Cause: Windows Error or invalid permissions.\r\n1092=Description: Crypt.dll has disabled itself.\\nPossible Cause: Version mismatch.\r\n1093=Description: Could not patch the client's Winsock functions.\\nPossible Cause: Internal error, Windows Error, or Incompatible Version.\r\n1094=\r\n1095=Warning: Could not copy packet lengths and/or encryption information from the client.\\nRazor may be able to run without this information, though some features may not function correctly.  Would you like to start Razor anyway?\\n\\nPossible Cause: Your client version may not be compatible with this version of Razor.\r\n1096=Umiejetnosc {0} wzrosla o {4}{5:F1}, wynosi teraz {3:F1} ({1}{2:F1}).\r\n1097=Zly skrot.\r\n1098=Zle id przedmotu.\r\n1099=Zla barwa.\r\n1100=Wybierz przedmiot do liczenia.\r\n1101=Error loading '{0}'!\\nThis profile is corrupt and cannot be used.\r\n1102=The property {0} was not found in this profile.\r\n1103=Your counters.xml file is corrupt and cannot be used.\r\n1104=Because you have Auto Search Containers off, you must now reopen all of your bags so that your counters can be updated.\r\n1105=Uwaga: Ilosc {0} = {1}!\r\n1106=Wybierz barwe.\r\n1107=Zrob zrzut ekranu\r\n//1108=Mozliwe wartosci:\\n{char} - imie postaci\\n{shard} - nazwa shardu\\n{str}/{hp}/{hpmax} - stan zdrowia\\n{dex}/{stam}/{stammax} - stan staminy\\n{int}/{mana}/{manamax} - stan many\\n{weight}/{maxweight} - waga\\n{gold} - ilosc zlota\\n{AR} - Armor Rating / Physical Resistance\\n{tithe} - Tithing points\\n{bandage} - Bandage Timer\\n{statbar}/{mediumstatbar}/{largestatbar} - Pasek statusu\\n{crimtime} - czas bycia przestepca\\n{stealthsteps} - ilosc krokow stealth\\nKolor - kod HTML hex : '~#rrggbb' ('~#~' konczy)\\nlub {Format} z listy liczniko\r\n1109=Wersja Razora: {0}\\nUzyta pamiec: {1}\\nWyslano: {2} ({3}/s)\\nOdebrano: {4} ({5}/s)\\nPolaczony {6}\\n\\nSerial gracza: 0x{7:X8}\\nSerial plecaka: 0x{8:X8}\\n\\nSledzone przedmioty: {9}\\nSledzone Moby: {10}\\n\r\n1110=Blokada: GORA\r\n1111=Blokada: DOL\r\n1112=Blokada: BLOKUJ\r\n1113=Czy chcesz usunac licznik \"{0}\"?\\nTo dotyczy kazdego profilu.\r\n1114=Wczytac profil \"{0}\"?\r\n1115=Blad przy wczytywaniu profilu.\r\n1116=Nie usuniesz domyslnego profilu.\r\n1117=Nazwa nowego profilu: \r\n1118=Blad przy tworzeniu profilu!\\n Powod: profil o tej nazwie istnieje.\\n\\nWczytac ten profil?\r\n1119=Wpisz nazwe listy Ubiorow:\r\n1120=Usunac ta liste?\r\n1121={0:X} (Poza zasiegiem)\r\n1122=Usunac przedmiot z listy?\r\n1123=Gdzie wlozyc rzeczy z listy  '{0}'?\r\n1124=Pojemnik ustawiony.\r\n1125=Obiekt nie znaleziony lub bledny\r\n1126=Te klawisze przypisano juz do '{0}'.\\nZmienic na '{1}'?\r\n1127=Zapisano dane.\r\n1128=Uwaga!\\nLogowanie pakietow moze obnizyc wydajnosc. Log moze bardzo szybko osiagnac duzy rozmiar, a Razor ich nie usuwa.\\n\\nLog Razora moze zawierac poufne dane takie jak haslo,\\n i nie powinien byc pokazywany osobom postronnym.\\n\\nNapewno wlaczyc logowanie?\\n(Tylko dla tego profilu)\r\n1129=Convert Selected to TYPE\r\n1130=Nazwa nowego makra: \r\n1131=Nazwa zawiera niepoprawne znaki.\r\n1132=Makro o tej nazwie juz istnieje.\r\n1133=Makro zostanie wyczyszczone przed nagraniem.\\nCzy napewno usunac zawartosc i nagrac nowa?\r\n1134=Napewno usunac '{0}'?\\n(Nie da sie tego cofnac)\r\n1135=Wstaw 'Pause/Wait...'\r\n1136=Wstaw 'Wybierz LastTarget'\r\n1137=W gore\r\n1138=W dol\r\n1139=Usun akcje\r\n1140=Nagrywaj od tego momentu\r\n1141=Nie znaleziono pliku '{0}'.\r\n1142=Jestes pewien?\r\n1143=Uwaga: Nastepujace {0} plik(i){1} nie moga zostac skasowane:\\n{2}\r\n1144=Zmiana bedzie dzialac po restarcie Razor'a.\r\n1145=Wlaczenie tej opcji sprawi, ze Razor zapisze haslo  w pliku profilu.\\nMimo, ze hasla sa kodowane istnieje niebezpieczenstwo.\\nCzy napewno wlaczyc ta opcje?\r\n1146=Musisz podac poprawny port.\r\n1147=Ignoruje zadanie (juz w kolejce).\r\n1148=Kolejkuje zadanie {0}... pozostalo {1}.\r\n1149=Zakonczono {0} zakolejkowanych zadan w {1:F1} sekund.\r\n1150=Uzyj Once Agent\r\n1151=Dodaj (Wskaz)...\r\n1152=Dodaj pojemnik (Wskaz)...\r\n1153=Skasuj (Wskaz)...\r\n1154=Czysc liste\r\n1155=Wskaz przedmiot do dodania.\r\n1156=Wskaz pojemnik.\r\n1157=Wskaz przedmiot do skasowania.\r\n1158=Przedmiot dodany.\r\n1159=Przedmiot skasowany.\r\n1160={0} item(s) added to the Use Once agent.\r\n1161=The UseOnce queue is empty!\r\n1162=Using '{0}'.  ({1} item(s) left in the UseOnce queue)\r\n1163=There was a problem with one of your UseOnce items, trying the next one.\r\n1164=SellAgent: Automatically selling {0} item(s) for {1}gp.\r\n1165=Remove\r\n1166=Container set successfully.\r\n1167=Clear\r\n1168=(Push to Disable)\r\n1169=(Push to Enable)\r\n1170=Set Hot Bag\r\n1171=Clear Hot Bag\r\n1172=Organizer Agent\r\n1173=Organizer\r\n1174=Organize Now\r\n1175=Container not set.\r\n1176=Razor nie moze odnalezc plecaka.\r\n1177=Organize Agent queued {0} item(s) to be moved. (This may take a few moments)\r\n1178=Organize Agent did not find any items to move.\r\n1179=Przedmiot jest juz na liscie.\r\n1180=AutoSearchExemptions\r\n1181=Agent kupowania zakupil {0} item(ow) za {1}gp.\r\n1182=Agent kupowania nie zadzialal, poniewaz nie posiadasz przy sobie odpowiedniej ilosci zlota.\r\n1183=Wpisz liczbe:\r\n1184=Prioryte klienta ustawiono na {0}\r\n1185=The current time is: {0}\r\n1186=You are at {0} in '{1}'\r\n1187=Undress bag was not found or out of range, using your backpack instead.\r\n1188={0} item(s) queued to be de-equipped.\r\n1189={0} item(s) queued to be equipped.\r\n1190={0} item(s) already equipped.\r\n1191={0} item(s) were not found. (Out of Range)\r\n1192=Warning: Spells.def not found, spell format text will not be shown\r\n1193=Krokow : {0}\r\n1194=Zaczynam liczyc kroki.\r\n1195=Oczysc kolejke celow\r\n1196=Atakuj ostatniego wroga\r\n1197=Kolejka celow ocyzscyona.\r\n1198=Wskay nowy 'Ostatni Cel'\r\n1199=Ostatni Cel ustawiony.\r\n1200=Nowy cel ustawiony.\r\n1201=Brak odpowiadajacych celi na ekranie.\r\n1202=Zakolejkowano TargetSelf.\r\n1203=Zakolejkowano LastTarget.\r\n1204=Server nadeslal nowy cel, anuluje cel Razor'a.\r\n1205=Cel wedlug typu {0}\r\n1206=Scavenger\r\n1207=Jestes pewien, ze chcesz to skasowac?\r\n1208=Wskaz folder do przechowywania obrazow.\r\n1209=Klawiatura\r\n1210=Przedmioty\r\n1211=Cele\r\n1212=Agenci\r\n1213=Ubierz\r\n1214=Makra\r\n1215=Czary\r\n1216=Umiejetnosci\r\n1217=Dodatkowe\r\n1251=Pierwszy\r\n1252=Drugi\r\n1253=Trzeci\r\n1254=Czwarty\r\n1255=Piaty\r\n1256=Szosty\r\n1257=Siodmy\r\n1258=Osmy\r\n1260=Necromancy\r\n1270=Chivalry\r\n1271=Mikstury\r\n1272=Ataki specjalne\r\n1290=Bushido\r\n1300=Ninjitsu\r\n1301=Sprzedaj\r\n1302=Kup\r\n1303=Input Required\r\n1304=Lista komend\r\n1305=Uzyj trzymanego przedmiotu\r\n1306=Musisz cos wyjac z reki aby moc to pozniej wlozyc.\r\n1307=Arm/Disarm - Prawa reka\r\n1308=Arm/Disarm - Lewa reka\r\n1309=Wyrzuc to co aktualnie trzymasz\r\n\r\n1311=> Enable/Disable Razor HotKeys\r\n1312=Hot Keys wlaczone (Wcisnij {0} by anulowac)\r\n1313=Hot Keys wylaczone (Wcisnij {0} by wlaczyc)\r\n1314=Hot Keys Wlaczone\r\n1315=Hot Keys Wylaczone\r\n1316=Walk: {0}\r\n1317=Add Type (Target)...\r\n1318=Wybrany Cel jest po za zasiegiem, anulowano!\r\n1319=Max Sell: {0}\r\n1320=Snooping Messages\r\n1321=Backpack Sounds\r\n1322=Wstaw \"If\" Conditional\r\n1323=Wstaw \"Else\"\r\n1324=Wstaw \"End If\"\r\n1325=Set Amount\r\n1326=Restock\r\n1327=Restock Now\r\n1328=Restock Agent\r\n1329=Target a container to restock from, or target yourself to use your bank box.\r\n1330=Wskazano bledny pojemnik.\r\n1331=Restock done, queued {0} item{1}.\r\n1332=Anuluj wybrany cel\r\n1333=Nowa wersja Razor'a jest dostepna\\n\\nChcesz odwiedzic strone Razor'a i ja pobrac?\r\n1334=Wgraj ponownie\r\n1335=Zapisz\r\n1336=UWAGA: Wybrany cel nie pozwala na wskazanie ziemi.  Ostatni Cel niezakonczony.\r\n1337=Resynchronizuj klienta\r\n1338=Zsiadanie zablokowane.\r\n1339=Rozpocznij nagrywanie \"PacketVideo\"\r\n1340=Zatrzymaj nagrywanie/odtwarzanie \"PacketVideo\"\r\n1341=Blad przy nagrywaniu.\\nZdarzenie zalogowane.\r\n1342=Plik niezgodny z ta wersja Razor'a.  Upewnij sie, ze masz najnowszego Razor'a.\r\n1343=Plik video uszkodzony.\\nMoze byc niekompatybilny.\\nPlik nie zostanie odtworzony.\r\n1344=Wystapil problem przy otwieraniu pliku. Moze byc uszkodzony lub niekompletny.\r\n1345=Nazwa kategorii:\r\n1346=Nie mozna skasowac katalogu.  Upewnij sie, ze jest pusty.\r\n1347=Nie mozna stworzyc katalogu.  Upewnij sie, ze wprowadziles poprawna nazwe.\r\n1348=Nie mozna przeniesc makra.  Upenij sie, ze podales poprawna kategorie.\r\n1349=Przyjaciele\r\n// 1350 to 1359 reserved (max length 15!)\r\n1350=Stopped\r\n1351=The End\r\n1352=Game Over\r\n1353=Spi czy umarl?\r\n1354=Got corp por?\r\n1355=bamboozled\r\n1356=pwned?\r\n1357=Jesus <3s you\r\n1358=Kal Vas Pwned\r\n1359=SMACKDOWN\r\n1360=Kogo dodac do listy przyjaciol.\r\n1361=Kogo usunac z listy przyjaciol.\r\n1362=Przyjaciel dodany.\r\n1363=Przyjaciel usuniety.\r\n1364=Special Constructs\r\n1365=Wstaw \"For Loop\"\r\n1366=Wstawt \"End For\"\r\n1367=Podaj liczbe powtorzen:\r\n1368=Oczysc Cache\r\n1369=Ostatni Czar\r\n1370=Ostatnia umiejetnosc\r\n1371=Ostatni przedmiot\r\n1372=Pokaz imiona\r\n1373=UzyjRaz\r\n1374=Wskaz dowolny cel\r\n1375=Wskaz dowolnego crima\r\n1376=Wskaz dowolnego niewinnego\r\n1377=Wskaz dowlonego crima\r\n1378=Wskaz dowolnego crima\r\n1379=UWAGA: Drag/Drop timeout! Odkladanie przedmiotu z reki do plecaka.\r\n1380=Musisz zrestartowac Razora i klienta aby zmiany odniosly efekt.\r\n1381=Musisz sie przelogowac aby to dzialalo poprawnie.\r\n1382=Queuing dragdrop request {0}... {1} left.\r\n1383=Polecenie restock w kolejce....\r\n1384=Twoja sila wzrosla o {0}{1}, i wynosi {2}.\r\n1385=Twoja zrecznosc wzrosla o {0}{1}, i wynosi {2}.\r\n1386=Twoja inteligencja wzrosla o {0}{1}, i wynosi {2}.\r\n1387=Jednolite oswietlenie\r\n1388=Leczenie wstrzymane (cel jest zatruty)!\r\n1389=Czyszczenie kolejki drag/drop\r\n1390=Przerwij\r\n1391=>Ulecz sie\r\n1392=Nastepny Cel\r\n1393=Set Restock HotBag\r\n1394=Dodaj do UzyjRaz\r\n1395=Atakuj ostatni cel\r\n1396=Edit Timeout...\r\n1397=Nie masz nic w rekach.\r\n1398=Niedozwolone\r\n1399=Dozwolone\r\n1400=Opcje uzgadniane z serwerem:\r\n1401=Wszystkie opcje dozwolone.\r\n1402=Filtr Pogody\r\n1403=Filtr oswietlenia\r\n1404=Inteligentny OstatniCel\r\n1405=Spr. odleglosci OstatniegoCelu\r\n1406=Auto-Otwieranie Drzwi\r\n1407=Rozbroj przed uzyciem czaru\r\n1408=Auto-Uzbrajanie po wypiciu mikstury\r\n1409=Blokuj Leczenie gdy zatruty\r\n1410=Zapetl Makro\r\n1411=UzyjRaz Agent\r\n1412=Restock Agent\r\n1413=Sell Agent\r\n1414=Buy Agent\r\n1415=Klawisze Mikstur\r\n1416=Rozne Cele\r\n1417=Liczba HP nad glowa/Wyswietl Statystyki\r\n// up to 1465: reserved\r\n1466=Funkcja niedozwolona przez serwer.\r\n1467=Funkcja ta jest niedozwolona przez aktualny serwer..\\nMozesz wybrac opcje ignorowania wiadomosci Serwera w zakladce \"Opcje\".\\n\\nBy sprawdzic liste niedozwolonych funkcji przejdz do zakladki \"Help & Status\".\r\n1468=Wstaw komentarz\r\n1469=Dodaj przyjaciela\r\n1470=Skasuja przyjaciela\r\n1471=> Mini-Leczenie/Odtruwanie siebie\r\n1472=Wylacz opcje \"Patch Encryption\" jesli uzywasz klienta ktory ma juz wylaczona enkrypcje.  Opcja ta powinna byc wlaczona jesli grasz na serwerach uzywajacych enkrypcji klienta (np. oficjalne serwery OSI/EA).\\nJesli nie jestes pewny wyboru, NIEODZNACZAJ tej opcji.\\n\\nNa pewno chcesz wylaczyc enkrypcje klienta?\r\n1473=Zsiadanie z konia\r\n1474=Pokaz/Schowaj okno Mapy\r\n1475=Cel jest zbyt daleko.\r\n1476=Kolejka drag/drop jest PELNA! Prosze zaczekac.\r\n1477=Tryb walki\r\n1478=Gumpy nagrod\r\n1479=Rozmiar okna gry jest bledny. Sprobuj ponownie.\r\n1480=(Scavenger HotBag)\r\n1481=(Restock HotBag {0})\r\n1482=(UzyjRaz #{0})\r\n1483=(Sell Agent HotBag)\r\n1484=(Organizer {0} HotBag)\r\n1485=Adres serwera ktory wpisales jest nieosiagalny.\r\n1486=Druzyna: Akceptuj zaproszenie\r\n1487=Druzyna: Odrzuc zaproszenie\r\n1488=Szkodliwy Cel\r\n1489=Przyjazny Cel\r\n1490=(Przyjaciel)\r\n1491=Rozpocznij odtad\r\n1492=Wczytywanie...\r\n1493=Wczytywanie standardowego profilu...\r\n1494=Wczytywanie Klienta...\r\n1495=Oczekiwanie na start Klienta...\r\n1496=Nie zapomnij o donate!\r\n1497=Razor wita!\r\n1498=Klient 2D (Auto wykrywanie)\r\n1499=Klient 3D (Auto wykrywanie)\r\n1500=(Auto wykrywanie)\r\n1501=Nieprzezroczystosc: {0}%\r\n1502=Wskaz nowa wartosc oczekiwania dla tej czynnosci (w sekundach):\r\n1503=nieprzypisane\r\n1504=Zmien wartosc oczekiwania\r\n1505=Wpisz nazwe\r\n1506=Niepoprawnie.\r\n1507=Staff only items\r\n1508={0}'s Statystyki\r\n1509=Zjedz wyczarowane jablko\r\n1510=Wskaz najblizszego Morderce\r\n1511=Wskaz najblizszego Crima\r\n1512=Wskaz najblizszego niewinnego\r\n1513=Wskaz najblizszego wroga\r\n1514=Wskaz najblizszego przyjaciela\r\n1515=Wskaz najblizszego nieprzyjaciela\r\n1516=Wskaz najblizszego humanoidalnego wroga\r\n1517=Wskaz najblizszego humanoidalnego Crima\r\n1518=Wskaz najblizszego humanoidalnego niewinnego\r\n1519=Wskaz najblizszego humanoidalnego Crima\r\n1520=Wskaz najblizszego Crima\r\n1521=UWAGA: Profil '{0}' jest uzywany przez drugiego Razora!\\nJesli wprowadzisz zmiany w tym profilu, dane moga zostac utracone. Zalecane jest uzywanie innych profili do kazdego wlaczonego Razora.\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.rus",
    "content": "﻿// Razor Russian/RUS Language Pack\r\n// Last Modified August 13, 2005\r\n// Author : Pavel Tsalkin [Prohor Meletevich] <pinkefir@mail.com>\r\n\r\n::Encoding=UTF-8\r\n::CliLoc=RUS\r\n\r\n[controls]\r\nWelcomeForm::Text=Добро пожаловать в Razor!\r\nWelcomeForm::groupBox3=Директория UO\r\nWelcomeForm::dataBrowse=Выбрать\r\nWelcomeForm::label5=Язык:\r\nWelcomeForm::groupBox2=Сервер\r\nWelcomeForm::label3=Сервер:\r\nWelcomeForm::label4=Порт:\r\nWelcomeForm::groupBox1=Параметры клиента\r\nWelcomeForm::useEnc=OSI шифрование\r\nWelcomeForm::makeDef=Запомнить эти параметры\r\nWelcomeForm::browse=Выбрать\r\nWelcomeForm::label1=Клиент:\r\nWelcomeForm::patchEncy=Убрать шифрование\r\nWelcomeForm::showAtStart=Показывать при старте\r\nWelcomeForm::quit=&Выход\r\nWelcomeForm::okay=&Okay\r\n\r\nMainForm::Text=Razor v{0}\r\nMainForm::generalTab=Основные\r\nMainForm::label10=Пров. обновления:\r\nMainForm::systray=Трей\r\nMainForm::taskbar=Панель задач\r\nMainForm::smartCPU=Понижать скорость для быстрых CPU\r\nMainForm::label7=Язык:\r\nMainForm::label11=Вид:\r\nMainForm::groupBox4=Профили\r\nMainForm::delProfile=Удал.\r\nMainForm::newProfile=&Новый...\r\nMainForm::showWelcome=Начальный диалог (для всех профилей)\r\nMainForm::alwaysTop=Razor всегда поверх окона UO\r\nMainForm::groupBox1=Фильтр\r\nMainForm::opacityLabel= Opacity: 100%\r\nMainForm::moreOptTab=Опции\r\nMainForm::setLTHilight=Установить\r\nMainForm::lthilight=Последняя цель\r\nMainForm::filterSnoop=Фильтр повторных сообщений\r\nMainForm::incomingCorpse=Показывать имена трупов\r\nMainForm::incomingMob=Показывать имена людей/существ\r\nMainForm::smoothWalk=Сглаживать перемещение чара\r\nMainForm::setHarmHue=Уст.\r\nMainForm::setNeuHue=Уст.\r\nMainForm::lblHarmHue=Вредн.\r\nMainForm::lblNeuHue=Нейтр.\r\nMainForm::lblBeneHue=Благотв.\r\nMainForm::setBeneHue=Уст.\r\nMainForm::setSpeechHue=Уст.\r\nMainForm::setWarnHue=Уст.\r\nMainForm::setMsgHue=Уст.\r\nMainForm::setExHue=Уст.\r\nMainForm::autoStackRes=Упорядочивать руду/рыбу/дерево\r\nMainForm::queueTargets=Послед. Цель и Выбр. Себя в очередь\r\nMainForm::spamFilter=Антифлуд системных сообщений\r\nMainForm::label4=тайла\r\nMainForm::openCorpses=Открыв. трупы с расст.\r\nMainForm::showNotoHue=Цвет персонажа в заголовке клиента\r\nMainForm::lblWarnHue=Предупреждения\r\nMainForm::lblMsgHue=Сообщения от Razor\r\nMainForm::lblExHue=Исключ. авто-поиска\r\nMainForm::blockDis=Запретить спешиваться в бою\r\nMainForm::chkForceSpellHue=Цвет заклинания:\r\nMainForm::chkForceSpeechHue=Речь персонажа\r\nMainForm::label3=Формат:\r\nMainForm::moreMoreOptTab=Расширенные\r\nMainForm::blockHealPoison=Не лечить если цель отравленна\r\nMainForm::potionEquip=Раз/во-оружать пред употр. зелья\r\nMainForm::label18=x:\r\nMainForm::gameSize=Размер окна UO:\r\nMainForm::label17=Сообщения Razor:\r\nMainForm::QueueActions=Действия над объектом в очередь\r\nMainForm::spellUnequip=Разоружить перед заклинанием\r\nMainForm::autoOpenDoors=Открывать двери\r\nMainForm::alwaysStealth=Показывать скрытные шаги\r\nMainForm::autoFriend=Члены группы - друзья\r\nMainForm::chkStealth=Подсчет скрытных шагов\r\nMainForm::rememberPwds=Запоминать пароли\r\nMainForm::showtargtext=Флаги цели левым щелчком\r\nMainForm::smartLT=Быстрая последняя цель\r\nMainForm::preAOSstatbar=Окно статуса в старом стиле\r\nMainForm::logPackets=Статистика пакетов\r\nMainForm::warnCount=Извещать если счетчик    <\r\nMainForm::rangeCheckLT=Выбор целей в радиусе:\r\nMainForm::actionStatusMsg=Сообщения об изменен. в очереди\r\nMainForm::label5=в интервале\r\nMainForm::label9=Приоритет клиента:\r\nMainForm::label8=тайл.\r\nMainForm::label6=мс\r\nMainForm::displayTab=Заголовок UO\r\nMainForm::excludePouches=Исключить сумки из поиска\r\nMainForm::highlightSpellReags=Показ. реагенты при заклинании\r\nMainForm::titlebarImages=Иконки на счетчиках в заголовке\r\nMainForm::sortCounters=Сортировать выбранн. счетчики\r\nMainForm::checkNewConts=Авто-поиск новых предметов\r\nMainForm::groupBox3=Заголовок окна клиента UO\r\nMainForm::showInBar=Показывать в заголовке UO:\r\nMainForm::groupBox2=Счетчики\r\nMainForm::delCounter=Измен.\r\nMainForm::addCounter=Новый\r\nMainForm::recount=Считать\r\nMainForm::dressTab=Снаряжение\r\nMainForm::groupBox6=Предметы снаряжения\r\nMainForm::clearDress=Очистить\r\nMainForm::dressDelSel=Убрать\r\nMainForm::undressBag=Сумка для вещей\r\nMainForm::undressList=Снять\r\nMainForm::dressUseCur=Добав. одетое\r\nMainForm::targItem=Добавить цель\r\nMainForm::dressNow=Одет.\r\nMainForm::groupBox5=Списки снаряжения\r\nMainForm::removeDress=Убрать\r\nMainForm::addDress=Добав.\r\nMainForm::undressConflicts=Перемещать кон- фликтующие вещи\r\nMainForm::skillsTab=Умения\r\nMainForm::dispDelta=Показ. разницу\r\nMainForm::skillCopyAll=Копировать все\r\nMainForm::skillCopySel=Копир. выбранное\r\nMainForm::label1=В сумме:\r\nMainForm::setlocks=Уст. на все:\r\nMainForm::resetDelta=Переключить +/-\r\nMainForm::agentsTab=Агенты\r\nMainForm::hotkeysTab=Горячие клавиши\r\nMainForm::dohotkey=Запуск выбранного\r\nMainForm::groupBox8=Горячая клавиша\r\nMainForm::chkPass=Запуск также и в UO \r\nMainForm::label2=Клв.\r\nMainForm::unsetHK=Убрать\r\nMainForm::setHK=Уст.\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Макрос\r\nMainForm::macroActGroup=Действия\r\nMainForm::loopMacro=Loop\r\nMainForm::recMacro=Запись\r\nMainForm::playMacro=Старт\r\nMainForm::delMacro=Убрать\r\nMainForm::newMacro=Новый\r\nMainForm::screenshotTab=Снимок\r\nMainForm::label12=Формат:\r\nMainForm::capNow=Сделать снимок экрана\r\nMainForm::radioUO=Только UO\r\nMainForm::radioFull=Полн. экран\r\nMainForm::screenAutoCap=Авто-подбор цветности\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Добавлять дату и время\r\nMainForm::videoTab=Видео\r\nMainForm::recFolder=...\r\nMainForm::label13=Директория записи:\r\nMainForm::groupBox7=Запись PacketVideo\r\nMainForm::vidRec=Записать PacketVideo\r\nMainForm::flipVidVert=Вертик.\r\nMainForm::flipVidHoriz=Горизнт.\r\nMainForm::groupBox10=Запись в AVI файл \r\nMainForm::recAVI=Записать видео в AVI файл ...\r\nMainForm::label16=Размеры:\r\nMainForm::label15=FPS:\r\nMainForm::label19=Поврт.:\r\nMainForm::groupBox9=Просмотр PacketVideo\r\nMainForm::label14=Скор.\r\nMainForm::vidClose=Закрыть\r\nMainForm::vidPlayStop=Стоп\r\nMainForm::vidPlay=Старт\r\nMainForm::vidOpen=Открыть\r\nMainForm::statusTab=Помощь\r\nMainForm::rebirth=Только PreT2A шард\r\nMainForm::visitForums=Форум Razor\r\nMainForm::visitHome=Домашняя страница Razor\r\nMainForm::visitGuide=Руководство пользователя\r\n\r\nHueEntry::Text=Выбрать цвет\r\nHueEntry::cancel=Отмена\r\nHueEntry::okay=&Okay\r\nHueEntry::preview=Просмотр\r\nHueEntry::inGame=Выбрать в игре\r\nHueEntry::label1=Номер цвета\r\n\r\n\r\nAddCounter::Text=Доб. счетчик\r\nAddCounter::delete=Удалить\r\nAddCounter::target=Цель\r\nAddCounter::cancel=Отмена\r\nAddCounter::Add=&Okay\r\nAddCounter::label4=Цвет (люб. -1):\r\nAddCounter::label3=ID вещи:\r\nAddCounter::label2=Формат:\r\nAddCounter::label1=Имя:\r\n\r\nMacroInsertWait::Text=Вставить Ожидание/Пауза...\r\nMacroInsertWait::radioMenu=Ждать меню в старом стиле\r\nMacroInsertWait::cancel=&Отмена\r\nMacroInsertWait::radioStat=Ждать\r\nMacroInsertWait::radioTarg=Ждать цель\r\nMacroInsertWait::radioGump=Ждать меню\r\nMacroInsertWait::label1=мсек.\r\nMacroInsertWait::radioPause=Ожидать\r\nMacroInsertWait::insert=&Вставить\r\n\r\nMacroInsertIf::Text=Вставить \"If\" (Если)...\r\nMacroInsertIf::label1=If:\r\nMacroInsertIf::cancel=&Отмена\r\nMacroInsertIf::insert=&Вставить\r\n\r\n[strings]\r\n1001=Статус смерти\r\n1002=Музыка барда\r\n1003=Лай собак\r\n1004=Мяуканье кошек\r\n1005=Ржание лошадей\r\n1006=Блеяние овец\r\n1007=Разговор с духами\r\n1008=Неудачные заклинания\r\n1009=Погода\r\n1010=Показать счетчики\r\n1011=Обновить счетчики\r\n1012=Очистка спец. ударов AOS\r\n1013=Установить основной спец. удар (AOS)\r\n1014=Установить вторичный спец. удар (AOS)\r\n1015=Переключить оглушение (пред-AOS)\r\n1016=Разоружить/Вооружить (пред-AOS)\r\n1017=Устанвливаю спец. удар {0}\r\n1018=Спец. удары AOS очищены.\r\n1019=Снять всё снаряжение\r\n1020=Снять снаряжение с обоих рук\r\n1021=Снять снаряжение с левой руки\r\n1022=Снять снаряжение с правой руки\r\n1023=Снять снаряжение с головы\r\n1024=Снять ювелные изделия\r\n1025=Перевязать себя\r\n1026=Перевязать последнюю цель\r\n1027=Использовать бинты (без подсчета времени)\r\n1028=Выпить зелье Лечения\r\n1029=Выпить зелье Противоядия\r\n1030=Выпить зелье Восстановления\r\n1031=Выпить зелье Ночного Зрения\r\n1032=Бросить зелье Взрыва\r\n1033=Выпить зелье Силы\r\n1034=Выпить зелье Ловкости\r\n1035=У вас нет бинтов\r\n1036=Не найдено ни одного предмета с типом '{0}'!\r\n1037=Двойной Щелчок ({0})\r\n1038=Выбрать цель заново\r\n1039=Преобразовать в \"Двойной Щелчок\" по типу\r\n1040=Выбор новой цели для этого действия.\r\n1041=ПРЕДУПРЕЖДЕНИЕ: Ошибка при загрузке значения из профиля:\\n{0}\r\n1042=ПРЕДУПРЕЖДЕНИЕ Макроса: Не могу найти объект (вне зоны досягаемости).\r\n1043=Перемещение {1} - {0}\r\n1044=Преобразовать в \"Переместить\" по типу\r\n1045=ПРЕДУПРЕЖДЕНИЕ Макроса: В руках ни чего нет.\r\n1046=Снарядить {0} (L:{1})\r\n1047=Бросить в {0} (@{1})\r\n1048=Преобразовать в \"Относительное Расположение\"\r\n1049=Бросить (относительно) @({0},{1},{2})\r\n1050=Реакция от меню (Кнопка {0})\r\n1051=Закрыть меню\r\n1052=Реакция от меню: {0}\r\n1053=ПРЕДУПРЕЖДЕНИЕ: Макрос запросил цель, но она не была получена с сервера! (может вам следует использовать \"Ждать Цель\"?)\r\n1054=Абсолютная цель\r\n1055=Преобразовать в \"Последнюю Цель\"\r\n1056=Преобразовать в \"Цель\" по типу\r\n1057=Релокация целей ({0},{1})\r\n1058=Последняя цель\r\n1059=Выбрать себя\r\n1060=Выбрать \"Последнюю Цель\"\r\n1061=Выбрать случайного Красного\r\n1062=Выбрать случайного Серого\r\n1063=Выбрать случайного Синего\r\n1064=Выбрать случайного Врага\r\n1065=Выбрать случайного Дружественного\r\n1066=Выбрать случайного Недружественного\r\n1067=Сказать '{0}'\r\n1068=Использовать умение {0}\r\n1069=Вызвать заклинание {0}\r\n1070=Установить спец. удар {0}\r\n1071=Одеть: {0}\r\n1072=Снять: {0}\r\n1073=Убрать Layer {0}\r\n1074=Ждать меню (любое)\r\n1075=Ждать меню (#{0})\r\n1076=Изменить\r\n1077=Ждать диалог (любой)\r\n1078=Ждать диалог (#{0})\r\n1079=Ждать цель\r\n1080=Пауза {0:#.00} сек\r\n1081=Ждать: {0} {1} {2}\r\n1082=Загрузка '{0}'...\r\n1083=> Остановить текущий макрос\r\n1084=Выполнить: {0}\r\n1085=Запуск макроса '{0}'...\r\n1086=Макрос '{0}' завершен.\r\n1087=Невозможно запустить Razor. Код ошибки:\\n\r\n1088=ОПИСАНИЕ: Невозможно найти окно клиента UO.\\nВозможная причина: Произошла ошибка при загрузке клиента.\r\n1089=ОПИСАНИЕ: Невозможно найти клиент UO.\\nВозможная причина: Произошла ошибка при загрузке клиента.\r\n1090=ОПИСАНИЕ: Невозможно создать окна.\\nВозможная причина: Внутренняя ошибка.\r\n1091=ОПИСАНИЕ: Невозможно получить доступ к совместной памяти Razor.\\nВозможная причина: Ошибка Windows или неправилные разрешения.\r\n1092=ОПИСАНИЕ: Crypt.dll не загружен.\\nВозможная причина: Несовпадение версий.\r\n1093=ОПИСАНИЕ: Невозможно изменить функции Winsock Клиента UO.\\nВозможная причина: Внутренняя ошибка, ошибка Windows, или несовместимая версия.\r\n1094=\r\n1095=ПРЕДУПРЕЖДЕНИЕ: Не могу получить длину пакета и/или информацию о шифровании клиента UO.\\nRazor может запустится без этой информации, но некоторые действия будут выполняться неправильно. Хотите ли вы продолжить запуск Razor?\\nВозможная причина: Версия вашего клиента несовместима с этой версией Razor.\r\n1096=Ваше умение '{0}' изменилось на {4}{5:F1}, теперь его значение {3:F1} ({1}{2:F1}).\r\n1097=Неверное сокращение.\r\n1098=Неверный ID объекта.\r\n1099=Неверный цвет.\r\n1100=Выберите объект обсчета.\r\n1101=Ошибка загрузки '{0}'!\\nЭтот профиль испорчен и не может быть использован.\r\n1102=Свойство {0} не найдено в текущем профиле.\r\n1103=Ваш файл counters.xml испорчен и не может быть использован.\r\n1104=Т.к. вы не выбрали опцию \"Искать предметы в сумках\", то вы должны открыть все ваши сумки, чтобы счетчики обновились.\r\n1105=ПРЕДУПРЕЖДЕНИЕ: Величина '{0}' теперь {1}!\r\n1106=Выберите цвет, который вы хотите использовать.\r\n1107=Сделать снимок экрана\r\n//1108=Возможные значения:\\n{char} - Имя персонажа\\n{shard} - Имя шарда\\n{str}/{hp}/{hpmax} - Информация о здоровье\\n{dex}/{stam}/{stammax} - Информация о ловкости\\n{int}/{mana}/{manamax} - Информация об интеллекте\\n{weight}/{maxweight} - Информация о весе\\n{gold} - Общее кол-во золота у персонажа\\n{AR} - Рейтинг брони / Физическое сопротивление\\n{tithe} - Очки заклинаний палладина (tithe points)\\n{bandage} - Время перевязки\\n{statbar}/{mediumstatbar}/{largestatbar} - Полоски здоровья, маны и выносливости\\n{crimtime} - Как долго вы будете вне закона\\n{stealthsteps} - Счетчик скрытых шагов\\nColor - HTML шестнадцатеричный код цвета: '~#rrggbb' ('~#~' чтобы убрать)\\nИли {Format} Из списка счетчиков\r\n1109=Версия Razor: {0}\\nИспользовано памяти: {1}\\nОтправлено: {2} ({3}/s)\\nПолучено: {4} ({5}/s)\\nВремя в игре: {6}\\n\\nСерийный номер игрока: 0x{7:X8}\\nСерийный номер рюкзака: 0x{8:X8}\\n\\nСлежение за предметами (кол-во): {9}\\nСлежение за существами (кол-во): {10}\\n\r\n1110=Установить на: + УВЕЛИЧЕНИЕ\r\n1111=Установить на: - УМЕНШЕНИЕ\r\n1112=Установить на: / ФИКСАЦИЯ\r\n1113=Вы уверены, что хотите удалить счетчик '{0}'?\\nЭто затронет все профили.\r\n1114=Загрузить профиль '{0}'?\r\n1115=Произошла ошибка при загрузке профиля.\r\n1116=Профиль 'default' является профилем по умолчанию и не может быть удален!\r\n1117=Введите имя нового профиля:\r\n1118=Невозможно создать новый профиль!\\n Причина: Профиль с таким именем уже существует.\\n\\nХотите ли вы загрузить существующий  профиль?\r\n1119=Введите имя нового списка:\r\n1120=Удалить этот список снаряжения?\r\n1121={0:X} (Объект вне зоны досягаемости)\r\n1122=Удалить этот объект из списка Снаряжения?\r\n1123=Выберите сумку, в которую будут сложены снятые вещи, указанные в списке '{0}'.\r\n1124=Сумка для снятых вещей выбрана.\r\n1125=Объект не найден или выбран неправильный объект.\r\n1126=Эта комбинация клавиш уже принадлежит '{0}'.\\nИзменить на '{1}'?\r\n1127=Данные успешно сохранены.\r\n1128=Предупреждение!\\nСтатистика пакетов может привести к существенному замедлению работы Razor. Размер файлов статистики также может резко возрасти.\\n\\nФайл статистики Razor может содержать персональную информацию, в том числе и пaроли. Вы не должны передавать этот файл людям, которым вы не доверяете.\\n\\nВы уверены, что хотите включить статистику пакетов?\\n(Это не будет сохранено в ваш профиль)\r\n1129=Преобразовать выбранные в Тип\r\n1130=Введите имя нового макроса: \r\n1131=Это имя содержит недопустимые символы.\r\n1132=Макрос с таким именем уже существует.\r\n1133=Этот макрос будет очищен перед записью.\\nВы уверены, что хотите перезаписать этот макрос?\r\n1134=Вы уверены, что хотите полностью удалить '{0}'?\\n(Это действие не может быть отменено)\r\n1135=Вставить: Пауза/Ожидание...\r\n1136=Вставить: Выбрать \"Последнюю Цель\"\r\n1137=Вверх\r\n1138=Вниз\r\n1139=Удалить действие\r\n1140=Начать запись с этого места\r\n1141=Файл '{0}' не найден.\r\n1142=Вы уверены?\r\n1143=ПРЕДУПРЕЖДЕНИЕ: Следующее количество фала(ов) {0} не было удалено:\\n{2}\r\n1144=Эти изменения вступят в силу при следующем запуске Razor.\r\n1145=Разрешение этой опции приведет к тому, что Razor сохранит ваши пароли как часть вашего профиля. Пароли будут зашифрованы, но злоумышленник, получивший доступ к .xml файлу профиля, сможет его использовать.\\nВы уверены, что хотите сохранять пароли в профиле?\r\n1146=Вы должны указать верный порт.\r\n1147=Игнорирую действие (уже в очереди).\r\n1148=Добавление действий в очередь {0}... {1} готово.\r\n1149=Добавлено действий в очередь: {0}, время выполнения {1:F1} сек.\r\n1150=Агент \"Использовать_Один_Раз\"\r\n1151=Добавить цель...\r\n1152=Добавить сумку...\r\n1153=Убрать цель...\r\n1154=Очистить список\r\n1155=Укажите объект для добавления.\r\n1156=Укажите сумку.\r\n1157=Укажите объект, чтобы убрать.\r\n1158=Объект добавлен.\r\n1159=Объект удален.\r\n1160=В агент \"Использовать_Один_Раз\" добавлено объектов: {0} \r\n1161=Очередь агента \"Использовать_Один_Раз\" пуста!\r\n1162=Использую '{0}'.  (Исключено объектов из очереди \"Использовать_Один_Раз\": {1})\r\n1163=Проблема с одним из объектов агента \"Использовать_Один_Раз\", попытка использовать следующий объект.\r\n1164=Агент \"Продавец\": Автоматически продано объектов {0}, получено {1}gp.\r\n1165=Убрать\r\n1166=Сумка выбрана.\r\n1167=Очистить\r\n1168=(Выключить)\r\n1169=(Включить)\r\n1170=Выбрать сумку...\r\n1171=Поменять сумку...\r\n1172=Агент \"Организатор\"\r\n1173=Организатор\r\n1174=Переместить сейчас\r\n1175=Сумка не выбрана.\r\n1176=Razor не может найти ваш рюкзак.\r\n1177=Агент \"Организатор\": добавлено объектов для упорядочивания: {0} (Это может занять некоторое время).\r\n1178=Агент \"Организатор\": не найдено ни одного объекта, подходящего для упорядочивания.\r\n1179=Этот объект уже в списке.\r\n1180=Исключить_Из_Авто_Поиска\r\n1181=Агент \"Покупатель\": автоматически куплено предметов {0}, истрачено {1}gp.\r\n1182=Агент \"Покупатель\" не может произвести необходимые действия, т.к. у вас не хватает золота.\r\n1183=Введите количество:\r\n1184=Установлен приоритет клиента: {0}\r\n1185=Текущее время: {0}\r\n1186=Вы находитесь {0} в '{1}'\r\n1187=Сумка для снятых вещей не найдена или находится слишком далеко, будет использован рюкзак.\r\n1188=Снять снаряжение, добавлено объектов в очередь: {0}.\r\n1189=Одеть снаряжение, добавлено объектов в очередь: {0}.\r\n1190=Снаряжение уже одето, объектов: {0}.\r\n1191=Не найдено объектов: {0}. (Вне зоны досягаемости)\r\n1192=ПРЕДУПРЕЖДЕНИЕ: Файл Spells.def не найден, формат заклинаний будет недоступен\r\n1193=Скрытых шагов: {0}\r\n1194=Начат подсчет скрытых шагов.\r\n1195=Очистить очередь целей\r\n1196=Атаковать последнего нападавшего\r\n1197=Очередь целей очищена.\r\n1198=Указать новую \"Последнюю Цель\"\r\n1199=\"Последняя Цель\" установлена.\r\n1200=Новая цель выбрана.\r\n1201=На экране не найдено ни одной цели, соответствующей вашему запросу.\r\n1202=Добавлено в очередь: \"Выбрать себя\".\r\n1203=Добавлено в очередь: \"Последняя Цель\".\r\n1204=Сервер получил новую цель.\r\n1205=Выбрать по типу '{0}'\r\n1206=Пылесос\r\n1207=Вы уверены, что хотите удалить это?\r\n1208=Выберете папку для сохранения снимков экрана.\r\n1209=Горячие клавиши\r\n\r\n1210=Предметы\r\n1211=Цели\r\n1212=Агенты\r\n1213=Одежда\r\n1214=Макросы\r\n1215=Заклинания\r\n1216=Умения\r\n1217=Другое\r\n1251=1й круг\r\n1252=2й круг\r\n1253=3й круг\r\n1254=4й круг\r\n1255=5й круг\r\n1256=6й круг\r\n1257=7й круг\r\n1258=8й круг\r\n1260=Necromancy\r\n1270=Chivalry\r\n1271=Зелья\r\n1272=Специальные действия\r\n1290=Bushido\r\n1300=Ninjitsu\r\n1301=Продавец\r\n1302=Покупатель\r\n1303=Необходим ввод значения\r\n1304=Список команд Razor\r\n1305=Использовать объект в руке\r\n1306=Прежде чем вооружиться, вы должны снять оружие.\r\n1307=Вооружить/разоружить правую руку\r\n1308=Вооружить/разоружить левую руку\r\n1309=Бросить объект в руках\r\n\r\n1311=> Включить/Выключить горячие клавиши Razor\r\n1312=Горячие клавиши обрабатываются (Нажмите {0} чтобы выключить)\r\n1313=Горячие клавиши не используются (Нажмите {0} чтобы включить)\r\n1314=Горячие клавиши обрабатываются\r\n1315=Горячие клавиши не используются\r\n1316=Шаги: {0}\r\n1317=Добавить тип...\r\n1318=Запрашиваемая цель вне зоны досягаемости.\r\n1319=Продажа, max: {0}\r\n1320=Повторяющиеся сообщения\r\n1321=Звуки рюкзака\r\n1322=Вставить условие \"If\" (условие)\r\n1323=Вставить \"Else\" (иначе)\r\n1324=Вставить \"End If\" (конец условия)\r\n1325=Установить кол-во\r\n1326=Автонаполнитель\r\n1327=Наполнить сейчас\r\n1328=Агент \"Автонаполнитель\"\r\n1329=Выберите сумку, окуда будет производится наполнение, или выберите себя, чтобы использовать ваш банковский ящик.\r\n1330=Эта сумка не подходит\r\n1331=Наполнение завершено, объектов в очереди: {0}.\r\n1332=\"Прекратить\" текущую цель\r\n1333=Более новая версия Razor доступна для скачивания с сайта.\\n\\nХотите посетить сайт Razor, чтобы скачать новую версию?\r\n1334=Загрузить снова\r\n1335=Сохранить\r\n1336=ПРЕДУПРЕЖДЕНИЕ: Текущая цель не позволяет вам указывать землю. \"Последняя Цель\" не выполнена.\r\n1337=Синхронизировать клиент\r\n1338=Спешивание во время боя заблокировано.\r\n1339=Начать запись \"PacketVideo\"\r\n1340=Остановить запись/воспроизведение \"PacketVideo\"\r\n1341=Произошла ошибка при попытке записи.\\nОшибка было добавлена в статистику.\r\n1342=Этот файл не совместим с этой версией Razor. Убедитесь, что у вас самая новая версия Rzor.\r\n1343=Файл видео поврежден и не может быть воспроизведен.\r\n1344=Невозможно прочитать файл. Он может быть поврежден.\r\n1345=Введите имя категории:\r\n1346=Директория не может быть удалена. Убедитесь, что она пуста.\r\n1347=Невозможно создать директорию. Убедитесь, что вы ввели правильное имя и попробуйте снова.\r\n1348=Невозможно переместить файл макроса. Убедитесь, что выбранная категория существует.\r\n1349=Друзья\r\n// 1350 to 1359 reserved (max length 15!)\r\n1350=Остановлен\r\n1351=Конец\r\n1352=Игра закончена?\r\n1353=ker-pwned\r\n1354=Got corp por?\r\n1355=bamboozled\r\n1356=pwned?\r\n1357=Jesus <3s you\r\n1358=Kal Vas Pwned\r\n1359=SMACKDOWN\r\n1360=Укажите игрока, который будет добавлен в список друзей\r\n1361=Укажите игрока, который будет удален из списка друзей\r\n1362=Друг добавлен.\r\n1363=Друг удален.\r\n1364=Специальные конструкторы\r\n1365=Вставить \"For Loop\" (цикл повторений)\r\n1366=Вставить \"End Loop\" (конец цикла)\r\n1367=Введите кол-во повторений:\r\n1368=Очистить очередь\r\n1369=Последнее заклинание\r\n1370=Последнее умение\r\n1371=Последний объект\r\n1372=Показать имена всех существ\r\n1373=Использовать_Один_Раз\r\n1374=Выбрать случайного Врага Человека\r\n1375=Выбрать случайного Серого Человека\r\n1376=Выбрать случайного Невинного Человека\r\n1377=Выбрать случайного Преступника Человека\r\n1378=Выбрать случайного Преступника\r\n1379=ПРЕДУПРЕЖДЕНИЕ: Закончилось время ожидания! Объект из рук перенесен в рюкзак.\r\n1380=Вы должны перезапустить Razor и клиент, чтобы изменения вступили в силу.\r\n1381=Вы должны выйти и зайти заново вашим персонажем, чтобы изменения вступили в силу.\r\n1382=Добавлено запросов на \"Перемещение\": {0}... {1} готово.\r\n1383=Запрос агента \"Автонаполнитель\" в процессе....\r\n1384=Ваша сила изменилась на {0}{1} и стала равной {2}.\r\n1385=Ваша ловкость изменилась на {0}{1} и стала равной {2}.\r\n1386=Ваш интеллект изменился на {0}{1} и стал равный {2}.\r\n1387=Уровни освещенности\r\n1388=Невозможно вылечить цель т.к. она отравлена!\r\n1389=Очистка очереди на \"Перемещение\"\r\n1390=Остановить сейчас\r\n1391=>Вылечить/Исцелить (от отравления) себя\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.swe",
    "content": "// Razor Swedish/swe Language Pack\r\n// Last Modified on Jan 15, 2007.\r\n// Author: Ilutzio (swordsmith100(at)hotmail.com)\r\n\r\n::Encoding=ISO-8859-1\r\n::CliLoc=SWE\r\n\r\n[controls]\r\nWelcomeForm::Text=Vlkommen till Razor!\r\nWelcomeForm::groupBox3=UO Mappen\r\nWelcomeForm::dataBrowse=Leta...\r\nWelcomeForm::label5=Sprk:\r\nWelcomeForm::groupBox2=Server\r\nWelcomeForm::label3=Server:\r\nWelcomeForm::label4=Port:\r\nWelcomeForm::groupBox1=Klient Alternativ\r\nWelcomeForm::useEnc=Anvnd OSI Kryptering\r\nWelcomeForm::makeDef=Gr Dessa Instllningar Till Standard\r\nWelcomeForm::browse=Leta...\r\nWelcomeForm::label1=Ladda Klient:\r\nWelcomeForm::patchEncy=Anvnd klientens kryptering\r\nWelcomeForm::showAtStart=Visa detta nr Razor startar\r\nWelcomeForm::quit=&Stng\r\nWelcomeForm::okay=&Okej\r\n\r\nMainForm::Text=Razor v{0}\r\nMainForm::generalTab=Allmnt\r\nMainForm::label10=Leta efter uppdateringar:\r\nMainForm::systray=Aktivitetsfltet\r\nMainForm::taskbar=Meddelandefltet\r\nMainForm::smartCPU=Anvnd smart CPU reducering\r\nMainForm::label7=Sprk:\r\nMainForm::label11=Visa i:\r\nMainForm::groupBox4=Profiler\r\nMainForm::delProfile=Radera\r\nMainForm::newProfile=&Ny...\r\nMainForm::showWelcome=Visa Vlkomstskrmen (fr alla anvndare)\r\nMainForm::alwaysTop=Anvnd Smart Always on Top\r\nMainForm::groupBox1=Filter\r\nMainForm::opacityLabel=Opasitet: 100%\r\nMainForm::moreOptTab=Fler Alternativ\r\nMainForm::blockHealPoison=Blockera healing om mlet r frgiftat\r\nMainForm::potionEquip=Avvpna/Vpna hnder fr \"pots\"\r\nMainForm::label17=Razor meddelanden:\r\nMainForm::QueueActions=Ka Object-Anvndning Automatiskt \r\nMainForm::spellUnequip=Avvpna hnder autom. fr magier\r\nMainForm::autoOpenDoors=ppna drrar automatiskt\r\nMainForm::alwaysStealth=Visa alltid Stealth steg \r\nMainForm::autoFriend=Behandl gruppmedl som 'Friend'\r\nMainForm::chkStealth=Rkna stealth-steg\r\nMainForm::rememberPwds=Kom ihg lsenord\r\nMainForm::showtargtext=Visa mlets 'flag' vid singel-klick\r\nMainForm::preAOSstatbar=Anvnd 'Pre-AOS' statusfnster\r\nMainForm::logPackets=Mjliggr paket loggning\r\nMainForm::rangeCheckLT=Avstnd p LastTarget:\r\nMainForm::actionStatusMsg=Visa Objekt-k meddelanden\r\nMainForm::label5=Objekt timer:\r\nMainForm::label9=Klientens Prioritet:\r\nMainForm::label8=tiles\r\nMainForm::label6=ms\r\nMainForm::label18=x\r\nMainForm::gameSize=Betvinga Fnster:\r\nMainForm::smartLT=Anvnd smart Last Target\r\nMainForm::moreOptTab=Alternativ\r\nMainForm::negotiate=Frhandla finesser med servern\r\nMainForm::setLTHilight=Val\r\nMainForm::lthilight=Last Target Markering:\r\nMainForm::filterSnoop=Filtrera Snooping-meddelanden\r\nMainForm::incomingCorpse=Visa namnen p Nya/Inkommande Lik\r\nMainForm::incomingMob=Visa namnen p Inkommande Folk/F\r\nMainForm::setHarmHue=Val\r\nMainForm::setNeuHue=Val\r\nMainForm::lblHarmHue=Harmfull\r\nMainForm::lblNeuHue=Neutral\r\nMainForm::lblBeneHue=Godartad\r\nMainForm::setBeneHue=Val\r\nMainForm::setSpeechHue=Val\r\nMainForm::setWarnHue=Val\r\nMainForm::setMsgHue=Val\r\nMainForm::setExHue=Val\r\nMainForm::autoStackRes=Bunta Malm/Fisk/Stockar vid Ftter\r\nMainForm::queueTargets=Ka LastTarget och TargetSelf\r\nMainForm::spamFilter=Filtrera repeterande systemmeddelanden\r\nMainForm::label4=tiles\r\nMainForm::openCorpses=ppna nya lik innom\r\nMainForm::showNotoHue=Visa notoritetsfrg p {char} i TitleBar\r\nMainForm::lblWarnHue=Varningsmedd. frg\r\nMainForm::lblMsgHue=Razors meddel. frg\r\nMainForm::lblExHue=Sk-Frskoningsfrg\r\nMainForm::blockDis=Blockera avsittning i strid\r\nMainForm::chkForceSpellHue=ndra Spell-frg:\r\nMainForm::chkForceSpeechHue=sidostt Talfrg\r\nMainForm::label3=Spell Format:\r\nMainForm::displayTab=Visning/Rknare\r\nMainForm::warnCount=Varna nr en rknare r under:\r\nMainForm::excludePouches=Autosk aldrig Pouches\r\nMainForm::highlightSpellReags=Markera reagenter vid Spell\r\nMainForm::titlebarImages=Visa bilder vid Rknare\r\nMainForm::checkNewConts=Sk autom. i nya behllare\r\nMainForm::groupBox3=Titelfnster Visning\r\nMainForm::showInBar=Visa detta i UOs titelfnster:\r\nMainForm::groupBox2=Rknare\r\nMainForm::delCounter=Rade/ndr\r\nMainForm::addCounter=Lgg till...\r\nMainForm::recount=Omrkn.\r\nMainForm::dressTab=Vpna/Kld\r\nMainForm::groupBox6=Bevpning/Kld Artiklar\r\nMainForm::clearDress=Rensa Listan\r\nMainForm::dressDelSel=Avlgsna\r\nMainForm::undressBag=ndra Avkldn. sck\r\nMainForm::undressList=Avkld\r\nMainForm::dressUseCur=Lgg till nuvarande\r\nMainForm::targItem=Lgg till (Ml)\r\nMainForm::dressNow=Kld\r\nMainForm::groupBox5=Bevpna/Kld det valda\r\nMainForm::removeDress=Avlgsna\r\nMainForm::addDress=Lgg till...\r\nMainForm::undressConflicts=Avlgsna autom. bestridande artikl.\r\nMainForm::skillsTab=Frdigheter\r\nMainForm::dispDelta=Visa frdighets- och statndringar\r\nMainForm::skillCopyAll=Kopiera Alla\r\nMainForm::skillCopySel=Kopiera de Valda\r\nMainForm::label1=Base Total:\r\nMainForm::setlocks=Set all locks:\r\nMainForm::resetDelta=Reset  +/-\r\nMainForm::agentsTab=Agenter\r\nMainForm::hotkeysTab=Snabbtange.\r\nMainForm::dohotkey=Aktivera Valda\r\nMainForm::groupBox8=Snabbtangent\r\nMainForm::chkPass=Skicka ven till UO\r\nMainForm::label2=Key:\r\nMainForm::unsetHK=Avstll\r\nMainForm::setHK=Bruka\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Macron\r\nMainForm::macroActGroup=Handlingar\r\nMainForm::loopMacro=Slinga\r\nMainForm::recMacro=Spela in\r\nMainForm::playMacro=Spela upp\r\nMainForm::delMacro=Avlgsna\r\nMainForm::newMacro=Ny...\r\nMainForm::screenshotTab=Skrmdumpar\r\nMainForm::label12=Bildformat:\r\nMainForm::capNow=Ta Skrmdump Nu\r\nMainForm::radioUO=Endast UO\r\nMainForm::radioFull=Helskrm\r\nMainForm::screenAutoCap=Automatisk ddskrmsgonblick\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Inkludera tidsstmpel p bilderna\r\nMainForm::videoTab=Videoinspeln.\r\nMainForm::recFolder=...\r\nMainForm::label13=Inspelningsmapp:\r\nMainForm::groupBox7=PacketVideo Inspelning\r\nMainForm::vidRec=Spela in PacketVideo\r\nMainForm::groupBox10=AVI Video Inspelning\r\nMainForm::flipVidVert=Vertikal\r\nMainForm::flipVidHoriz=Horisontal\r\nMainForm::recAVI=Spela in AVI Video...\r\nMainForm::label16=Upplsning:\r\nMainForm::label15=FPS:\r\nMainForm::label19=Vnd:\r\nMainForm::groupBox9=PacketVideo Uppspelning\r\nMainForm::label14=Hastighet:\r\nMainForm::vidClose=Stng\r\nMainForm::vidPlayStop=Stoppa\r\nMainForm::vidPlay=Spela\r\nMainForm::vidOpen=ppna...\r\nMainForm::statusTab=Hjlp && Status\r\nMainForm::forumsLink=Razor Diskussionsforum\r\nMainForm::homeLink=Razor Hemsidan\r\nMainForm::userGuideLink=Razor Anvndarmanual\r\n\r\nHueEntry::Text=Vlj en frg\r\nHueEntry::cancel=Avbryt\r\nHueEntry::okay=&Okej\r\nHueEntry::preview=Frhandsgranska\r\nHueEntry::inGame=Vlj i spelet\r\nHueEntry::label1=Frgnummer:\r\n\r\nAddCounter::Text=Lgg till en Rknare\r\nAddCounter::delete=Ta bort\r\nAddCounter::target=Vlj \r\nAddCounter::cancel=Avbryt\r\nAddCounter::Add=&Okej\r\nAddCounter::label4=Frg (Valfri: -1):\r\nAddCounter::label3=Artikel ID:\r\nAddCounter::label2=Format:\r\nAddCounter::label1=Namn:\r\n\r\nMacroInsertWait::Text=Lgg in en Pause...\r\nMacroInsertWait::radioMenu=Vnta p gammaldags Meny/Dialog\r\nMacroInsertWait::cancel=&Avbryt\r\nMacroInsertWait::radioStat=Vnta i \r\nMacroInsertWait::radioTarg=Vnta p Target\r\nMacroInsertWait::radioGump=Vnta p Gump\r\nMacroInsertWait::label1=millisekunder\r\nMacroInsertWait::radioPause=Pausa i:\r\nMacroInsertWait::insert=&Inflika\r\n\r\nMacroInsertIf::Text=Inflika Om...\r\nMacroInsertIf::label1=Om:\r\nMacroInsertIf::cancel=&Avbryt\r\nMacroInsertIf::insert=&Inflika\r\n\r\n[strings]\r\n1001=Ddsstatus\r\n1002=Bardmusik\r\n1003=Hundljud\r\n1004=Kattljud\r\n1005=Hstljud\r\n1006=Frljud\r\n1007=Spirit Speak ljud\r\n1008=Spell Fizzle ljud\r\n1009=Vder\r\n1010=Visa Rknare\r\n1011=Rkna om Rknare\r\n1012=Rensa AOS Frmga\r\n1013=Bruka Primr Frmga (AOS)\r\n1014=Bruka Sekundr Frmga (AOS)\r\n1015=Stun av/p (Pre-AOS)\r\n1016=Disarm av/p (Pre-AOS)\r\n1017=Bruka frmga {0}\r\n1018=AOS-frmgor rensade.\r\n1019=Avkld allt\r\n1020=Avkld bda hnderna\r\n1021=Avkld Vnstra handen\r\n1022=Avkld Hgra handen\r\n1023=Avkld hatten\r\n1024=Avkld smycken\r\n1025=Bandagera Self\r\n1026=Bandagera LastTarget\r\n1027=Bruka Bandage (Ingen Timer)\r\n1028=Drick Heal\r\n1029=Drick Cure\r\n1030=Drick Refresh\r\n1031=Drick Night Sight\r\n1032=Drick Explosion\r\n1033=Drick Strength\r\n1034=Drick Agility\r\n1035=Inga bandage funna\r\n1036=Inga artiklar av typen {0} funna!\r\n1037=Dubbelklicka ({0})\r\n1038=ter-Sikta\r\n1039=Konvertera till DClick enligt Type\r\n1040=Vlj ett nytt ml vid denna handling.\r\n1041=VARNING: Undantag ptrffades medan denna profil laddades:\\n{0}\r\n1042=Macro Varning: Kan inte finna den artikeln (Fr stort avstnd).\r\n1043=Lyft {1} - {0}\r\n1044=Konvertera till Lyfta enligt Typ\r\n1045=Macro Varning: Hller inte i ngot.\r\n1046=Utrusta till {0} (L:{1})\r\n1047=Lgg {0} (@{1})\r\n1048=Konvertera till Relativ Plats\r\n1049=Lgg (Relativt) @({0},{1},{2})\r\n1050=GumpSvar (Knapp {0})\r\n1051=Stng Gump\r\n1052=MenySvar {0}\r\n1053=Varning: Macrot kallade p ett target, men servern skickade inget! (Behver du kanske anvnda 'WaitForTarget'?)\r\n1054=Absolut Target\r\n1055=Konvertera till LastTarget\r\n1056=Konvertera till Target enligt Typ\r\n1057=Trget RelLoc ({0},{1})\r\n1058=Last Tagret\r\n1059=Target Self\r\n1060=Vlj Last Target\r\n1061=Stt slumpmssig Red som Target\r\n1062=Stt slumpmssig Grey som Target\r\n1063=Stt slumpmssig Blue som Target\r\n1064=Stt slumpmssig Enemy som Target\r\n1065=Stt slumpmssig Friendly som Target\r\n1066=Stt slumpmssig Non-Friendly som Target\r\n1067=Sg \"{0}\"\r\n1068=AnvndFrdighet {0}\r\n1069=AnvndSpell {0}\r\n1070=BrukaFrmga {0}\r\n1071=Kld: {0}\r\n1072=Avkld: {0}\r\n1073=Avkld Lager {0}\r\n1074=Vnta p meny (Vilken som helst)\r\n1075=Vnta p meny (#{0})\r\n1076=ndra...\r\n1077=Vnta p Gump (Vilken som helst)\r\n1078=Vnta p Gump (#{0})\r\n1079=Vnta p Riktmrke\r\n1080=Pause {0:#.00}sek\r\n1081=Vnta p {0} {1} {2}\r\n1082=Laddar '{0}'...\r\n1083=> Stoppa Aktivt Macro\r\n1084=Spela: {0}\r\n1085=Spelar Macro '{0}'...\r\n1086=Macro '{0}' klart.\r\n1087=Razor kunde itne initialisera.  Felkod:\\n\r\n1088=Beskrivning: Could not find the client Window Handle.\\nMjlig Orsak: The Client may not have initialized properly.\r\n1089=Description: Could not find the Client's ThreadID\\nPossible Cause: The Client may not have initialized Properly.\r\n1090=Description: Could not create Windows Hooks.\\nPossible Cause: Internal error.\r\n1091=Description: Could not create or access Razor shared memory.\\nPossible Cause: Windows Error or invalid permissions.\r\n1092=Description: Crypt.dll has disabled itself.\\nPossible Cause: Version mismatch.\r\n1093=Description: Could not patch the client's Winsock functions.\\nPossible Cause: Internal error, Windows Error, or Incompatible Version.\r\n1094=Description: An invalid parameter was passed to the loade.\\nPossible Cause: Mismatched DLL versions.\r\n1095=Warning: Could not copy packet lengths and/or encryption information from the client.\\nRazor may be able to run without this information, though some features may not function correctly.  Would you like to start Razor anyway?\\n\\nPossible Cause: Your client version may not be compatible with this version of Razor.\r\n1096=Your skill in {0} has changed by {4}{5:F1}, it is now {3:F1} ({1}{2:F1}).\r\n1097=Invalid frkortning.\r\n1098=Invalid artikel id.\r\n1099=Invalid frg.\r\n1100=Vlj en artikel att rkna.\r\n1101=Error loading '{0}'!\\nThis profile is corrupt and cannot be used.\r\n1102=The property {0} was not found in this profile.\r\n1103=Your counters.xml file is corrupt and cannot be used.\r\n1104=Because you have Auto Search Containers off, you must now reopen all of your bags so that your counters can be updated.\r\n1105=Varning: {0} mngd r nu {1}!\r\n1106=Vlj frgen du nskar anvnda.\r\n1107=Ta Skrmdump Nu\r\n1108=Possible values:\\n{char} - Character name\\n{shard} - Shard name\\n{str}/{hp}/{hpmax} - Health status\\n{dex}/{stam}/{stammax} - Dex status\\n{int}/{mana}/{manamax} - Int status\\n{weight}/{maxweight} - Weight information\\n{gold} - Total Gold on character\\n{AR} - Armor Rating / Physical Resistance\\n{tithe} - Tithing points\\n{followers}/{followersmax} - Followers slots\\n{bandage} - Bandage Timer\\n{statbar}/{mediumstatbar}/{largestatbar} - Status bar\\n{crimtime} - How long you have been a criminal\\n{stealthsteps} - Stealth steps counter\\n{physresist} - Physical Resistance\\n{coldresist} - Cold Resistance\\n{fireresist} - Fire Resistance\\n{energyresist} - Energy Resistance\\n{poisonresist} - Poison Resistance\\n{luck} - Luck\\n{damage} - Damage Min-Max\\nColor - HTML hex color code: '~#rrggbb' ('~#~' to terminate)\\nOr a {Format} from the Counters list\r\n1109=Razor Version: {0}\\nMemory Used: {1}\\nSend: {2} ({3}/s)\\nRecv: {4} ({5}/s)\\nConnected for {6}\\n\\nPlayer Serial: 0x{7:X8}\\nBackpack Serial: 0x{8:X8}\\n\\nTracking Items: {9}\\nTracking Mobs: {10}\\n\r\n1110=Stt Pil: UPP\r\n1111=Stt Pil: NER\r\n1112=Stt Pil: LST\r\n1113=r du sker p att du vill avlgsna rknaren \"{0}\"?\\nDetta kommer pverka alla profiler.\r\n1114=Ladda profilen \"{0}\" nu?\r\n1115=Ett fel uppstod nr profilen skulle laddas.\r\n1116=Du kan ej ta bort standardprofilen\r\n1117=Skriv ett profilnamn: \r\n1118=Kan ej skapa en ny profil!\\n Anledning: En profil vid detta namn existerar redan.\\n\\nVil du ladda sagda nu?\r\n1119=Skriv ett namn fr denna nya Dress List:\r\n1120=Ta bort denna dress list?\r\n1121={0:X} (Artikel out of Range)\r\n1122=Avlgsna artikeln frn denna dress list?\r\n1123=Vlj en pse som listan '{0}' kan avklda till.\r\n1124=Undress pse vald.\r\n1125=Artikeln hittades ej, eller s valdes fel sort.\r\n1126=Den tangentkombinationen anvnds redan av '{0}'.\\nBut till '{1}'?\r\n1127=Datan sparades.\r\n1128=Warning!\\nLogging packets may reduce Razor's performance. Log files can also\\neasily grow very large, and Razor will not automatically remove them.\\n\\nRazor's packet log files may contain personal information such as\\npasswords, and should be not be given to people you do not trust.\\n\\nAre you sure you want to enable packet logging?\\n(This will not be saved in your user profile)\r\n1129=Konvertera det valda till TYPE\r\n1130=Skriv ett namn fr det nya macrot: \r\n1131=Namnet innehller icke tilltna tecken.\r\n1132=Ett macro vid det namnet finns redan.\r\n1133=Detta macrot kommer att rensas innan inspelning.\\nVill du verkligen spela ver detta macrot?\r\n1134=Vill du verkligen PERMANENT ta bort '{0}'?\\n(Detta r utan tervndo)\r\n1135=inflika Pause/Vntan...\r\n1136=Inflika Vlj LastTarget\r\n1137=Flytta Upp\r\n1138=Flytta Ner\r\n1139=Ta bort Handling\r\n1140=Brja Inspeningen Hr\r\n1141=Filen '{0}' hittades ej.\r\n1142=r du sker?\r\n1143=VARNING: Den fljande {0} file{1} kunde inte tas bort:\\n{2}\r\n1144=Denna ndringen kommer trda i kraft efter att Razor startats om.\r\n1145=Vljer du detta s kommer Razor att spara dina lsenord i din profil.\\nLsenorden r dock krypterade men ehuru kan nn f tag i din XML fil och f tag p dina lsenord.\\nr du sker p att du vill anvnda detta val?\r\n1146=Du mste vlja en port.\r\n1147=Ignorerar handlingsfrfrgan (redan kad).\r\n1148=Kar handlingsfrfrgan {0}... {1} kvar.\r\n1149=Frdigstllde {0} kade handlingar p {1:F1} sekunder.\r\n1150=Use Once Agent\r\n1151=Lgg till (Target)...\r\n1152=Lgg till Behllare (Target)...\r\n1153=Avlgsna (Target)...\r\n1154=Rensa Listan\r\n1155=Vlj en artikel som ska lggas till.\r\n1156=Vlj en behllare.\r\n1157=Vlj en artikel att avlgsna.\r\n1158=Artikel tillagd.\r\n1159=Artikel avlgsnad.\r\n1160={0} artiklar tillagda till Use Once agenten.\r\n1161=UseOnce kn r tom!\r\n1162=Anvnder '{0}'.  ({1} artiklar kvar i UseOnce kn)\r\n1163=Ett problem uppstod med en av dina UseOnce artiklar, frsker med nsta.\r\n1164=SellAgent: Sljer automatiskt {0} artiklar fr {1}gp.\r\n1165=Avlgsna\r\n1166=Behllare vald.\r\n1167=Rensa\r\n1168=(Kliicka fr att stnga av)\r\n1169=(Klicka fr att stta p)\r\n1170=Vlj Hot Bag\r\n1171=Rensa Hot Bag\r\n1172=Organizer Agent\r\n1173=Organizer\r\n1174=Organisera Nu\r\n1175=En behllare r inte vald.\r\n1176=Razor kunde inte hitta din ryggsck.\r\n1177=Organize Agenten har kat {0} artiklar som ska flyttas. (detta kan ta ett tag)\r\n1178=Organize Agenten hittade inga artiklar att flytta.\r\n1179=Den artikeln r redan listad.\r\n1180=AutoSearchExemptions\r\n1181=Buy Agenten kpte {0} artiklar fr {1}gp.\r\n1182=Buy Agenten kpte inte vissa artiklar p listan fr att du har inte nog med guld.\r\n1183=Skriv mngd:\r\n1184=Clientens Processprioritet satt till {0}\r\n1185=KLockan r: {0}\r\n1186=Du r vid {0} i '{1}'\r\n1187=Undress bag hittades inte eller var utom rckhll, anvnder din ryggsck istllet\r\n1188={0} artiklar kade fr avkldning.\r\n1189={0} artiklar kade fr bekldning.\r\n1190={0} artiklar r redan bekldda.\r\n1191={0} artiklar hittades inte. (Out of Range)\r\n1192=Varning: Spells.def hittades ej, spell format text kommer ej att visas\r\n1193=Stealth Steg: {0}\r\n1194=Rknar nu stealth steg.\r\n1195=Rensa Target Queue\r\n1196=Attackera Last Combatant\r\n1197=Target queue rensad.\r\n1198=Vlj ett nytt 'Last Target'\r\n1199=Last Target valt.\r\n1200=Nytt target valt.\r\n1201=Inget sdant ml finns p din skrm.\r\n1202=Kar target self.\r\n1203=Kar last target.\r\n1204=Servern snde ett nytt target, avbryter Razors target.\r\n1205=Target by Type {0}\r\n1206=Scavenger\r\n1207=Vill du verkligen ta bort detta?\r\n1208=Vlj en mapp vari Razors skrmdumpar ska sparas.\r\n1209=Snabbtangenter\r\n\r\n1210=Artiklar\r\n1211=Targets\r\n1212=Agenter\r\n1213=Kld\r\n1214=Macron\r\n1215=Spells\r\n1216=Frdigheter\r\n1217=Blandat\r\n1251=1st\r\n1252=2nd\r\n1253=3rd\r\n1254=4th\r\n1255=5th\r\n1256=6th\r\n1257=7th\r\n1258=8th\r\n1260=Necromancy\r\n1270=Chivalry\r\n1271=Potions\r\n1272=Special Moves\r\n1290=Bushido\r\n1300=Ninjitsu\r\n1301=Slj\r\n1302=Kp\r\n1303=Skrift Krvs\r\n1304=Razor Kommandolista\r\n1305=Anvnd Artikeln i Handen\r\n1306=Du mste avvpna ntt innan du kan vpna det.\r\n1307=Vpna/Avvpna Hger Hand\r\n1308=Vpna/Avvpna Vnster Hand\r\n1309=Avvpna det som du hller i\r\n1310=Spellweaving\r\n1311=> Stt p/Stng av Razors Snabbtangenter\r\n1312=Snabbtangenter pslagna (Tryck {0} fr att stnga av dem)\r\n1313=Snabbtangenter avstngda (Tryck {0} fr att sl p dem)\r\n1314=Snabbtangenter pslagna\r\n1315=Snabbtangenter avstngda\r\n1316=G: {0}\r\n1317=Lgg till Typ (Target)...\r\n1318=Det valda mlet r utom rckhll, last target verkstlldes ej!\r\n1319=Max Slj: {0}\r\n1320=Snooping Meddelanden\r\n1321=Ryggscksljud\r\n1322=Inflika \"If\" Argument\r\n1323=Inflika \"Else\"\r\n1324=Inflika \"End If\"\r\n1325=Vlj Mngd\r\n1326=Fyll p\r\n1327=Fyll p Nu\r\n1328=Pfyllningsagenen\r\n1329=Vlj en behllare att fylla p frn, eller vlj dig sjlv fr att anvnda banken.\r\n1330=Den behllaren r ej giltig.\r\n1331=Pfyllning klar, kade {0} artiklar{1}.\r\n1332=Avbryt Current Target\r\n1333=En nyare Razor version finns tillgnglig p hemsidan.\\n\\nVill du beska Razor websidan fr att ladda ner den nya versionen?\r\n1334=Ladda om\r\n1335=Spara\r\n1336=Varning: Det nuvarande riktmrket kan ej vara markbundet.  Last Target verkstlldes ej.\r\n1337=tersynchronisera Klienten\r\n1338=Avsittning blockerad.\r\n1339=Starta Razor \"PacketVideo\" Inspelning\r\n1340=Stoppa \"PacketVideo\" Inspening/Uppspelning\r\n1341=Ett fel uppstod vid inspeningen.\\nTUndantaget har loggfrts.\r\n1342=Denna fil r ej kompatibel med denna Razor version.  Se till att du har den senaste Razor versionen.\r\n1343=Denna videofil r korrupt.\\nDen kan vara sndrad eller mixtrad med.\\nFilen kan ej spelas.\r\n1344=Filen kunde ej lsas.  Den kan vara skadad eller sndrad.\r\n1345=Skrev ett kategorinamn:\r\n1346=Mappen kunde ej tas bort.  Se till att den r tom.\r\n1347=Mapen kunde ej skapas.  Se till att det valda namnet r godtagbart.\r\n1348=Macro filen kunde ej flyttas.  Se till att kategorinamnet r godtagbart.\r\n1349=Friends\r\n// 1350 to 1359 reserved (max length 15!)\r\n1350=Stopped\r\n1351=The End\r\n1352=Game Over?\r\n1353=ker-pwned\r\n1354=Got corp por?\r\n1355=bamboozled\r\n1356=pwned?\r\n1357=Jesus <3s you\r\n1358=Kal Vas Pwned\r\n1359=SMACKDOWN\r\n1360=Vlj en spelare som ska lggas till din friend list.\r\n1361=Vlj en spelare att avlgsna frn din friend list.\r\n1362=Friend tillagd.\r\n1363=Friend avlgsnad.\r\n1364=Special Constructs\r\n1365=Inflika \"For Loop\"\r\n1366=Inflika \"End For\"\r\n1367=Skriv in nskade upprepningar:\r\n1368=Rensa Scavenger Cachen\r\n1369=Last Spell\r\n1370=Last Skill\r\n1371=Last Object\r\n1372=All Names\r\n1373=UseOnce\r\n1374=Target Random Enemy Humanoid\r\n1375=Target Random Grey Humanoid\r\n1376=Target Random Innocent Humanoid\r\n1377=Target Random Criminal Humanoid\r\n1378=Target Random Criminal\r\n1379=VARNING: Drag/Slpp paus! Slpper den handhllna artikeln i ryggscken.\r\n1380=Du mste starta om Razor och klienten fr att verkstlla ndringen.\r\n1381=Du mste logga ut och sedemera in igen fr att denna ndring ska fungera.\r\n1382=Kar dragdrop begran {0}... {1} kvar.\r\n1383=Pfyllningsfrfrgan verkstlls....\r\n1384=Din strength har ndrats med {0}{1}, den r nu {2}.\r\n1385=Din dexterity ndrats med {0}{1}, den r nu {2}.\r\n1386=Din intelligence har ndrats med {0}{1}, den r nu {2}.\r\n1387=Light Levels\r\n1388=Heal blockerad (mlet r frgiftat)!\r\n1389=Rensa Drag/Slpp Kn\r\n1390=Stoppa Nu\r\n1391=>Heal/Cure Self\r\n1392=Next Target\r\n1393=Vlj Pfyllnings HotBag\r\n1394=Lgg till UseOnce\r\n1395=Attackera Last Target\r\n1396=ndra Vntan...\r\n1397=Du hller inte i ngot.\r\n1398=INTE tilltet\r\n1399=tilltet\r\n1400=Finesser frhandlade med servern:\r\n1401=Alla finesser tilltna.\r\n1402=Vderfilter\r\n1403=Ljusniv-filter\r\n1404=Smart LastTarget\r\n1405=Kontrollera avstndet p LastTarget\r\n1406=ppna drrar automatiskt\r\n1407=Avvpna innan Spell Cast\r\n1408=Auto-Potion Vpning\r\n1409=Blockera Heal vid Poison\r\n1410=Loopar Macron\r\n1411=Use Once Agent\r\n1412=Pfyllningsagent\r\n1413=Slj Agent\r\n1414=Kp Agent\r\n1415=Potion Snabbtangenter\r\n1416=Slumpa Targets\r\n// 1417 to 1465 reserved\r\n1466=Finessen tillts ej av servern\r\n1467=Servern tillter itne denna finess.\\nDu kan vlja att ignorera servern i \"Options\" tabben.\\n\\nFr att se en lista ver icke tilltna finesser, iakta \"Help & Status\" tabben.\r\n1468=Inflika Kommentar\r\n1469=Lgg till Friend\r\n1470=Avlgsna Friend\r\n1471=>Mini-Heal/Cure Self\r\n1472=Du borde bara stnga av \"Patch Encryption\" om du anvnder en avkrypterad klient.  Du ska behlla det ven p OSI/EA servrar.\\nOm du r osker s ska du lmna boxen ikryssad..\\n\\r du sker p att du vill stnga av client-side encryption patching?\r\n1473=Avsittning\r\n1474=Visa/Dlj Map Fnstret\r\n1475=Det r fr lngt borta.\r\n1476=Drag-slpp kn r FULL! Var god vnta.\r\n1477=Pendla mellan War/Peace\r\n"
  },
  {
    "path": "etc/Language/Razor_lang.tur",
    "content": "// Razor Turkish/TUR Language Pack\r\n// Last Modified 08/02/05\r\n// Author : Yilmaz YAVUZ [Mystraworld ATi]\r\n::CliLoc=TUR\r\n\r\n[controls]\r\nWelcomeForm::Text=Razor a Hosgeldiniz!\r\nWelcomeForm::groupBox3=UO dosya yolu\r\nWelcomeForm::dataBrowse=Bul...\r\nWelcomeForm::label5=Dil:\r\nWelcomeForm::groupBox2=Sunucu ayarlari\r\nWelcomeForm::label3=Sunucu:\r\nWelcomeForm::label4=Port:\r\nWelcomeForm::groupBox1=Istemci Ayarlari\r\nWelcomeForm::useEnc=OSI sifrelemesi kullan\r\nWelcomeForm::makeDef=Bu ayarlari varsayilan yap\r\nWelcomeForm::browse=Bul...\r\nWelcomeForm::label1=Istemci:\r\nWelcomeForm::patchEncy=Patch client encryption\r\nWelcomeForm::showAtStart=Razor basladiginda goster\r\nWelcomeForm::quit=&Cikis\r\nWelcomeForm::okay=&Tamam\r\n\r\nMainForm::Text=Razor v{0}[waptir.com]\r\nMainForm::generalTab=Genel\r\nMainForm::label10=Guncelleme ayari:\r\nMainForm::systray=System Tray\r\nMainForm::taskbar=Taskbar\r\nMainForm::smartCPU=Akilli CPU kullanimi\r\nMainForm::label7=Lisan:\r\nMainForm::label11=Goster:\r\nMainForm::groupBox4=Profiller\r\nMainForm::delProfile=Sil\r\nMainForm::newProfile=&Yeni...\r\nMainForm::showWelcome=Acilis ekranini goster(Tum kullanicilar icin)\r\nMainForm::alwaysTop=Akilli ustte kalmayi kullan\r\nMainForm::groupBox1=Filtreler\r\nMainForm::opacityLabel=Seffaf: 100%\r\nMainForm::moreOptTab=Ayarlar\r\nMainForm::setLTHilight=Rnk\r\nMainForm::lthilight=Son hedef belirt:\r\nMainForm::filterSnoop=Snooping mesajlarini gosterme\r\nMainForm::incomingCorpse=Yeni cesetlerin ismini goster\r\nMainForm::incomingMob=Yeni kisi/npclerin ismini goster\r\nMainForm::setHarmHue=Rnk\r\nMainForm::setNeuHue=Rnk\r\nMainForm::lblHarmHue=Zararli\r\nMainForm::lblNeuHue=Tarafsiz\r\nMainForm::lblBeneHue=Yararli\r\nMainForm::setBeneHue=Rnk\r\nMainForm::setSpeechHue=Rnk\r\nMainForm::setWarnHue=Rnk\r\nMainForm::setMsgHue=Rnk\r\nMainForm::setExHue=Rnk\r\nMainForm::autoStackRes=Auto-Stack Ore/Fish/Logs at Feet\r\nMainForm::autoFriend=Partidekileri Friend olarak algila\r\nMainForm::queueTargets=Targetself ve lasttarget leri siraya koy\r\nMainForm::spamFilter=Tekrar eden sistem mesajlarini gosterme\r\nMainForm::label4=ise\r\nMainForm::openCorpses=Yeni cesetleri ac. Uzaklik\r\nMainForm::showNotoHue=Show noto hue on {char} in TitleBar\r\nMainForm::lblWarnHue=Uyari mesaji rengi\r\nMainForm::lblMsgHue=Razor mesaji rengi\r\nMainForm::lblExHue=Arama mesaji rengi\r\nMainForm::chkStealth=Gizli yurume adimlarini say\r\nMainForm::chkForceSpellHue=Buyu renkleri:\r\nMainForm::chkForceSpeechHue=Konusma rengi\r\nMainForm::label3=Buyu yazisi:\r\nMainForm::moreMoreOptTab=Diger Ayarlar\r\nMainForm::blockDis=Savas modunda binekten inme\r\nMainForm::rememberPwds=Parolalari hatirla \r\nMainForm::showtargtext=Tek clickte hedefi goster\r\nMainForm::smartLT=Akilli lasttarget'i kullan\r\nMainForm::preAOSstatbar=Pre-Aos status unu kullan\r\nMainForm::logPackets=Paket loglamasini ac\r\nMainForm::warnCount=Eger sayaclar dusukse uyar:\r\nMainForm::label8=kare\r\nMainForm::rangeCheckLT=Lasttarget menzili:\r\nMainForm::spellUnequip=Buyu yaparken silahlari indir\r\nMainForm::actionStatusMsg=Siralama mesajlarini goster\r\nMainForm::label6=ms\r\nMainForm::label5=Nesne suresi\r\nMainForm::QueueActions=Nesne geciktirme olaylarini sirala \r\nMainForm::label9=Istemci ustunlugu:\r\nMainForm::displayTab=Ekran/Sayaclar\r\nMainForm::excludePouches=Pouchlari sakin arama\r\nMainForm::highlightSpellReags=Buyu yaparken regleri belirt\r\nMainForm::titlebarImages=Sayaclarda resim goster\r\nMainForm::sortCounters=Akilli sayac siraliyici kullan\r\nMainForm::checkNewConts=Yeni kutulari ara\r\nMainForm::groupBox3=Baslik Cubugu Gorunumu\r\nMainForm::showInBar=Baslik cubugunda goster:\r\nMainForm::groupBox2=Sayaclar\r\nMainForm::delCounter=Sil/Duznle\r\nMainForm::addCounter=Ekle...\r\nMainForm::recount=Yenile\r\nMainForm::dressTab=Elbise-Item\r\nMainForm::groupBox6=Nesne listesi\r\nMainForm::clearDress=Listeyi sil\r\nMainForm::dressDelSel=Sil\r\nMainForm::undressBag=Cikarma Poseti Ayarla\r\nMainForm::undressList=Cikar\r\nMainForm::dressUseCur=Suankini ekle\r\nMainForm::targItem=Ekle (Nesne)\r\nMainForm::dressNow=Giy\r\nMainForm::groupBox5=Giysi Listesi\r\nMainForm::removeDress=Cikar..\r\nMainForm::addDress=Ekle...\r\nMainForm::undressConflicts=Ayni nesneleri tasi\r\nMainForm::skillsTab=Skiller\r\nMainForm::dispDelta=Otomatik yenile\r\nMainForm::skillCopyAll=Hepsini Kopyala\r\nMainForm::skillCopySel=Secileni Kopyala\r\nMainForm::label1=Skiller toplami:\r\nMainForm::setlocks=Hepsini:\r\nMainForm::resetDelta=Reset  +/-\r\nMainForm::agentsTab=Agents\r\nMainForm::hotkeysTab=Tuslar\r\nMainForm::dohotkey=Secileni yap\r\nMainForm::groupBox8=Tus\r\nMainForm::chkPass=UO ya gecir\r\nMainForm::label2=Tus:\r\nMainForm::unsetHK=Bosalt\r\nMainForm::setHK=Ayarla\r\nMainForm::chkCtrl=Ctrl\r\nMainForm::chkAlt=Alt\r\nMainForm::chkShift=Shift\r\nMainForm::macrosTab=Makrolar\r\nMainForm::macroActGroup=Olaylar\r\nMainForm::loopMacro=Dondur\r\nMainForm::recMacro=Kaydet\r\nMainForm::playMacro=Oynat\r\nMainForm::delMacro=Sil...\r\nMainForm::newMacro=Ekle..\r\nMainForm::screenshotTab=Ekran Goruntusu\r\nMainForm::label12=Resim Formati\r\nMainForm::capNow=Simdi SS cek\r\nMainForm::radioUO=Sadece UO\r\nMainForm::radioFull=Tum Ekran\r\nMainForm::screenAutoCap=Olunce otomatik ss cek\r\nMainForm::setScnPath=...\r\nMainForm::dispTime=Resimlere tarih ekle\r\nMainForm::videoTab=Video cek\r\nMainForm::recFolder=...\r\nMainForm::label13=Kayit klasoru:\r\nMainForm::groupBox7=PacketVideo kayidi\r\nMainForm::vidRec=PacketVideo kaydet\r\nMainForm::groupBox10=AVI Video kayidi\r\nMainForm::recAVI=AVI Video kaydet...\r\nMainForm::label16=Cozunurluk:\r\nMainForm::label15=FPS:\r\nMainForm::groupBox9=PacketVideo Oynat\r\nMainForm::label14=Hiz:\r\nMainForm::label17=Razor mesajlari:\r\nMainForm::vidClose=Kapat\r\nMainForm::vidPlayStop=Dur\r\nMainForm::vidPlay=Oynat\r\nMainForm::vidOpen=Ac...\r\nMainForm::statusTab=Yardim && Status\r\nMainForm::visitForums=Yardim Forumlari\r\nMainForm::visitHome=Razor Anasayfasi\r\nMainForm::visitGuide=Razor Klavuzu\r\n\r\nHueEntry::Text=Renk Sec\r\nHueEntry::cancel=Iptal\r\nHueEntry::okay=&Tamam\r\nHueEntry::preview=Onizle\r\nHueEntry::inGame=Oyunda Sec\r\nHueEntry::label1=Renk no:\r\n\r\nAddCounter::Text=Sayac editoru\r\nAddCounter::delete=Sil..\r\nAddCounter::target=Hedef \r\nAddCounter::cancel=Iptal\r\nAddCounter::Add=&Tamam\r\nAddCounter::label4=Renk (Any: -1):\r\nAddCounter::label3=Item ID:\r\nAddCounter::label2=Bicim:\r\nAddCounter::label1=Isim:\r\n\r\nMacroInsertWait::Text=Bekleme/Durdurma Ekle...\r\nMacroInsertWait::radioMenu=old-style Menu/Dialog icin bekle\r\nMacroInsertWait::cancel=&Iptal\r\nMacroInsertWait::radioStat=Bekle : \r\nMacroInsertWait::radioTarg=Hedef bekle :\r\nMacroInsertWait::radioGump=Gumpi bekle :\r\nMacroInsertWait::label1=milliseconds\r\nMacroInsertWait::radioPause=Bekle:\r\nMacroInsertWait::insert=&Ekle\r\n\r\nMacroInsertIf::Text=If.. ekle\r\nMacroInsertIf::label1=If:\r\nMacroInsertIf::cancel=&Iptal\r\nMacroInsertIf::insert=&Ekle\r\n\r\n[strings]\r\n1001=Death Status\r\n1002=Bard Muzikleri\r\n1003=Kopek sesleri\r\n1004=Kedi sesleri\r\n1005=At sesleri\r\n1006=Koyun sesleri\r\n1007=Spirit Speak sesi\r\n1008=Buyu fizzle sesi\r\n1009=Hava olayi sesi\r\n1010=Sayaclari goster\r\n1011=Sayaclari yenile\r\n1012=AOS abilitylerini sil\r\n1013=Set Primary Ability (AOS)\r\n1014=Set Secondary Ability (AOS)\r\n1015=Toggle Stun (Pre-AOS)\r\n1016=Toggle Disarm (Pre-AOS)\r\n1017=Setting ability {0}\r\n1018=AOS Abilities cleared.\r\n1019=Hepsini cikar\r\n1020=Ellerindekini indir\r\n1021=Sol elindekini indir\r\n1022=Sag elindekini indir\r\n1023=Sapkayi cikar\r\n1024=Yuzuk/Bilezik cikar\r\n1025=Bandaj self\r\n1026=Son hedefe bandaj\r\n1027=Bandaj kullan (Timersiz)\r\n1028=Heal ic\r\n1029=Cure ic\r\n1030=Refresh ic\r\n1031=Night Sight ic\r\n1032=Explosion at\r\n1033=Strength ic\r\n1034=Agility ic\r\n1035=Bandaj bulunamadi :(\r\n1036=item type {0} bulunamadi :(\r\n1037=Cift tikla ({0})\r\n1038=Yeni hedef\r\n1039=Tipine gore tiklamali yap\r\n1040=Bu olaya yeni hedef yap.\r\n1041=WARNING: Exception while loading profile property:\\n{0}\r\n1042=Macro Warning: Cannot find that item (Out of Range).\r\n1043=Kaldir {1} - {0}\r\n1044=Tipine gore kaldirmali yap\r\n1045=Macro Warning: Hic bisi kaldirmiyor.\r\n1046=Giy/tak {0} (L:{1})\r\n1047=Cikar {0} (@{1})\r\n1048=Bolgeye gore hedefle\r\n1049=Cikar (Relative) @({0},{1},{2})\r\n1050=Tiklama (Button {0})\r\n1051=Kapatma\r\n1052=Menu tiklama {0}\r\n1053=Warning: Macro requested target, but no target sent from server! (Do you need a 'WaitForTarget'?)\r\n1054=Bir hedef\r\n1055=Son hedefe cevir\r\n1056=Tipine gore hedefe cevir\r\n1057=Target RelLoc ({0},{1})\r\n1058=Son hedef\r\n1059=Kendine hedef\r\n1060=Son hedef yap\r\n1061=Herhangi bir kirmiziyi hedefle\r\n1062=Herhangi bir griyi hedefle\r\n1063=Herhangi bir maviyi hedefle\r\n1064=Herhangi bir dusmani hedefle\r\n1065=Herhangi bir arkadasi hedefle\r\n1066=Herhangi bir arkadas olmayani hedefle\r\n1067=Soyle: \"{0}\"\r\n1068=Skill kullan: {0}\r\n1069=Buyu yap: {0}\r\n1070=Ability yap: {0}\r\n1071=Giy: {0}\r\n1072=Cikar: {0}\r\n1073=Unequip Layer {0}\r\n1074=Herhangi bir menuyu bekle\r\n1075=Menuyu bekle: (#{0})\r\n1076=Duzenle...\r\n1077=Herhangi bir gump u bekle\r\n1078=Gump u bekle: (#{0})\r\n1079=Hedefi bekle\r\n1080={0:#.00}sn bekle\r\n1081={0} {1} {2} icin bekle\r\n1082=Yukleniyor: '{0}'...\r\n1083=> Makroyu durdur\r\n1084=Oynat: {0}\r\n1085=Makro aktif '{0}'...\r\n1086=Makro '{0}' bitti.\r\n1087=Razor was unable to initialize.  Error code:\\n\r\n1088=Description: Could not find the client Window Handle.\\nPossible Cause: The Client may not have initialized properly.\r\n1089=Description: Could not find the Client's ThreadID\\nPossible Cause: The Client may not have initialized Properly.\r\n1090=Description: Could not create Windows Hooks.\\nPossible Cause: Internal error.\r\n1091=Description: Could not create or access Razor shared memory.\\nPossible Cause: Windows Error or invalid permissions.\r\n1092=Description: Crypt.dll has disabled itself.\\nPossible Cause: Version mismatch.\r\n1093=Description: Could not patch the client's Winsock functions.\\nPossible Cause: Internal error, Windows Error, or Incompatible Version.\r\n1094=\r\n1095=Warning: Could not copy packet lengths and/or encryption information from the client.\\nRazor may be able to run without this information, though some features may not function correctly.  Would you like to start Razor anyway?\\n\\nPossible Cause: Your client version may not be compatible with this version of Razor.\r\n1096={0} skillin {4}{5:F1} degisti, simdi {3:F1} ({1}{2:F1}) oldu.\r\n1097=Invalid abbreviation.\r\n1098=Gecersiz itemid.\r\n1099=Gecersiz renk.\r\n1100=Sayacagim nesneyi secin.\r\n1101=Error loading '{0}'!\\nThis profile is corrupt and cannot be used.\r\n1102={0} ozelligi bu profilde bulunamadi.\r\n1103=counters.xml dosyaniz hasar gormus kullanilamiyor\r\n1104=Because you have Auto Search Containers off, you must now reopen all of your bags so that your counters can be updated.\r\n1105=Dikkat: {0} nesnesinden sadece {1} tane kaldi!\r\n1106=Kullanmak istedigin rengi sec.\r\n1107=Simdi SS al\r\n\r\n1109=Razor Version: {0}\\nMemory Used: {1}\\nSend: {2} ({3}/s)\\nRecv: {4} ({5}/s)\\nConnected for {6}\\n\\nPlayer Serial: 0x{7:X8}\\nBackpack Serial: 0x{8:X8}\\n\\nTracking Items: {9}\\nTracking Mobs: {10}\\nTurkce ceviri :\\nMystraworld ATi (Y&&Y) waptir.com\r\n1110=Set Lock: Yukari\r\n1111=Set Lock: Asagi\r\n1112=Set Lock: Kilitli\r\n1113=\"{0}\" sayacini silmek istediginize eminmisiniz?\\nButun profillerde silinecektir.\r\n1114=\"{0}\" profilini simdi yukleyimmi?\r\n1115=Profili yuklerken hata olustu\r\n1116=Varsayilan profili kolay kolay silemezsiniz :)\r\n1117=Profilinize isim yazin: \r\n1118=Profil olusturulamiyor!\\n Cunku bu isimden bidene daha var.\\n\\nSimdi bu eski profili yukliyimmi?\r\n1119=Yeni elbise listesi icin isim girin:\r\n1120=Bu elbise listesini silmek istediginize eminmisiniz?\r\n1121={0:X} (Item out of Range)\r\n1122=Bu nesneyi listeden silmek istediginize eminmisiniz?\r\n1123='{0}' listesindeki itemleri bosaltmak icin bir kutu/poset secin.\r\n1124=Cikarma poseti ayarlandi.\r\n1125=Nesne bulunamiyor yada sizde bir dandiklik var.\r\n1126=That key combination already belongs to '{0}'.\\nChange it to '{1}'?\r\n1127=Veri basariyla kaydedildi.\r\n1128=Warning!\\nLogging packets may reduce Razor's performance. Log files can also\\neasily grow very large, and Razor will not automatically remove them.\\n\\nRazor's packet log files may contain personal information such as\\npasswords, and should be not be given to people you do not trust.\\n\\nAre you sure you want to enable packet logging?\\n(This will not be saved in your user profile)\r\n1129=Secileni bu tipe cevir\r\n1130=Yeni makroya bi isim girin: \r\n1131=Bu isim olmaz kiytirik karakterler iceriyor.\r\n1132=Bu isimde bir makro zati var.\r\n1133=Kaydedilmeden once eski kayitli makro silinecek.\\nKaydetmek istediginize eminmisiniz?\r\n1134='{0}' silmeyi gercekten istiyormusunuz?\\n(Geri donusu yok ona gore)\r\n1135=Bekle/Durma ekle..\r\n1136=Son hedefi secme ekle..\r\n1137=Yukari tasi\r\n1138=Asagi tasi\r\n1139=Bunu sil\r\n1140=Burdan kaydetmeye basla\r\n1141='{0}' dosyasi bulunamadi.\r\n1142=Eminmisin?\r\n1143=WARNING: The following {0} file{1} count not be deleted:\\n{2}\r\n1144=Razoru yeniden baslatinca bu secenek aktif olacaktir\r\n1145=Bu secenegi secerek parolalarinizi profilinizin bir parcasi olarak saklayacaksiniz..\\nEger birileri sizin profilinizin xml dosyasini bulursa ozaman yandiniz.\\nBunu halen aktif etmek istiyormusunuz?\r\n1146=Lutfen doru durust port girin adami ayar etmeyin.\r\n1147=Ignoring action request (already queued).\r\n1148=Queuing action request {0}... {1} left.\r\n1149={0} siralanmis olay {1:F1} saniyede bitti.\r\n1150=Use Once Agent\r\n1151=Ekle (Target)...\r\n1152=Kutu Ekle (Target)...\r\n1153=Sil (Target)...\r\n1154=Listeyi sil\r\n1155=Eklemek icin bir nesne secin\r\n1156=Bir utu secin.\r\n1157=Silmek icin bir nesne secin.\r\n1158=Nesne Eklendi.\r\n1159=Nesne Silindi.\r\n1160={0} nesne Use Once agent a eklendi.\r\n1161=Useonce sirasi bos.\r\n1162=Using '{0}'.  ({1} item(s) left in the UseOnce queue)\r\n1163=There was a problem with one of your UseOnce items, trying the next one.\r\n1164=SellAgent: Sizin yerinize {0} nesneyi {1}gp satti.\r\n1165=Sil\r\n1166=Kutu basariyla ayarlandi.\r\n1167=Bosalt\r\n1168=(Kapatmak icin tikla)\r\n1169=(Acmak icin tikla)\r\n1170=Poseti ayarla\r\n1171=Poseti iptalet\r\n1172=Organizer Agent\r\n1173=Toplayici\r\n1174=Simdi topla\r\n1175=Kutu ayarli degil.\r\n1176=Razor cebinizi bulamadi.\r\n1177=Toplayici {0} tane nesneyi tasiyacak bu azcik zaman alabilir.\r\n1178=Toplayici hicbir tasinacak nesne bulamadi\r\n1179=Bu nesne zaten listede.\r\n1180=AutoSearchExemptions\r\n1181={0} nesne sizin yerinize {1}gp ye satin alindi.\r\n1182=Satin alma agenti paraniz olmadigindan yada yetmediginden satin alamadi.\r\n1183=Miktar girin:\r\n1184=Istemci calisma seviyesi {0} e getirildi\r\n1185=Suanki zaman: {0}\r\n1186=You are at {0} in '{1}'\r\n1187=Cikarma poseti bulunamadi yada cok uzak, onun yerine cebinize cikardim.\r\n1188={0} nesne cikarilacak.\r\n1189={0} nesne giyilmek icin siraya kondu.\r\n1190={0} nesne zaten giyilmis.\r\n1191={0} nesne bulunamadi yada menzil disi\r\n1192=Uyari : buyu ozelligi bulunamadi buyu yazisi gorunmeyecek\r\n1193=Gizli adim: {0}\r\n1194=Suan gizli adimlariniz sayilmaya baslandi.\r\n1195=Hedef sirasini bosalt\r\n1196=Son dusmana saldir\r\n1197=Hedef sirasi bosaltildi.\r\n1198=Yeni bir 'Son hedef' secin\r\n1199=Son Hedef ayarlandi.\r\n1200=Yeni hedef ayarlandi.\r\n1201=Bu nitelige uygun biri ekranda yok.\r\n1202=Kendine hedef alma siraya kondu.\r\n1203=Son hedef siraya kondu.\r\n1204=Sunucu yeni bir hedef belirledi, razorunki iptal oldu.\r\n1205={0} tipine gore hedefle\r\n1206=Copcu\r\n1207=Bunu silmek istediginize eminmisiniz?\r\n1208=Razorun SS lerini saklamak icin bir klasor secin.\r\n1209=Tuslar\r\n1210=Nesneler\r\n1211=Hedefler\r\n1212=Agentlar\r\n1213=Giyinme\r\n1214=Makrolar\r\n1215=Buyuler\r\n1216=Skiller\r\n1217=Digerleri\r\n1251=1st\r\n1252=2nd\r\n1253=3rd\r\n1254=4th\r\n1255=5th\r\n1256=6th\r\n1257=7th\r\n1258=8th\r\n1260=Necromancy\r\n1270=Chivalry\r\n1271=Potions\r\n1272=Special Moves\r\n1290=Bushido\r\n1300=Ninjitsu\r\n1301=Sat\r\n1302=Satinal\r\n1303=Input Required\r\n1304=Razor komutlari listesi\r\n1305=Elindeki itemi kullan\r\n1306=Bisiyi elinden dusurmeden once eline alman gerek.\r\n1307=Sag eline silah Al/Birak\r\n1308=Sol eline silah Al/Birak\r\n1309=Suan elinde tuttugunu dusur\r\n\r\n1311=>Razor tuslarini kullanima Ac/Kapat\r\n1312=Tuslar acik {0} a tikla kapat\r\n1313=Tuslar kapali {0} a tikla ac\r\n1314=Razor tuslari acildi\r\n1315=Razor tuslari kapatildi\r\n1316=Yuru: {0}\r\n1317=Tip ekle (Target)...\r\n1318=Istenen hedef bulunamadi, son hedefi calistiramadim!\r\n1319=En fazla {0} tane sat\r\n1320=Snooping Mesajlari\r\n1321=Cep sesleri\r\n1322=\"If/Eger\" ekle\r\n1323=\"Else/Degilse\" ekle\r\n1324=\"End If/Egeri bitir\" ekle\r\n1325=Miktar ayarla\r\n1326=Doldur\r\n1327=Simdi Doldur\r\n1328=Doldurma Agenti\r\n1329=Doldurmak icin kullanilacak kutuyu gosterin yada kendinize tiklayin bankanizdan doldurayim.\r\n1330=Bu kutu yanlis.\r\n1331={0} nesnenin doldurmasi tamamlandi{1}.\r\n1332=Simdiki hedefi iptal et\r\n1333=Yeni razor srm cikmis yuklemek icin web sitesini ziyaret etmek istermisin?\r\n1334=Yenile\r\n1335=Kaydet\r\n1336=Uyari: Suanki hedef yeri secmenizi desteklemiyor, son hedef calistirilamadi.\r\n1337=Istemciyi senkronize et\r\n1338=Binekten inme engellendi.\r\n1339=PacketVideo kaydetmeye basladi\r\n1340=\"PacketVideo\" kayit/tekrari durdur\r\n1341=Kayda baslarken hata olustu.\r\n1342=Bu dosya razorun bu surumu ile uygun degil en son surum razor kullandiginize emin olun.\r\n1343=Bu video dosyasi bozulmus, belki yarim kalmis olabilir, dosya oynatilamadi.\r\n1344=Dosyayi okurken problemle karsilasildi, dosya hasar gormus olabilir.\r\n1345=Kategori ismi gir:\r\n1346=Klasor silinemedi icinin bos olduguna emin olun.\r\n1347=Klasor olusturulamadi dogru isim girdiginize emin olun.\r\n1348=Makro dosyasi tasinamadi kategoriyi dogru girdiginize emin olun.\r\n1349=Arkadaslar\r\n// 1350 to 1359 reserved (max length 15!)\r\n1350=Durduruldu\r\n1351=Bitti\r\n1352=Oyun bittimi?\r\n1353=ker-pwned\r\n1354=girdimi corpor\r\n1355=imamin kayigi..\r\n1356=yattinmi?\r\n1357=Toprai bololsun\r\n1358=Kal Vas yedi\r\n1359=SMACKDOWN\r\n1360=Arkadaslara eklemek icin bir oyuncu sec.\r\n1361=Arkadaslardan silmek icin bir oyuncu sec.\r\n1362=Arkadas eklendi.\r\n1363=Arkadas silindi.\r\n1364=Ozel islemler\r\n1365=\"For Loop/Dongu\" ekle\r\n1366=\"End For/Dongu bitirme\" ekle\r\n1367=Dongu sayisi :\r\n1368=Bellegi temizle\r\n1369=Son buyu\r\n1370=Son skill\r\n1371=Son nesne\r\n1372=Tum isimler\r\n1373=UseOnce\r\n1374=Herhangi bir dusman insani hedefle\r\n1375=Herhangi bir gri insani hedefle\r\n1376=Herhangi bir mavi insani hedefle\r\n1377=Herhangi bir crim insani hedefle\r\n1378=Herhangi bir crimi hedefle\r\n1379=UYARI: Tasima suresi zamanasimi oldu eldeki item cebe koyuldu.\r\n1380=Bu degisikligin olmasi icin razoru yeniden baslatman gerek\r\n1381=Bu degisikligin olmasi icin serverdan cikip tekrar girmen gerek"
  },
  {
    "path": "etc/Razor.nsi",
    "content": ";--------------------------------\r\n;Include Modern UI\r\n\r\n  !include \"MUI.nsh\"\r\n\r\n;--------------------------------\r\n;General\r\n\r\n  ;Name and file\r\n  Name \"Razor\"\r\n  OutFile \"Razor1013_Inst.exe\"\r\n\r\n  ;Default installation folder\r\n  InstallDir \"$PROGRAMFILES\\Razor\"\r\n  \r\n  ;Get installation folder from registry if available\r\n  InstallDirRegKey HKLM \"Software\\Razor\" \"InstallDir\"\r\n\r\n\r\n;--------------------------------\r\n;Variables\r\n\r\n  Var MUI_TEMP\r\n  Var STARTMENU_FOLDER\r\n\r\n;--------------------------------\r\n;Interface Settings\r\n\r\n  !define MUI_ABORTWARNING\r\n\r\n;--------------------------------\r\n;Pages\r\n\r\n  !insertmacro MUI_PAGE_LICENSE \".\\License.txt\"\r\n  !insertmacro MUI_PAGE_DIRECTORY\r\n  \r\n  ;Start Menu Folder Page Configuration\r\n  !define MUI_STARTMENUPAGE_REGISTRY_ROOT \"HKLM\" \r\n  !define MUI_STARTMENUPAGE_REGISTRY_KEY \"Software\\Razor\" \r\n  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME \"StartMenuFolder\"\r\n  \r\n  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER\r\n\r\n  !insertmacro MUI_PAGE_INSTFILES\r\n  \r\n  !insertmacro MUI_UNPAGE_CONFIRM\r\n  !insertmacro MUI_UNPAGE_INSTFILES\r\n\r\n;--------------------------------\r\n;Languages\r\n \r\n  !insertmacro MUI_LANGUAGE \"English\"\r\n\r\n;--------------------------------\r\n;Installer Sections\r\n\r\nSection \"Razor\" \r\n\r\n  ;Store installation folder\r\n  WriteRegStr HKLM \"Software\\Razor\" \"InstallDir\" $INSTDIR\r\n  WriteRegStr HKLM \"Software\\Razor\" \"UId\" \"0\"\r\n\r\n  ; For tugsoft plugins to function just make sure the tugsoft key exists... put in a dummy value\r\n  WriteRegStr HKCU \"Software\\Tugsoft\\UOAssist\\ThirdParty\" \"Owner\" \"Razor\"\r\n\r\n  WriteRegStr HKCR \".rpv\" \"\" \"Razor.PacketVideo\"\r\n  WriteRegStr HKCR \"Razor.PacketVideo\\DefaultIcon\" \"\" \"$INSTDIR\\RPVOpenStub.exe,0\"\r\n  WriteRegStr HKCR \"Razor.PacketVideo\\shell\\open\\command\" \"\" '\"$INSTDIR\\RPVOpenStub.exe\" %1'\r\n\r\n  CreateDirectory \"$INSTDIR\\Language\"\r\n\r\n  SetOutPath \"$INSTDIR\"\r\n\r\n  WriteUninstaller \"$INSTDIR\\Uninstall.exe\"\r\n\r\n  File \".\\Razor.exe\"\r\n  File \".\\RPVOpenStub.exe\"\r\n  ;File \".\\RPVEditor.exe\"\r\n  File \".\\Updater.exe\"\r\n  File \".\\unrar.dll\"\r\n  File \".\\Crypt.dll\"\r\n  File \".\\Loader.dll\"\r\n  File \".\\Ultima.dll\"\r\n  File \".\\zlib.dll\"\r\n  File \".\\License.txt\"\r\n  File \".\\License_CHS.txt\"\r\n  File \".\\changelog.txt\"\r\n\r\n  File \".\\Newtonsoft.Json.dll\"\r\n\r\n  SetOverwrite ifnewer\r\n  File \".\\Guardlines.def\"\r\n  File \".\\Spells.def\"\r\n  File \".\\Counters.xml\"\r\n  SetOverwrite on\r\n\r\n  Delete \"$INSTDIR\\Crash.log\"\r\n\r\n  SetOutPath \"$INSTDIR\\Language\"\r\n  File \".\\Language\\Razor_lang.*\"\r\n  \r\n  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\r\n    \r\n    ;Create shortcuts\r\n    CreateDirectory \"$SMPROGRAMS\\$STARTMENU_FOLDER\"\r\n    CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\Razor.lnk\" \"$INSTDIR\\Razor.exe\"\r\n    ;CreateShortcut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\RPV Editor (Alpha).lnk\" \"$INSTDIR\\RPVEditor.exe\"\r\n    CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\Visit Razor's Website.lnk\" \"https://github.com/msturgill/razor\"\r\n    CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\Uninstall.lnk\" \"$INSTDIR\\Uninstall.exe\"\r\n    CreateShortcut \"$DESKTOP\\Razor.lnk\" \"$INSTDIR\\Razor.exe\"\r\n  \r\n  !insertmacro MUI_STARTMENU_WRITE_END\r\n\r\nSectionEnd\r\n\r\n;--------------------------------\r\n;Uninstaller Section\r\n\r\nSection \"Uninstall\"\r\n\r\n  DeleteRegKey HKCR \".rpv\"\r\n  DeleteRegKey HKCR \"Razor.PacketVideo\"\r\n  DeleteRegKey HKLM \"Software\\Razor\"\r\n  DeleteRegKey HKCU \"Software\\Razor\"\r\n\r\n  Delete \"$INSTDIR\\Razor.exe\"\r\n  Delete \"$INSTDIR\\RPVOpenStub.exe\"\r\n  ;Delete \"$INSTDIR\\RPVEditor.exe\"\r\n  Delete \"$INSTDIR\\Crypt.dll\"\r\n  Delete \"$INSTDIR\\UOG.dll\"\r\n  Delete \"$INSTDIR\\Loader.dll\"\r\n  Delete \"$INSTDIR\\Ultima.dll\"\r\n  Delete \"$INSTDIR\\zlib.dll\"\r\n  Delete \"$INSTDIR\\Spells.def\"\r\n  Delete \"$INSTDIR\\Uninstall.exe\"\r\n  Delete \"$INSTDIR\\License.txt\"\r\n  Delete \"$INSTDIR\\License_CHS.txt\"\r\n  Delete \"$INSTDIR\\UOReport0.log\"\r\n  Delete \"$INSTDIR\\Crash.log\"\r\n  Delete \"$INSTDIR\\changelog.txt\"\r\n  Delete \"$INSTDIR\\Guardlines.def\"\r\n\r\n  Delete \"$INSTDIR\\Newtonsoft.Json.dll\"\r\n\r\n  RMDir /r \"$INSTDIR\\Language\"\r\n\r\n  MessageBox MB_YESNO|MB_ICONQUESTION \"Do you want to save your razor profiles and macros?  (Selecting no will delete them)\" IDYES AfterProfiles\r\n    Delete \"$INSTDIR\\Counters.xml\"\r\n    RMDir /r \"$INSTDIR\\Profiles\"\r\n    RMDir /r \"$INSTDIR\\Macros\"\r\n\r\nAfterProfiles:\r\n\r\n  MessageBox MB_YESNO|MB_ICONQUESTION \"Do you want to save your screen shots and video captures?  (Selecting no will delete them)\" IDYES AfterSS\r\n    RMDir /r \"$INSTDIR\\ScreenShots\"\r\n    RMDir /r \"$INSTDIR\\Videos\"\r\n\r\nAfterSS:\r\n\r\n  RMDir \"$INSTDIR\"\r\n  \r\n  !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP\r\n    \r\n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Uninstall.lnk\"\r\n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Razor.lnk\"\r\n  ;Delete \"$SMPROGRAMS\\$MUI_TEMP\\RPV Editor (Alpha).lnk\"\r\n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Visit Razor's Website.lnk\"\r\n  Delete \"$DESKTOP\\Razor.lnk\"\r\n  \r\n  ;Delete empty start menu parent diretories\r\n  StrCpy $MUI_TEMP \"$SMPROGRAMS\\$MUI_TEMP\"\r\n \r\n  startMenuDeleteLoop:\r\n    RMDir $MUI_TEMP\r\n    GetFullPathName $MUI_TEMP \"$MUI_TEMP\\..\"\r\n    \r\n    IfErrors startMenuDeleteLoopDone\r\n  \r\n    StrCmp $MUI_TEMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop\r\n  startMenuDeleteLoopDone:\r\n\r\nSectionEnd\r\n"
  },
  {
    "path": "etc/animdata.csv",
    "content": "abysmal_horror (312),312\nant_lion (787),787\narachnids_spider_black_widow (157),157\narachnids_spider_black_widow2 (173),173\narachnids_spider_dread (11),11\narachnids_spider_dread2 (19),19\narachnids_spider_frost (20),20\narachnids_spider_giant (28),28\narcane_demon (784),784\nBimbobushi (242),242\nbirds_eagle (5),5\nbirds_generic (6),6\nblack_ant_matriarch (808),808\nblack_ant_queen (807),807\nblack_ant_warrior (806),806\nblack_ant_worker (805),805\nbog_thing (780),780\nbogling (779),779\nbonedemon (308),308\nbovines_bull_brown (232),232\nbovines_bull_spotted (233),233\nbovines_cow_brown (216),216\nbovines_cow_spotted (231),231\nbruins_bear_black (211),211\nbruins_bear_brown (167),167\nbruins_bear_grizzly (212),212\nbruins_bear_polar (213),213\ncanines_dog_hound (217),217\ncanines_hell_hound (97),97\ncanines_hell_hound2 (98),98\ncanines_wolf_dark (99),99\ncanines_wolf_dire (23),23\ncanines_wolf_grey (25),25\ncanines_wolf_grey2 (27),27\ncanines_wolf_silver (100),100\ncanines_wolf_timber (225),225\ncanines_wolf_white (34),34\ncanines_wolf_white2 (37),37\ncentaurs_centaur (101),101\nChangling (264),264\nchaos_demon (792),792\ncharacter_blackthorn (991),991\ncharacter_dupre (994),994\ncharacter_lord_british (990),990\nchariot (786),786\nclockwork_minion (757),757\nclockwork_minion2 (763),763\nclockwork_overseer (756),756\nCrane (254),254\nCrow (283),283\ncrystal_elemental (300),300\nCuShidhe (277),277\ncyclops_cyclops (75),75\ndaemons_daemon (9),9\ndaemons_daemon_black_gate (38),38\ndaemons_daemon_elder (40),40\ndaemons_daemon_exodus (102),102\ndaemons_daemon_ice_fiend (43),43\ndaemons_daemon2 (10),10\nDarknight_Creeper (313),313\nDawn_Girl (774),774\ndeer_doe (237),237\ndeer_stag (234),234\ndemon_knight (318),318\nDenkou_Yajuu (196),196\ndevourer (303),303\ndolphins_dolphin (151),151\ndoppleganger (777),777\ndragons_dragon_asian (103),103\ndragons_dragon_retro_grey (12),12\ndragons_dragon_retro_grey2 (60),60\ndragons_dragon_retro_red (59),59\ndragons_dragon_retro_red2 (61),61\ndragons_dragon_retro_red3 (172),172\ndragons_dragon_skeletal (104),104\ndragons_wyrm_ancient (105),105\ndragons_wyrm_retro_white (49),49\ndragons_wyrm_retro_white2 (180),180\ndragons_wyrm_shadow (106),106\ndragons_wyvern (62),62\nDreadHorn (257),257\nDryad (266),266\nelementals_acid_elemental (158),158\nelementals_agapite_elemental (107),107\nelementals_air_elemental (13),13\nelementals_blood_elemental (159),159\nelementals_blood_elemental2 (160),160\nelementals_bronze_elemental (108),108\nelementals_copper_dull_elemental (110),110\nelementals_copper_elemental (109),109\nelementals_earth_elemental (14),14\nelementals_fire_elemental (15),15\nelementals_gold_elemental (166),166\nelementals_ice_elemental (161),161\nelementals_iron_elemental (111),111\nelementals_poison_elemental (162),162\nelementals_snow_elemental (163),163\nelementals_valorite_elemental (112),112\nelementals_verite_elemental (113),113\nelementals_water_elemental (16),16\nequines_horse_dappled_brown (200),200\nequines_horse_dappled_brown_pack (291),291\nequines_horse_dappled_grey (226),226\nequines_horse_dark_brown (204),204\nequines_horse_dark_steed (114),114\nequines_horse_ethereal (115),115\nequines_horse_firesteed (190),190\nequines_horse_nightmare (116),116\nequines_horse_nightmare2 (177),177\nequines_horse_nightmare3 (178),178\nequines_horse_nightmare4 (179),179\nequines_horse_silver_steed (117),117\nequines_horse_tan (228),228\nequines_horse_war_brittanian (118),118\nequines_horse_war_mage_council (119),119\nequines_horse_war_minax (120),120\nequines_horse_war_shadowlord (121),121\nequines_unicorn (122),122\nequines_unicorn_ethereal (192),192\nethereal_warriors_male (123),123\nethereal_warriors_male2 (175),175\nethereals_energy_vortex (164),164\nethereals_wisp (58),58\nethereals_wisp2 (165),165\nettins_ettin (2),2\nettins_ettin2 (18),18\nFan_Dancer (247),247\nfelines_cougar (63),63\nfelines_housecat (201),201\nfelines_leopard_snow (64),64\nfelines_leopard_snow2 (65),65\nfelines_panther (214),214\nfelines_predator_hellcat (127),127\nFerret (279),279\nFetid_Essence (273),273\nfey_race_pixie (128),128\nfey_race_pixie2 (176),176\nfire_ant_matriarch (804),804\nfire_ant_queen (783),783\nfire_ant_warrior (782),782\nfire_ant_worker (781),781\nflails_corpser (8),8\nflails_reaper (47),47\nflails_swamp_tentacles (66),66\nflails_swamp_tentacles2 (129),129\nflesh_golem (304),304\nflesh_renderer (315),315\nfour_armed_demon (746),746\nfour_armed_demon2 (785),785\nfowl_normal_hen (208),208\nfrogs_bullfrog (81),81\nfrogs_frog_giant (80),80\ngargoyles_gargoyle (4),4\ngargoyles_gargoyle_blistering (130),130\ngargoyles_gargoyle_enforcer (754),754\ngargoyles_gargoyle_guard (755),755\ngargoyles_gargoyle_shopkeeper (758),758\ngargoyles_gargoyle_slave (753),753\ngargoyles_gargoyle_stone (67),67\ngazers_gazer (22),22\ngazers_gazer_elder (68),68\ngazers_gazer_elder2 (69),69\ngenies_efreet (131),131\ngiant_beetle (791),791\ngiant_beetle_ethereal (195),195\nGiant_Beetle_Fire (169),169\ngibberling (307),307\ngolem_iron (752),752\ngore_fiend (305),305\ngorillas_silverback (29),29\nGouzen_Ha (199),199\nh_female (401),401\nh_female1 (606),606\nh_female3 (745),745\nh_male (400),400\nh_male1 (605),605\nh_male3 (744),744\nH_Savage_Female (184),184\nh_savage_female (751),751\nH_Savage_Female2 (186),186\nH_Savage_Male (183),183\nh_savage_male (750),750\nH_SavageRider_Male (185),185\nHai_Riyo (243),243\nharpies_harpy (30),30\nharpies_harpy_stone (73),73\nheadless_headless (31),31\nhorde_demon (776),776\nhorde_demon2 (795),795\nhorde_demon3 (796),796\nHydra (265),265\nimpaler (306),306\nimps_imp (74),74\nimps_shadow_fiend (168),168\nJuggernaut (768),768\nJuka_Mage (765),765\nJuka_Warrior (764),764\nKappa (240),240\nkirin_kirin (132),132\nkirin_kirin_ethereal (191),191\nKitsun_Tsuki (246),246\nkrakens_kraken (77),77\nLady_of_the_Snow (252),252\nLadyMelisande (258),258\nLeatherMinotaur (281),281\nliche_liche_lord_retro (78),78\nliche_liche_lord_retro2 (79),79\nliche_liche_lord_retro3 (82),82\nliche_liche_retro (24),24\nliche_liche_retro3 (749),749\nlizard_race_lizardman (33),33\nlizard_race_lizardman2 (35),35\nlizard_race_lizardman3 (36),36\nlizards_alligator_brown (202),202\nlizards_alligator_small (133),133\nlizards_komodo_dragon (134),134\nlizards_lava_lizard (206),206\nllamas_llama (220),220\nllamas_llama_ethereal (170),170\nllamas_llama_pack (292),292\nmages_evil_mage (124),124\nmages_evil_mage_master (125),125\nmages_evil_mage_master2 (126),126\nMeer_Mage (770),770\nMeer_Warrior (771),771\nmf_dragon_fire (797),797\nMf_Dragon_Rust (46),46\nmf_dragon_rust (798),798\nMinotaur (263),263\nMinotaurArmored (280),280\nMondainSteed01 (284),284\nmongbats_mongbat (39),39\nMonstrousInterredGrizzle (259),259\nMonstrousInterredGrizzle2 (272),272\nmound_of_maggots (319),319\nMulti Colored Horde Deamon (999),999\nNPC_Adranath (772),772\nNPC_Blackthorn (769),769\nNPC_Blackthorn_Cohort (767),767\nNPC_Cpt_Dasha (773),773\nNPC_Kabur (766),766\nogres_ogre (1),1\nogres_ogre_lord (83),83\nogres_ogre_lord_arctic (135),135\nogres_ogre_lord2 (84),84\nOni (241),241\nophidians_ophidian_archmage (136),136\nophidians_ophidian_knight (137),137\nophidians_ophidian_mage (85),85\nophidians_ophidian_queen (87),87\nophidians_ophidian_warrior (86),86\norcs_orc (17),17\norcs_orc_bomber (182),182\norcs_orc_captain (7),7\norcs_orc_lord (138),138\norcs_orc_lord2 (139),139\norcs_orc_lord3 (189),189\norcs_orc_scout (181),181\norcs_orc_shaman (140),140\norcs_orc2 (41),41\nostards_ostard_desert (210),210\nostards_ostard_ethereal (171),171\nostards_ostard_forest (218),218\nostards_ostard_frenzied (219),219\npaladins_paladin (141),141\nParoxysmus (256),256\nParrot (282),282\npatchskeleton (309),309\nplague_beast (775),775\nplayer_ghost5 (970),970\nporcines_boar (290),290\nporcines_pig (203),203\nquagmire (789),789\nRaptalon (276),276\nrat_race_ratman (42),42\nrat_race_ratman2 (44),44\nrat_race_ratman3 (45),45\nrat_race_ratman4 (142),142\nrat_race_shaman (143),143\nravager (314),314\nReaperForm (285),285\nridgeback_ridgeback (187),187\nridgeback_ridgeback_ethereal (193),193\nridgeback_savage (188),188\nrodents_rabbit_cottontail (205),205\nrodents_rat_giant (215),215\nrodents_rat_sewer (238),238\nruminants_goat_billy (209),209\nruminants_goat_mountain (88),88\nruminants_sheep (207),207\nruminants_sheep_shorn (223),223\nRune_Beetle (244),244\nsand_vortex (790),790\nSatyr (271),271\nscorpions_giant (48),48\nsea_horse_sea_horse (144),144\nsea_serpents_sea_serpent (145),145\nsea_serpents_sea_serpent2 (150),150\nserpents_snake (52),52\nserpents_snake_giant (21),21\nserpents_snake_giant_ice (89),89\nserpents_snake_giant_lava (90),90\nserpents_snake_giant_silver (91),91\nserpents_snake_giant_silver2 (92),92\nserpents_snake_giant_silver3 (93),93\nshadow_knight (311),311\nshadowlords_shadowlord (146),146\nShimmering_Effusion (261),261\nskeletal_mount (793),793\nskeletons_skeleton (50),50\nskeletons_skeleton_knight (147),147\nskeletons_skeleton_mage (148),148\nskeletons_skeleton2 (56),56\nskeletons_skeleton3 (57),57\nskittering_hopper (302),302\nslimes_slime (51),51\nslimes_slime_frost (94),94\nslimes_slime_frost2 (96),96\nsphinx (788),788\nspirits_blade_spirit (574),574\nspirits_ghost (26),26\nspirits_ghost2 (748),748\nSquirrel (278),278\nsuccubi_succubus (149),149\nsuccubi_succubus2 (174),174\nswamp_dragon (794),794\nswamp_dragon_armor (799),799\nswamp_dragon_ethereal (194),194\nswarm (778),778\nterathan_terathan_avenger (152),152\nterathan_terathan_drone (71),71\nterathan_terathan_queen (72),72\nterathan_terathan_warrior (70),70\ntitans_titan (76),76\nTormentedMinotaur (262),262\ntreefellow (301),301\nTri_Wolf (250),250\nTroglodyte (267),267\ntrolls_troll (53),53\ntrolls_troll_frost (55),55\ntrolls_troll2 (54),54\nvampire_bat (317),317\nVampyric_Beast (251),251\nwailingbanshee (310),310\nwailingbanshee2 (747),747\nwalking_dead_ghoul (153),153\nwalking_dead_mummy (154),154\nwalking_dead_rotting_corpse (155),155\nwalking_dead_zombie (3),3\nwalrus_walrus_male (221),221\nwander (316),316\nWild_Guar (248),248\nYamandon (249),249\nYomotsu_Elder (255),255\nYomotsu_Priest (253),253\nYomotsu_Warrior (245),245\n"
  },
  {
    "path": "etc/counters.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\r\n<counters>\r\n\t<counter>\r\n\t\t<name>Bandages</name>\r\n\t\t<format>aids</format>\r\n\t\t<itemid>3617</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Black Pearl</name>\r\n\t\t<format>bp</format>\r\n\t\t<itemid>3962</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Blood Moss</name>\r\n\t\t<format>bm</format>\r\n\t\t<itemid>3963</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Cure Potions</name>\r\n\t\t<format>cure</format>\r\n\t\t<itemid>3847</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Garlic</name>\r\n\t\t<format>gl</format>\r\n\t\t<itemid>3972</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Ginseng</name>\r\n\t\t<format>gs</format>\r\n\t\t<itemid>3973</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Heal Potions</name>\r\n\t\t<format>heal</format>\r\n\t\t<itemid>3852</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Mandrake Root</name>\r\n\t\t<format>mr</format>\r\n\t\t<itemid>3974</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Nightshade</name>\r\n\t\t<format>ns</format>\r\n\t\t<itemid>3976</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Spider's Silk</name>\r\n\t\t<format>ss</format>\r\n\t\t<itemid>3981</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Sulfurous Ash</name>\r\n\t\t<format>sa</format>\r\n\t\t<itemid>3980</itemid>\r\n\t\t<hue>0</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Arrows</name>\r\n\t\t<format>arw</format>\r\n\t\t<itemid>3903</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Bolts</name>\r\n\t\t<format>blt</format>\r\n\t\t<itemid>7163</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Platinum</name>\r\n\t\t<format>plat</format>\r\n\t\t<itemid>3821</itemid>\r\n\t\t<hue>1154</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Folded Cloth</name>\r\n\t\t<format>fcloth</format>\r\n\t\t<itemid>5990</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Cloth Bolts</name>\r\n\t\t<format>bcloth</format>\r\n\t\t<itemid>3989</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Logs</name>\r\n\t\t<format>logs</format>\r\n\t\t<itemid>7133</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Thread</name>\r\n\t\t<format>thread</format>\r\n\t\t<itemid>4000</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Yarn</name>\r\n\t\t<format>yarn</format>\r\n\t\t<itemid>3613</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Sewing Kit</name>\r\n\t\t<format>sewing</format>\r\n\t\t<itemid>3997</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Cotton Bale</name>\r\n\t\t<format>bale</format>\r\n\t\t<itemid>3577</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Lockpicks</name>\r\n\t\t<format>lp</format>\r\n\t\t<itemid>5372</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Explosion Potions</name>\r\n\t\t<format>explo</format>\r\n\t\t<itemid>3853</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Agility Potions</name>\r\n\t\t<format>agility</format>\r\n\t\t<itemid>3848</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Total Refresh Potion</name>\r\n\t\t<format>refresh</format>\r\n\t\t<itemid>3851</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n\t<counter>\r\n\t\t<name>Strength Potion</name>\r\n\t\t<format>strength</format>\r\n\t\t<itemid>3849</itemid>\r\n\t\t<hue>-1</hue>\r\n\t</counter>\r\n</counters>"
  },
  {
    "path": "etc/doors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Doors>\n    <Category name=\"Doors\">\n        <Door name=\"Barred Metal 1\" base=\"1669\" item=\"BarredMetalDoor\"></Door>\n        <Door name=\"Barred Metal 2\" base=\"8173\" item=\"BarredMetalDoor2\"></Door>\n        <Door name=\"Dark Wood\" base=\"1701\" item=\"DarkWoodDoor\"></Door>\n        <Door name=\"Light Wood\" base=\"1749\" item=\"LightWoodDoor\"></Door>\n        <Door name=\"Medium Wood\" base=\"1717\" item=\"MediumWoodDoor\"></Door>\n        <Door name=\"Metal 1\" base=\"1653\" item=\"MetalDoor\"></Door>\n        <Door name=\"Metal 2\" base=\"1733\" item=\"MetalDoor2\"></Door>\n        <Door name=\"Rattan\" base=\"1685\" item=\"RattanDoor\"></Door>\n        <Door name=\"Strong Wood\" base=\"1765\" item=\"StrongWoodDoor\"></Door>\n    </Category>\n    <Category name=\"House Doors\">\n        <Door name=\"Dark Wood\" base=\"1701\" item=\"DarkWoodHouseDoor\"></Door>\n        <Door name=\"Metal\" base=\"1653\" item=\"MetalHouseDoor\"></Door>\n    </Category>\n    <Category name=\"Gates\">\n        <Door name=\"Dark Wood\" base=\"2150\" item=\"DarkWoodGate\"></Door>\n        <Door name=\"Iron\" base=\"2084\" item=\"IronGate\"></Door>\n        <Door name=\"Iron Short\" base=\"2124\" item=\"IronGateShort\"></Door>\n        <Door name=\"Light Wood\" base=\"2105\" item=\"LightWoodGate\"></Door>\n    </Category>\n    <Category name=\"Portcullis\" EW=\"1782\" NS=\"1781\" itemEW=\"PortcullisEW\" itemNS=\"PortcullisNS\"></Category>\n    <Category name=\"Secret Doors\">\n        <Door name=\"Dungeon\" base=\"788\" item=\"SecretDungeonDoor\"></Door>\n        <Door name=\"Light Wood\" base=\"836\" item=\"SecretLightWoodDoor\"></Door>\n        <Door name=\"Stone 1\" base=\"232\" item=\"SecretStoneDoor1\"></Door>\n        <Door name=\"Stone 2\" base=\"804\" item=\"SecretStoneDoor2\"></Door>\n        <Door name=\"Stone 3\" base=\"852\" item=\"SecretStoneDoor3\"></Door>\n        <Door name=\"Wooden\" base=\"820\" item=\"SecretWoodenDoor\"></Door>\n    </Category>\n    <Category name=\"Phantasya Custom\">\n        <Door name=\"Self Locking Door\" base=\"1701\" item=\"SelfLockingDoor\"></Door>\n    </Category>\n</Doors>"
  },
  {
    "path": "etc/dotNet.nsh",
    "content": "# DotNET version checking macro.\r\n# Written by AnarkiNet(AnarkiNet@gmail.com) originally, modified by eyal0 (for use in http://www.sourceforge.net/projects/itwister)\r\n# Downloads and runs the Microsoft .NET Framework version 2.0 Redistributable and runs it if the user does not have the correct version.\r\n# To use, call the macro with a string:\r\n# !insertmacro CheckDotNET \"2\"\r\n# !insertmacro CheckDotNET \"2.0.9\"\r\n# (Version 2.0.9 is less than version 2.0.10.)\r\n# All register variables are saved and restored by CheckDotNet\r\n# No output\r\n \r\n!macro CheckDotNET DotNetReqVer\r\n  !define DOTNET_URL \"http://www.microsoft.com/downloads/info.aspx?na=90&p=&SrcDisplayLang=en&SrcCategoryId=&SrcFamilyId=0856eacb-4362-4b0d-8edd-aab15c5e04f5&u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2f5%2f6%2f7%2f567758a3-759e-473e-bf8f-52154438565a%2fdotnetfx.exe\"\r\n  DetailPrint \"Checking your .NET Framework version...\"\r\n  ;callee register save\r\n  Push $0\r\n  Push $1\r\n  Push $2\r\n  Push $3\r\n  Push $4\r\n  Push $5\r\n  Push $6 ;backup of intsalled ver\r\n  Push $7 ;backup of DoNetReqVer\r\n \r\n  StrCpy $7 ${DotNetReqVer}\r\n \r\n  System::Call \"mscoree::GetCORVersion(w .r0, i ${NSIS_MAX_STRLEN}, *i r2r2) i .r1 ?u\"\r\n \r\n  ${If} $0 == 0\r\n  \tDetailPrint \".NET Framework not found, download is required for program to run.\"\r\n    Goto NoDotNET\r\n  ${EndIf}\r\n \r\n  ;at this point, $0 has maybe v2.345.678.\r\n  StrCpy $0 $0 $2 1 ;remove the starting \"v\", $0 has the installed version num as a string\r\n  StrCpy $6 $0\r\n  StrCpy $1 $7 ;$1 has the requested verison num as a string\r\n \r\n  ;MessageBox MB_OKCANCEL \"found $0\" IDCANCEL GiveUpDotNET\r\n \r\n  ;MessageBox MB_OKCANCEL \"looking for $1\" IDCANCEL GiveUpDotNET\r\n \r\n  ;now let's compare the versions, installed against required <part0>.<part1>.<part2>.\r\n  ${Do}\r\n    StrCpy $2 \"\" ;clear out the installed part\r\n    StrCpy $3 \"\" ;clear out the required part\r\n \r\n    ${Do}\r\n      ${If} $0 == \"\" ;if there are no more characters in the version\r\n        StrCpy $4 \".\" ;fake the end of the version string\r\n      ${Else}\r\n        StrCpy $4 $0 1 0 ;$4 = character from the installed ver\r\n        ${If} $4 != \".\"\r\n          StrCpy $0 $0 ${NSIS_MAX_STRLEN} 1 ;remove that first character from the remaining\r\n        ${EndIf}\r\n      ${EndIf}\r\n \r\n      ${If} $1 == \"\"  ;if there are no more characters in the version\r\n        StrCpy $5 \".\" ;fake the end of the version string\r\n      ${Else}\r\n        StrCpy $5 $1 1 0 ;$5 = character from the required ver\r\n        ${If} $5 != \".\"\r\n          StrCpy $1 $1 ${NSIS_MAX_STRLEN} 1 ;remove that first character from the remaining\r\n        ${EndIf}\r\n      ${EndIf}\r\n      ;MessageBox MB_OKCANCEL \"installed $2,$4,$0 required $3,$5,$1\" IDCANCEL GiveUpDotNET\r\n      ${If} $4 == \".\"\r\n      ${AndIf} $5 == \".\"\r\n        ${ExitDo} ;we're at the end of the part\r\n      ${EndIf}\r\n \r\n      ${If} $4 == \".\" ;if we're at the end of the current installed part\r\n        StrCpy $2 \"0$2\" ;put a zero on the front\r\n      ${Else} ;we have another character\r\n        StrCpy $2 \"$2$4\" ;put the next character on the back\r\n      ${EndIf}\r\n      ${If} $5 == \".\" ;if we're at the end of the current required part\r\n        StrCpy $3 \"0$3\" ;put a zero on the front\r\n      ${Else} ;we have another character\r\n        StrCpy $3 \"$3$5\" ;put the next character on the back\r\n      ${EndIf}\r\n    ${Loop}\r\n    ;MessageBox MB_OKCANCEL \"finished parts: installed $2,$4,$0 required $3,$5,$1\" IDCANCEL GiveUpDotNET\r\n \r\n    ${If} $0 != \"\" ;let's remove the leading period on installed part if it exists\r\n      StrCpy $0 $0 ${NSIS_MAX_STRLEN} 1\r\n    ${EndIf}\r\n    ${If} $1 != \"\" ;let's remove the leading period on required part if it exists\r\n      StrCpy $1 $1 ${NSIS_MAX_STRLEN} 1\r\n    ${EndIf}\r\n \r\n    ;$2 has the installed part, $3 has the required part\r\n    ${If} $2 S< $3\r\n      IntOp $0 0 - 1 ;$0 = -1, installed less than required\r\n      ${ExitDo}\r\n    ${ElseIf} $2 S> $3\r\n      IntOp $0 0 + 1 ;$0 = 1, installed greater than required\r\n      ${ExitDo}\r\n    ${ElseIf} $2 == \"\"\r\n    ${AndIf} $3 == \"\"\r\n      IntOp $0 0 + 0 ;$0 = 0, the versions are identical\r\n      ${ExitDo}\r\n    ${EndIf} ;otherwise we just keep looping through the parts\r\n  ${Loop}\r\n \r\n  ${If} $0 < 0\r\n    DetailPrint \".NET Framework Version found: $6, but is older than the required version: $7\"\r\n    Goto OldDotNET\r\n  ${Else}\r\n    DetailPrint \".NET Framework Version found: $6, equal or newer to required version: $7.\"\r\n    Goto NewDotNET\r\n  ${EndIf}\r\n \r\nNoDotNET:\r\n    MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \\\r\n    \".NET Framework not installed.$\\nRequired Version: $7 or greater.$\\nDownload .NET Framework version from www.microsoft.com?\" \\\r\n    /SD IDYES IDYES DownloadDotNET IDNO NewDotNET\r\n    goto GiveUpDotNET ;IDCANCEL\r\nOldDotNET:\r\n    MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \\\r\n    \"Your .NET Framework version: $6.$\\nRequired Version: $7 or greater.$\\nDownload .NET Framework version from www.microsoft.com?\" \\\r\n    /SD IDYES IDYES DownloadDotNET IDNO NewDotNET\r\n    goto GiveUpDotNET ;IDCANCEL\r\n \r\nDownloadDotNET:\r\n  DetailPrint \"Beginning download of latest .NET Framework version.\"\r\n  NSISDL::download ${DOTNET_URL} \"$TEMP\\dotnetfx.exe\"\r\n  DetailPrint \"Completed download.\"\r\n  Pop $0\r\n  ${If} $0 == \"cancel\"\r\n    MessageBox MB_YESNO|MB_ICONEXCLAMATION \\\r\n    \"Download cancelled.  Continue Installation?\" \\\r\n    IDYES NewDotNET IDNO GiveUpDotNET\r\n  ${ElseIf} $0 != \"success\"\r\n    MessageBox MB_YESNO|MB_ICONEXCLAMATION \\\r\n    \"Download failed:$\\n$0$\\n$\\nContinue Installation?\" \\\r\n    IDYES NewDotNET IDNO GiveUpDotNET\r\n  ${EndIf}\r\n  DetailPrint \"Pausing installation while downloaded .NET Framework installer runs.\"\r\n  ExecWait '$TEMP\\dotnetfx.exe /q /c:\"install /q\"'\r\n  DetailPrint \"Completed .NET Framework install/update. Removing .NET Framework installer.\"\r\n  Delete \"$TEMP\\dotnetfx.exe\"\r\n  DetailPrint \".NET Framework installer removed.\"\r\n  goto NewDotNet\r\n \r\nGiveUpDotNET:\r\n  Abort \"Installation cancelled by user.\"\r\n \r\nNewDotNET:\r\n  DetailPrint \"Proceeding with remainder of installation.\"\r\n  Pop $0\r\n  Pop $1\r\n  Pop $2\r\n  Pop $3\r\n  Pop $4\r\n  Pop $5\r\n  Pop $6 ;backup of intsalled ver\r\n  Pop $7 ;backup of DoNetReqVer\r\n!macroend\r\n\r\n; IsDotNETInstalled\r\n;\r\n; Usage:\r\n;   Call IsDotNETInstalled\r\n;   Pop $0\r\n;   StrCmp $0 1 found.NETFramework no.NETFramework\r\nFunction IsDotNETInstalled\r\n  Push $0\r\n  Push $1\r\n  Push $2\r\n  Push $3\r\n  Push $4\r\n \r\n  ReadRegStr $4 HKEY_LOCAL_MACHINE \\\r\n    \"Software\\Microsoft\\.NETFramework\" \"InstallRoot\"\r\n  # remove trailing back slash\r\n  Push $4\r\n  Exch $EXEDIR\r\n  Exch $EXEDIR\r\n  Pop $4\r\n  # if the root directory doesn't exist .NET is not installed\r\n  IfFileExists $4 0 noDotNET\r\n \r\n  StrCpy $0 0\r\n \r\n  EnumStart:\r\n \r\n    EnumRegKey $2 HKEY_LOCAL_MACHINE \\\r\n      \"Software\\Microsoft\\.NETFramework\\Policy\"  $0\r\n    IntOp $0 $0 + 1\r\n    StrCmp $2 \"\" noDotNET\r\n \r\n    StrCpy $1 0\r\n \r\n    EnumPolicy:\r\n \r\n      EnumRegValue $3 HKEY_LOCAL_MACHINE \\\r\n        \"Software\\Microsoft\\.NETFramework\\Policy\\$2\" $1\r\n      IntOp $1 $1 + 1\r\n       StrCmp $3 \"\" EnumStart\r\n        IfFileExists \"$4\\$2.$3\" foundDotNET EnumPolicy\r\n \r\n  noDotNET:\r\n    StrCpy $0 0\r\n    Goto done\r\n \r\n  foundDotNET:\r\n    StrCpy $0 1\r\n \r\n  done:\r\n    Pop $4\r\n    Pop $3\r\n    Pop $2\r\n    Pop $1\r\n    Exch $0\r\nFunctionEnd"
  },
  {
    "path": "etc/guardlines.def",
    "content": "# Papua\r\n5639 3095 192 223 -128 127\r\n5831 3237 20 30 -128 127\r\n\r\n# Delucia\r\n5123 3942 192 122 -128 127\r\n5147 4064 125 20 -128 127\r\n5235 3930 80 12 -128 127\r\n\r\n# Yew\r\n92 656 349 225 -30 39\r\n441 746 216 135 0 39\r\n258 881 399 380 0 39\r\n657 922 42 307 0 39\r\n657 806 17 28 0 39\r\n718 874 38 22 0 39\r\n761 741 19 21 0 39\r\n\r\n# Wind\r\n5132 3 70 55 -128 127\r\n5132 58 81 68 -128 127\r\n5213 98 39 28 -128 127\r\n5197 126 55 78 -128 127\r\n5252 112 42 58 -128 127\r\n5252 170 32 8 -128 127\r\n5252 178 20 5 -128 127\r\n5252 183 10 10 -128 127\r\n5294 19 72 120 -128 127\r\n5279 57 15 55 -128 127\r\n5286 25 8 32 -128 127\r\n\r\n# Jhelom\r\n1303 3670 189 225 -20 127\r\n1338 3895 74 28 -20 127\r\n1383 3951 109 94 -20 127\r\n1494 3767 12 11 -20 127\r\n\r\n# Vesper\r\n2893 598 121 50 -10 127\r\n2816 648 249 365 -10 127\r\n2734 944 82 4 -10 127\r\n2728 948 88 53 -10 127\r\n\r\n# Minoc\r\n2411 366 135 241 -10 127\r\n2548 495 72 55 -10 127\r\n2564 585 3 42 -10 127\r\n2567 585 61 61 -10 127\r\n2499 627 68 63 -10 127\r\n2694 685 15 16 -10 127\r\n\r\n# Serpent's Hold. Get\r\n2868 3324 205 195 0 127\r\n\r\n# Magincia\r\n3653 2046 27 48 0 127\r\n3752 2046 52 48 0 127\r\n3680 2045 72 49 0 127\r\n3652 2094 160 180 -128 127\r\n3649 2256 54 47 -128 127\r\n3554 2132 18 18 -128 127\r\n\r\n# Nujel'm\r\n3475 1000 360 435 0 127\r\n\r\n# Cove\r\n2200 1110 50 50 -10 127\r\n2200 1160 86 86 -10 127\r\n\r\n# Ocllo\r\n3587 2456 119 99 -128 127 F\r\n3706 2460 2 95 -128 127 F\r\n3587 2555 106 73 -128 127 F\r\n3590 2628 103 58 -128 127 F\r\n3693 2555 61 144 -128 127 F\r\n3754 2558 7 141 -128 127 F\r\n3761 2555 7 144 -128 50 F\r\n3695 2699 66 13 -128 127 F\r\n\r\n# Haven\r\n3590 2460 118 226 -10 127 T\r\n3568 2552 22 79 -10 127 T\r\n3708 2558 53 154 -10 127 T\r\n3695 2686 13 26 -10 127 T\r\n3759 2767 10 10 -10 127 T\r\n\r\n# Britain\r\n1416 1498 324 279 -10 127\r\n1500 1408 46 90 0 127\r\n1385 1538 31 239 -10 127\r\n1416 1777 324 60 0 127\r\n1385 1777 31 130 0 127\r\n1093 1538 292 369 0 127\r\n1330 1991 13 13 -10 127\r\n\r\n# Skara Brae\r\n638 2062 12 11 0 127\r\n538 2107 150 190 -10 127\r\n\r\n# Trinsic\r\n1856 2636 75 28 -10 127\r\n1816 2664 283 231 -10 127\r\n2099 2782 18 25 -10 127\r\n1970 2895 47 32 -10 127\r\n1796 2696 20 67 0 127\r\n1800 2796 16 52 0 127\r\n1823 2943 11 11 -128 127\r\n\r\n# Moonglow\r\n4535 844 20 3 0 127\r\n4530 847 31 61 0 127\r\n4521 914 56 49 0 127\r\n4278 915 54 19 0 127\r\n4283 944 53 73 0 127\r\n4377 1015 59 37 -10 127\r\n4367 1050 142 145 0 127\r\n4539 1036 27 18 0 127\r\n4517 1053 23 22 0 127\r\n4389 1198 47 39 0 127\r\n4466 1211 32 25 0 127\r\n4700 1108 17 18 0 127\r\n4656 1127 26 13 0 127\r\n4678 1162 25 25 0 127\r\n4613 1196 23 22 0 127\r\n4646 1212 14 17 0 127\r\n4677 1214 26 22 0 127\r\n4459 1276 16 16 0 127\r\n4622 1316 22 24 0 127\r\n4487 1353 59 21 0 127\r\n4477 1374 69 35 0 127\r\n4659 1387 40 40 0 127\r\n4549 1482 29 27 0 127\r\n4405 1451 23 23 0 127\r\n4483 1468 21 13 0 127\r\n\r\n\r\n#duel\r\n5307 3681 33 26 -127 127 \r\n5158 3436 33 28 -127 127 \r\n5848 3500 27 30 -127 127 \r\n6055 2324 39 24 -127 127 \r\n5757 3658 27 26 -127 127"
  },
  {
    "path": "etc/items.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Items>\n    <Group name=\"Buildings\">\n        <Group name=\"Doors\">\n            <Group name=\"Metal\">\n                <Group name=\"Barred Metal\">\n                    <Item ID=\"0x0685\"/>\n                    <Item ID=\"0x0687\"/>\n                    <Item ID=\"0x068D\"/>\n                    <Item ID=\"0x068F\"/>\n                    <Item ID=\"0x1fed\"/>\n                    <Item ID=\"0x1fee\"/>\n                    <Item ID=\"0x1fef\"/>\n                    <Item ID=\"0x1ff0\"/>\n                </Group>\n                <Group name=\"Solid Metal\">\n                    <Item ID=\"0x0675\"/>\n                    <Item ID=\"0x0677\"/>\n                    <Item ID=\"0x067D\"/>\n                    <Item ID=\"0x067F\"/>\n                </Group>\n            </Group>\n            <Group name=\"Organic\">\n                <Group name=\"Hide\">\n                    <Item ID=\"0x022C\"/>\n                    <Item ID=\"0x022D\"/>\n                    <Item ID=\"0x022E\"/>\n                    <Item ID=\"0x022F\"/>\n                </Group>\n                <Group name=\"Rattan\">\n                    <Item ID=\"0x0695\"/>\n                    <Item ID=\"0x0697\"/>\n                    <Item ID=\"0x069D\"/>\n                    <Item ID=\"0x069F\"/>\n                </Group>\n            </Group>\n            <Group name=\"Secret Doors\">\n                <Item ID=\"0x0319\"/>\n                <Item ID=\"0x0321\"/>\n                <Item ID=\"0x0329\"/>\n                <Item ID=\"0x0331\"/>\n                <Item ID=\"0x0339\"/>\n                <Item ID=\"0x033F\"/>\n                <Item ID=\"0x0349\"/>\n                <Item ID=\"0x034F\"/>\n                <Item ID=\"0x0359\"/>\n                <Item ID=\"0x0363\"/>\n            </Group>\n            <Group name=\"Stone\">\n                <Group name=\"Crystal\">\n                    <Item ID=\"0x35E7\"/>\n                    <Item ID=\"0x367B\"/>\n                    <Item ID=\"0x367D\"/>\n                    <Item ID=\"0x367f\"/>\n                    <Item ID=\"0x3681\"/>\n                    <Item ID=\"0x3683\"/>\n                    <Item ID=\"0x3685\"/>\n                    <Item ID=\"0x3687\"/>\n                    <Item ID=\"0x3689\"/>\n                </Group>\n            </Group>\n            <Group name=\"Wood\">\n                <Group name=\"Floral doors\">\n                    <Item ID=\"0x2D46\"/>\n                    <Item ID=\"0x2D48\"/>\n                    <Item ID=\"0x2D63\"/>\n                    <Item ID=\"0x2D65\"/>\n                    <Item ID=\"0x2D67\"/>\n                    <Item ID=\"0x2D69\"/>\n                    <Item ID=\"0x2D6B\"/>\n                    <Item ID=\"0x2D6D\"/>\n                    <Item ID=\"0x2FE2\"/>\n                    <Item ID=\"0x2FE4\"/>\n                    <Item ID=\"0x2FE4\"/>\n                    <Item ID=\"0x319C\"/>\n                    <Item ID=\"0x319E\"/>\n                    <Item ID=\"0x31A0\"/>\n                    <Item ID=\"0x31A2\"/>\n                    <Item ID=\"0x31A4\"/>\n                    <Item ID=\"0x31A6\"/>\n                    <Item ID=\"0x31A8\"/>\n                    <Item ID=\"0x31AA\"/>\n                    <Item ID=\"0x31AC\"/>\n                    <Item ID=\"0x31AE\"/>\n                </Group>\n                <Group name=\"Gray Wood\">\n                    <Item ID=\"0x3640\"/>\n                    <Item ID=\"0x3642\"/>\n                    <Item ID=\"0x3644\"/>\n                    <Item ID=\"0x3646\"/>\n                    <Item ID=\"0x368B\"/>\n                    <Item ID=\"0x368D\"/>\n                    <Item ID=\"0x368f\"/>\n                    <Item ID=\"0x3691\"/>\n                    <Item ID=\"0x3693\"/>\n                    <Item ID=\"0x3695\"/>\n                    <Item ID=\"0x3697\"/>\n                    <Item ID=\"0x3699\"/>\n                </Group>\n                <Group name=\"Sliding Doors\">\n                    <Item ID=\"0x26F4\"/>\n                    <Item ID=\"0x26F6\"/>\n                    <Item ID=\"0x2990\"/>\n                    <Item ID=\"0x2991\"/>\n                    <Item ID=\"0x299e\"/>\n                    <Item ID=\"0x299f\"/>\n                    <Item ID=\"0x2A05\"/>\n                    <Item ID=\"0x2A05\"/>\n                    <Item ID=\"0x2A05\"/>\n                    <Item ID=\"0x2A09\"/>\n                    <Item ID=\"0x2A0D\"/>\n                    <Item ID=\"0x2A0f\"/>\n                    <Item ID=\"0x2A11\"/>\n                    <Item ID=\"0x2A11\"/>\n                    <Item ID=\"0x2A13\"/>\n                    <Item ID=\"0x2A15\"/>\n                    <Item ID=\"0x2A15\"/>\n                    <Item ID=\"0x2A17\"/>\n                    <Item ID=\"0x2A19\"/>\n                    <Item ID=\"0x2A19\"/>\n                    <Item ID=\"0x2A1b\"/>\n                </Group>\n                <Group name=\"Solid + Metal\">\n                    <Item ID=\"0x06E5\"/>\n                    <Item ID=\"0x06E7\"/>\n                    <Item ID=\"0x06ED\"/>\n                    <Item ID=\"0x06EF\"/>\n                </Group>\n                <Group name=\"Solid Dark\">\n                    <Group name=\"Gate\">\n                        <Item ID=\"0x0866\"/>\n                        <Item ID=\"0x0868\"/>\n                        <Item ID=\"0x086A\"/>\n                        <Item ID=\"0x086C\"/>\n                        <Item ID=\"0x086E\"/>\n                        <Item ID=\"0x0870\"/>\n                        <Item ID=\"0x0872\"/>\n                        <Item ID=\"0x0874\"/>\n                    </Group>\n                    <Item ID=\"0x06A5\"/>\n                    <Item ID=\"0x06A7\"/>\n                    <Item ID=\"0x06AD\"/>\n                    <Item ID=\"0x06AF\"/>\n                </Group>\n                <Group name=\"Solid Light\">\n                    <Group name=\"Gate\">\n                        <Item ID=\"0x0839\"/>\n                        <Item ID=\"0x083A\"/>\n                        <Item ID=\"0x083B\"/>\n                        <Item ID=\"0x083D\"/>\n                        <Item ID=\"0x083E\"/>\n                        <Item ID=\"0x083F\"/>\n                        <Item ID=\"0x0841\"/>\n                        <Item ID=\"0x0843\"/>\n                    </Group>\n                    <Item ID=\"0x06D5\"/>\n                    <Item ID=\"0x06D7\"/>\n                    <Item ID=\"0x06DD\"/>\n                    <Item ID=\"0x06DF\"/>\n                </Group>\n                <Group name=\"Solid Purple\">\n                    <Item ID=\"0x241F\"/>\n                    <Item ID=\"0x2420\"/>\n                    <Item ID=\"0x2421\"/>\n                    <Item ID=\"0x2422\"/>\n                    <Item ID=\"0x2423\"/>\n                    <Item ID=\"0x2424\"/>\n                </Group>\n            </Group>\n        </Group>\n        <Group name=\"Fences\">\n            <Group name=\"Iron Fence and Gate\">\n                <Item ID=\"0x0821\"/>\n                <Item ID=\"0x0822\"/>\n                <Item ID=\"0x0823\"/>\n                <Item ID=\"0x0824\"/>\n                <Item ID=\"0x0826\"/>\n                <Item ID=\"0x0827\"/>\n                <Item ID=\"0x0829\"/>\n                <Item ID=\"0x0849\"/>\n                <Item ID=\"0x084A\"/>\n                <Item ID=\"0x084B\"/>\n                <Item ID=\"0x084C\"/>\n                <Item ID=\"0x084E\"/>\n                <Item ID=\"0x0851\"/>\n                <Item ID=\"0x0856\"/>\n            </Group>\n            <Group name=\"Wooden Fence\">\n                <Item ID=\"0x085C\"/>\n                <Item ID=\"0x085D\"/>\n                <Item ID=\"0x085E\"/>\n                <Item ID=\"0x085F\"/>\n                <Item ID=\"0x0860\"/>\n                <Item ID=\"0x0861\"/>\n                <Item ID=\"0x0862\"/>\n                <Item ID=\"0x0863\"/>\n                <Item ID=\"0x0864\"/>\n                <Item ID=\"0x0865\"/>\n                <Item ID=\"0x0877\"/>\n                <Item ID=\"0x0878\"/>\n                <Item ID=\"0x088A\"/>\n                <Item ID=\"0x088B\"/>\n            </Group>\n        </Group>\n        <Group name=\"Floor\">\n            <Group name=\"Carpet + Rugs\">\n                <Group name=\"Blue Carpet\">\n                    <Item ID=\"0x0ABD\"/>\n                    <Item ID=\"0x0ABE\"/>\n                    <Item ID=\"0x0ABF\"/>\n                    <Item ID=\"0x0AC0\"/>\n                    <Item ID=\"0x0AC1\"/>\n                    <Item ID=\"0x0AC2\"/>\n                    <Item ID=\"0x0AC3\"/>\n                    <Item ID=\"0x0AC4\"/>\n                    <Item ID=\"0x0AC5\"/>\n                    <Item ID=\"0x0AF6\"/>\n                    <Item ID=\"0x0AF7\"/>\n                    <Item ID=\"0x0AF8\"/>\n                    <Item ID=\"0x0AF9\"/>\n                    <Item ID=\"0x3f0a\"/>\n                </Group>\n                <Group name=\"Damaged Rug\">\n                    <Item ID=\"0x1098\"/>\n                    <Item ID=\"0x1099\"/>\n                    <Item ID=\"0x109a\"/>\n                    <Item ID=\"0x109b\"/>\n                    <Item ID=\"0x109c\"/>\n                    <Item ID=\"0x109d\"/>\n                    <Item ID=\"0x109e\"/>\n                    <Item ID=\"0x109f\"/>\n                    <Item ID=\"0x10a0\"/>\n                    <Item ID=\"0x10a1\"/>\n                    <Item ID=\"0x10a2\"/>\n                    <Item ID=\"0x10a3\"/>\n                    <Item ID=\"0x1DD3\"/>\n                    <Item ID=\"0x1DD4\"/>\n                    <Item ID=\"0x1DD5\"/>\n                    <Item ID=\"0x1DD6\"/>\n                    <Item ID=\"0x1DD7\"/>\n                    <Item ID=\"0x1DD8\"/>\n                    <Item ID=\"0x1DD9\"/>\n                    <Item ID=\"0x1DDA\"/>\n                    <Item ID=\"0x1DDB\"/>\n                    <Item ID=\"0x1DDC\"/>\n                    <Item ID=\"0x1DDD\"/>\n                    <Item ID=\"0x1DDE\"/>\n                    <Item ID=\"0x1DDF\"/>\n                    <Item ID=\"0x1DE0\"/>\n                    <Item ID=\"0x1DE1\"/>\n                    <Item ID=\"0x1DE2\"/>\n                    <Item ID=\"0x1DE3\"/>\n                    <Item ID=\"0x1DE4\"/>\n                    <Item ID=\"0x1DE5\"/>\n                    <Item ID=\"0x1DE6\"/>\n                    <Item ID=\"0x1DE7\"/>\n                    <Item ID=\"0x1DE8\"/>\n                    <Item ID=\"0x1DE9\"/>\n                    <Item ID=\"0x1DEA\"/>\n                    <Item ID=\"0x1DEB\"/>\n                    <Item ID=\"0x1DEC\"/>\n                    <Item ID=\"0x1DED\"/>\n                    <Item ID=\"0x1DEE\"/>\n                    <Item ID=\"0x1DEF\"/>\n                    <Item ID=\"0x1DF0\"/>\n                    <Item ID=\"0x1DF1\"/>\n                    <Item ID=\"0x1DF2\"/>\n                    <Item ID=\"0x1DF3\"/>\n                    <Item ID=\"0x1DF4\"/>\n                    <Item ID=\"0x1DF5\"/>\n                    <Item ID=\"0x1DF6\"/>\n                    <Item ID=\"0x1DF7\"/>\n                    <Item ID=\"0x1DF8\"/>\n                    <Item ID=\"0x1DF9\"/>\n                    <Item ID=\"0x1DFA\"/>\n                    <Item ID=\"0x1DFB\"/>\n                    <Item ID=\"0x1DFC\"/>\n                </Group>\n                <Group name=\"Fancy Blue Carpet\">\n                    <Item ID=\"0x0AD1\"/>\n                    <Item ID=\"0x0AD2\"/>\n                    <Item ID=\"0x0AD3\"/>\n                    <Item ID=\"0x0AD4\"/>\n                    <Item ID=\"0x0AD5\"/>\n                    <Item ID=\"0x0AD6\"/>\n                    <Item ID=\"0x0AD7\"/>\n                    <Item ID=\"0x0AD8\"/>\n                    <Item ID=\"0x0AD9\"/>\n                    <Item ID=\"0x3f08\"/>\n                </Group>\n                <Group name=\"Fancy Blue-Red Carpet\">\n                    <Item ID=\"0x0AEC\"/>\n                    <Item ID=\"0x0AED\"/>\n                    <Item ID=\"0x0AEE\"/>\n                    <Item ID=\"0x0AEF\"/>\n                    <Item ID=\"0x0AF0\"/>\n                    <Item ID=\"0x0AF1\"/>\n                    <Item ID=\"0x0AF2\"/>\n                    <Item ID=\"0x0AF3\"/>\n                    <Item ID=\"0x0AF4\"/>\n                    <Item ID=\"0x0AF5\"/>\n                    <Item ID=\"0x3f17\"/>\n                </Group>\n                <Group name=\"Fancy Gold Carpet\">\n                    <Item ID=\"0x0ADA\"/>\n                    <Item ID=\"0x0ADB\"/>\n                    <Item ID=\"0x0ADC\"/>\n                    <Item ID=\"0x0ADD\"/>\n                    <Item ID=\"0x0ADE\"/>\n                    <Item ID=\"0x0ADF\"/>\n                    <Item ID=\"0x0AE0\"/>\n                    <Item ID=\"0x0AE1\"/>\n                    <Item ID=\"0x0AE2\"/>\n                    <Item ID=\"0x3f11\"/>\n                </Group>\n                <Group name=\"Fancy Red Carpet\">\n                    <Item ID=\"0x0AE3\"/>\n                    <Item ID=\"0x0AE4\"/>\n                    <Item ID=\"0x0AE5\"/>\n                    <Item ID=\"0x0AE6\"/>\n                    <Item ID=\"0x0AE7\"/>\n                    <Item ID=\"0x0AE8\"/>\n                    <Item ID=\"0x0AE9\"/>\n                    <Item ID=\"0x0AEA\"/>\n                    <Item ID=\"0x0AEB\"/>\n                    <Item ID=\"0x3f0d\"/>\n                </Group>\n                <Group name=\"Grey Rug\">\n                    <Item ID=\"0x0AB3\"/>\n                    <Item ID=\"0x0AB4\"/>\n                    <Item ID=\"0x0AB5\"/>\n                    <Item ID=\"0x0AB6\"/>\n                    <Item ID=\"0x0AB7\"/>\n                    <Item ID=\"0x0AB8\"/>\n                    <Item ID=\"0x0AB9\"/>\n                    <Item ID=\"0x0ABA\"/>\n                    <Item ID=\"0x0ABB\"/>\n                    <Item ID=\"0x0ABC\"/>\n                </Group>\n                <Group name=\"Red Carpet\">\n                    <Item ID=\"0x0AC6\"/>\n                    <Item ID=\"0x0AC7\"/>\n                    <Item ID=\"0x0AC8\"/>\n                    <Item ID=\"0x0AC9\"/>\n                    <Item ID=\"0x0ACA\"/>\n                    <Item ID=\"0x0ACB\"/>\n                    <Item ID=\"0x0ACC\"/>\n                    <Item ID=\"0x0ACD\"/>\n                    <Item ID=\"0x0ACE\"/>\n                    <Item ID=\"0x0ACF\"/>\n                    <Item ID=\"0x0AD0\"/>\n                    <Item ID=\"0x3f18\"/>\n                </Group>\n                <Group name=\"Red Rug\">\n                    <Item ID=\"0x0AA9\"/>\n                    <Item ID=\"0x0AAA\"/>\n                    <Item ID=\"0x0AAB\"/>\n                    <Item ID=\"0x0AAC\"/>\n                    <Item ID=\"0x0AAD\"/>\n                    <Item ID=\"0x0AAE\"/>\n                    <Item ID=\"0x0AAF\"/>\n                    <Item ID=\"0x0AB0\"/>\n                    <Item ID=\"0x0AB1\"/>\n                    <Item ID=\"0x0AB2\"/>\n                </Group>\n            </Group>\n            <Group name=\"Fancy Stone\">\n                <Group name=\"Blue Tiles\">\n                    <Item ID=\"0x0491\"/>\n                    <Item ID=\"0x0492\"/>\n                    <Item ID=\"0x0493\"/>\n                    <Item ID=\"0x0494\"/>\n                    <Item ID=\"0x049B\"/>\n                    <Item ID=\"0x049b\"/>\n                    <Item ID=\"0x04EA\"/>\n                    <Item ID=\"0x04EB\"/>\n                    <Item ID=\"0x04EC\"/>\n                    <Item ID=\"0x04ED\"/>\n                    <Item ID=\"0x04EE\"/>\n                    <Item ID=\"0x04EF\"/>\n                    <Item ID=\"0x04F0\"/>\n                    <Item ID=\"0x04F1\"/>\n                    <Item ID=\"0x04F2\"/>\n                </Group>\n                <Group name=\"Crystal Floor\">\n                    <Item ID=\"0x35B2\"/>\n                    <Item ID=\"0x35B3\"/>\n                    <Item ID=\"0x35B4\"/>\n                    <Item ID=\"0x35B5\"/>\n                    <Item ID=\"0x35B6\"/>\n                    <Item ID=\"0x35B7\"/>\n                    <Item ID=\"0x35B8\"/>\n                    <Item ID=\"0x35B9\"/>\n                    <Item ID=\"0x35BA\"/>\n                    <Item ID=\"0x35BB\"/>\n                    <Item ID=\"0x35BC\"/>\n                    <Item ID=\"0x35BD\"/>\n                </Group>\n                <Group name=\"Gray Stone\">\n                    <Item ID=\"0x361A\"/>\n                    <Item ID=\"0x361B\"/>\n                    <Item ID=\"0x361C\"/>\n                    <Item ID=\"0x361D\"/>\n                    <Item ID=\"0x361E\"/>\n                    <Item ID=\"0x361F\"/>\n                    <Item ID=\"0x3620\"/>\n                    <Item ID=\"0x3621\"/>\n                    <Item ID=\"0x3622\"/>\n                </Group>\n                <Group name=\"Marble\">\n                    <Item ID=\"0x0495\"/>\n                    <Item ID=\"0x0496\"/>\n                    <Item ID=\"0x0497\"/>\n                    <Item ID=\"0x0498\"/>\n                    <Item ID=\"0x050D\"/>\n                    <Item ID=\"0x050F\"/>\n                    <Item ID=\"0x050e\"/>\n                    <Item ID=\"0x0510\"/>\n                    <Item ID=\"0x0511\"/>\n                    <Item ID=\"0x0512\"/>\n                    <Item ID=\"0x0513\"/>\n                    <Item ID=\"0x0514\"/>\n                </Group>\n                <Group name=\"Red Tiles\">\n                    <Item ID=\"0x04F3\"/>\n                    <Item ID=\"0x04F4\"/>\n                    <Item ID=\"0x04F5\"/>\n                    <Item ID=\"0x04F6\"/>\n                    <Item ID=\"0x04F7\"/>\n                    <Item ID=\"0x04F8\"/>\n                    <Item ID=\"0x04F9\"/>\n                    <Item ID=\"0x04FA\"/>\n                    <Item ID=\"0x04FB\"/>\n                </Group>\n            </Group>\n            <Group name=\"Magic\">\n                <Group name=\"Alchemic Symbols\">\n                    <Item ID=\"0x181d\"/>\n                    <Item ID=\"0x181e\"/>\n                    <Item ID=\"0x181f\"/>\n                    <Item ID=\"0x1820\"/>\n                    <Item ID=\"0x1821\"/>\n                    <Item ID=\"0x1822\"/>\n                    <Item ID=\"0x1823\"/>\n                    <Item ID=\"0x1824\"/>\n                    <Item ID=\"0x1825\"/>\n                    <Item ID=\"0x1826\"/>\n                    <Item ID=\"0x1827\"/>\n                    <Item ID=\"0x1828\"/>\n                </Group>\n                <Group name=\"Alchemical Symbols\">\n                    <Item ID=\"0x181D\"/>\n                    <Item ID=\"0x181E\"/>\n                    <Item ID=\"0x181F\"/>\n                    <Item ID=\"0x1820\"/>\n                    <Item ID=\"0x1821\"/>\n                    <Item ID=\"0x1822\"/>\n                    <Item ID=\"0x1823\"/>\n                    <Item ID=\"0x1824\"/>\n                    <Item ID=\"0x1825\"/>\n                    <Item ID=\"0x1826\"/>\n                    <Item ID=\"0x1827\"/>\n                </Group>\n                <Group name=\"Black\">\n                    <Item ID=\"0x3B16\"/>\n                    <Item ID=\"0x3B17\"/>\n                    <Item ID=\"0x3B18\"/>\n                    <Item ID=\"0x3B19\"/>\n                    <Item ID=\"0x3B1A\"/>\n                    <Item ID=\"0x3B1B\"/>\n                    <Item ID=\"0x3B1C\"/>\n                    <Item ID=\"0x3B1D\"/>\n                    <Item ID=\"0x3B1E\"/>\n                    <Item ID=\"0x3B1F\"/>\n                    <Item ID=\"0x3B20\"/>\n                    <Item ID=\"0x3B21\"/>\n                    <Item ID=\"0x3B22\"/>\n                    <Item ID=\"0x3B23\"/>\n                    <Item ID=\"0x3B24\"/>\n                    <Item ID=\"0x3B25\"/>\n                    <Item ID=\"0x3B26\"/>\n                </Group>\n                <Group name=\"Chaos\">\n                    <Item ID=\"0x14E3\"/>\n                    <Item ID=\"0x14E4\"/>\n                    <Item ID=\"0x14E5\"/>\n                    <Item ID=\"0x14E6\"/>\n                </Group>\n                <Group name=\"Compassion\">\n                    <Item ID=\"0x14A7\"/>\n                    <Item ID=\"0x14A8\"/>\n                    <Item ID=\"0x14A9\"/>\n                    <Item ID=\"0x14AA\"/>\n                    <Item ID=\"0x14AB\"/>\n                    <Item ID=\"0x14AC\"/>\n                    <Item ID=\"0x14AD\"/>\n                    <Item ID=\"0x14AE\"/>\n                </Group>\n                <Group name=\"Glass + Stars\">\n                    <Item ID=\"0x213F\"/>\n                    <Item ID=\"0x2140\"/>\n                    <Item ID=\"0x2141\"/>\n                    <Item ID=\"0x2142\"/>\n                    <Item ID=\"0x2143\"/>\n                    <Item ID=\"0x2144\"/>\n                    <Item ID=\"0x2e40\"/>\n                    <Item ID=\"0x2e41\"/>\n                    <Item ID=\"0x2e42\"/>\n                    <Item ID=\"0x2e43\"/>\n                    <Item ID=\"0x2e44\"/>\n                    <Item ID=\"0x2e45\"/>\n                    <Item ID=\"0x2e46\"/>\n                    <Item ID=\"0x2e47\"/>\n                </Group>\n                <Group name=\"Honesty\">\n                    <Item ID=\"0x149F\"/>\n                    <Item ID=\"0x14A0\"/>\n                    <Item ID=\"0x14A1\"/>\n                    <Item ID=\"0x14A2\"/>\n                    <Item ID=\"0x14A3\"/>\n                    <Item ID=\"0x14A4\"/>\n                    <Item ID=\"0x14A5\"/>\n                    <Item ID=\"0x14A6\"/>\n                </Group>\n                <Group name=\"Honor\">\n                    <Item ID=\"0x14C7\"/>\n                    <Item ID=\"0x14C8\"/>\n                    <Item ID=\"0x14C9\"/>\n                    <Item ID=\"0x14CA\"/>\n                    <Item ID=\"0x14CB\"/>\n                    <Item ID=\"0x14CC\"/>\n                    <Item ID=\"0x14CD\"/>\n                    <Item ID=\"0x14CE\"/>\n                </Group>\n                <Group name=\"Humility\">\n                    <Item ID=\"0x14CF\"/>\n                    <Item ID=\"0x14D0\"/>\n                    <Item ID=\"0x14D1\"/>\n                    <Item ID=\"0x14D2\"/>\n                    <Item ID=\"0x14D3\"/>\n                    <Item ID=\"0x14D4\"/>\n                    <Item ID=\"0x14D5\"/>\n                    <Item ID=\"0x14D6\"/>\n                </Group>\n                <Group name=\"Justice\">\n                    <Item ID=\"0x14AF\"/>\n                    <Item ID=\"0x14B0\"/>\n                    <Item ID=\"0x14B1\"/>\n                    <Item ID=\"0x14B2\"/>\n                    <Item ID=\"0x14B3\"/>\n                    <Item ID=\"0x14B4\"/>\n                    <Item ID=\"0x14B5\"/>\n                    <Item ID=\"0x14B6\"/>\n                </Group>\n                <Group name=\"Sacrifice\">\n                    <Item ID=\"0x150A\"/>\n                    <Item ID=\"0x150B\"/>\n                    <Item ID=\"0x150C\"/>\n                    <Item ID=\"0x150D\"/>\n                    <Item ID=\"0x150E\"/>\n                    <Item ID=\"0x150F\"/>\n                    <Item ID=\"0x1510\"/>\n                    <Item ID=\"0x1511\"/>\n                </Group>\n                <Group name=\"Spirituality\">\n                    <Item ID=\"0x14BF\"/>\n                    <Item ID=\"0x14C0\"/>\n                    <Item ID=\"0x14C1\"/>\n                    <Item ID=\"0x14C2\"/>\n                    <Item ID=\"0x14C3\"/>\n                    <Item ID=\"0x14C4\"/>\n                    <Item ID=\"0x14C5\"/>\n                    <Item ID=\"0x14C6\"/>\n                </Group>\n                <Group name=\"Teleporter Symbols\">\n                    <Item ID=\"0x17CF\"/>\n                    <Item ID=\"0x17D0\"/>\n                    <Item ID=\"0x17D1\"/>\n                    <Item ID=\"0x17D2\"/>\n                    <Item ID=\"0x17D3\"/>\n                    <Item ID=\"0x17D4\"/>\n                    <Item ID=\"0x17D5\"/>\n                    <Item ID=\"0x17D6\"/>\n                    <Item ID=\"0x17D7\"/>\n                    <Item ID=\"0x17D8\"/>\n                    <Item ID=\"0x17D9\"/>\n                    <Item ID=\"0x17DA\"/>\n                    <Item ID=\"0x17DB\"/>\n                    <Item ID=\"0x17DC\"/>\n                    <Item ID=\"0x17DD\"/>\n                    <Item ID=\"0x17DE\"/>\n                    <Item ID=\"0x17DF\"/>\n                    <Item ID=\"0x17E0\"/>\n                    <Item ID=\"0x17E1\"/>\n                    <Item ID=\"0x17E2\"/>\n                    <Item ID=\"0x17E3\"/>\n                    <Item ID=\"0x17E4\"/>\n                    <Item ID=\"0x17E5\"/>\n                    <Item ID=\"0x17E6\"/>\n                    <Item ID=\"0x17E7\"/>\n                    <Item ID=\"0x17E8\"/>\n                    <Item ID=\"0x17E9\"/>\n                    <Item ID=\"0x17EA\"/>\n                    <Item ID=\"0x17EB\"/>\n                    <Item ID=\"0x17EC\"/>\n                    <Item ID=\"0x17ED\"/>\n                    <Item ID=\"0x17EE\"/>\n                    <Item ID=\"0x17EF\"/>\n                    <Item ID=\"0x17F0\"/>\n                    <Item ID=\"0x17F1\"/>\n                    <Item ID=\"0x17F2\"/>\n                    <Item ID=\"0x17FC\"/>\n                    <Item ID=\"0x17FD\"/>\n                    <Item ID=\"0x17FE\"/>\n                    <Item ID=\"0x17FF\"/>\n                    <Item ID=\"0x1800\"/>\n                    <Item ID=\"0x1801\"/>\n                    <Item ID=\"0x1802\"/>\n                    <Item ID=\"0x1803\"/>\n                    <Item ID=\"0x1804\"/>\n                    <Item ID=\"0x1805\"/>\n                    <Item ID=\"0x1806\"/>\n                    <Item ID=\"0x1807\"/>\n                    <Item ID=\"0x1808\"/>\n                    <Item ID=\"0x1809\"/>\n                    <Item ID=\"0x180A\"/>\n                    <Item ID=\"0x180B\"/>\n                    <Item ID=\"0x180C\"/>\n                    <Item ID=\"0x180D\"/>\n                </Group>\n                <Group name=\"Valor\">\n                    <Item ID=\"0x14B7\"/>\n                    <Item ID=\"0x14B8\"/>\n                    <Item ID=\"0x14B9\"/>\n                    <Item ID=\"0x14BA\"/>\n                    <Item ID=\"0x14BB\"/>\n                    <Item ID=\"0x14BC\"/>\n                    <Item ID=\"0x14BD\"/>\n                    <Item ID=\"0x14BE\"/>\n                </Group>\n            </Group>\n            <Group name=\"Misc\">\n                <Item ID=\"0x049C\"/>\n                <Item ID=\"0x2712\"/>\n                <Item ID=\"0x2720\"/>\n                <Item ID=\"0x2721\"/>\n                <Item ID=\"0x2752\"/>\n                <Item ID=\"0x337a\"/>\n            </Group>\n            <Group name=\"Organic, Other\">\n                <Group name=\"Brown Bearskin E\">\n                    <Item ID=\"0x1E40\"/>\n                    <Item ID=\"0x1E41\"/>\n                    <Item ID=\"0x1E42\"/>\n                    <Item ID=\"0x1E43\"/>\n                    <Item ID=\"0x1E44\"/>\n                    <Item ID=\"0x1E45\"/>\n                    <Item ID=\"0x1E46\"/>\n                    <Item ID=\"0x1E47\"/>\n                    <Item ID=\"0x1E48\"/>\n                </Group>\n                <Group name=\"Brown Bearskin S\">\n                    <Item ID=\"0x1E36\"/>\n                    <Item ID=\"0x1E37\"/>\n                    <Item ID=\"0x1E38\"/>\n                    <Item ID=\"0x1E39\"/>\n                    <Item ID=\"0x1E3A\"/>\n                    <Item ID=\"0x1E3B\"/>\n                    <Item ID=\"0x1E3C\"/>\n                    <Item ID=\"0x1E3D\"/>\n                    <Item ID=\"0x1E3E\"/>\n                    <Item ID=\"0x2AC8\"/>\n                    <Item ID=\"0x2AC9\"/>\n                    <Item ID=\"0x2ACd\"/>\n                    <Item ID=\"0x2ACe\"/>\n                </Group>\n                <Group name=\"Polar Bearskin E\">\n                    <Item ID=\"0x1E53\"/>\n                    <Item ID=\"0x1E54\"/>\n                    <Item ID=\"0x1E55\"/>\n                    <Item ID=\"0x1E56\"/>\n                    <Item ID=\"0x1E57\"/>\n                    <Item ID=\"0x1E58\"/>\n                    <Item ID=\"0x1E59\"/>\n                    <Item ID=\"0x1E5A\"/>\n                    <Item ID=\"0x1E5B\"/>\n                </Group>\n                <Group name=\"Polar Bearskin S\">\n                    <Item ID=\"0x1E49\"/>\n                    <Item ID=\"0x1E4A\"/>\n                    <Item ID=\"0x1E4B\"/>\n                    <Item ID=\"0x1E4C\"/>\n                    <Item ID=\"0x1E4D\"/>\n                    <Item ID=\"0x1E4E\"/>\n                    <Item ID=\"0x1E4F\"/>\n                    <Item ID=\"0x1E50\"/>\n                    <Item ID=\"0x1E51\"/>\n                </Group>\n                <Group name=\"Tatami\">\n                    <Item ID=\"0x2435\"/>\n                    <Item ID=\"0x2436\"/>\n                    <Item ID=\"0x2437\"/>\n                    <Item ID=\"0x2438\"/>\n                    <Item ID=\"0x29C0\"/>\n                    <Item ID=\"0x29C1\"/>\n                    <Item ID=\"0x29C2\"/>\n                    <Item ID=\"0x29C3\"/>\n                    <Item ID=\"0x29C4\"/>\n                    <Item ID=\"0x29C5\"/>\n                    <Item ID=\"0x29C6\"/>\n                    <Item ID=\"0x29C7\"/>\n                    <Item ID=\"0x29C8\"/>\n                    <Item ID=\"0x29C9\"/>\n                    <Item ID=\"0x29CA\"/>\n                    <Item ID=\"0x29CB\"/>\n                    <Item ID=\"0x29D0\"/>\n                    <Item ID=\"0x29D1\"/>\n                    <Item ID=\"0x29D6\"/>\n                    <Item ID=\"0x29D7\"/>\n                    <Item ID=\"0x29D8\"/>\n                    <Item ID=\"0x29D9\"/>\n                    <Item ID=\"0x29Da\"/>\n                    <Item ID=\"0x29Db\"/>\n                    <Item ID=\"0x2A1d\"/>\n                    <Item ID=\"0x2A1e\"/>\n                    <Item ID=\"0x2A1f\"/>\n                    <Item ID=\"0x2A20\"/>\n                    <Item ID=\"0x2A21\"/>\n                    <Item ID=\"0x2A21\"/>\n                    <Item ID=\"0x2A22\"/>\n                    <Item ID=\"0x2A22\"/>\n                    <Item ID=\"0x2A23\"/>\n                    <Item ID=\"0x2A23\"/>\n                    <Item ID=\"0x2A24\"/>\n                    <Item ID=\"0x2A24\"/>\n                    <Item ID=\"0x2A25\"/>\n                    <Item ID=\"0x2A26\"/>\n                    <Item ID=\"0x2A27\"/>\n                    <Item ID=\"0x2A28\"/>\n                    <Item ID=\"0x2A29\"/>\n                    <Item ID=\"0x2A3C\"/>\n                    <Item ID=\"0x2A3D\"/>\n                    <Item ID=\"0x2A3E\"/>\n                    <Item ID=\"0x2A3F\"/>\n                    <Item ID=\"0x2A40\"/>\n                    <Item ID=\"0x2A41\"/>\n                    <Item ID=\"0x2A42\"/>\n                    <Item ID=\"0x2A44\"/>\n                </Group>\n            </Group>\n            <Group name=\"Outdoors\">\n                <Group name=\"Cobblestone\">\n                    <Item ID=\"0x0515\"/>\n                    <Item ID=\"0x0516\"/>\n                    <Item ID=\"0x0517\"/>\n                    <Item ID=\"0x0518\"/>\n                    <Item ID=\"0x0654\"/>\n                    <Item ID=\"0x0655\"/>\n                </Group>\n                <Group name=\"Drain\">\n                    <Item ID=\"0x30E7\"/>\n                    <Item ID=\"0x30E8\"/>\n                    <Item ID=\"0x30E9\"/>\n                    <Item ID=\"0x30EA\"/>\n                    <Item ID=\"0x30EB\"/>\n                    <Item ID=\"0x30EC\"/>\n                    <Item ID=\"0x30ED\"/>\n                    <Item ID=\"0x30EE\"/>\n                    <Item ID=\"0x30EF\"/>\n                    <Item ID=\"0x30F0\"/>\n                    <Item ID=\"0x30F1\"/>\n                    <Item ID=\"0x30F2\"/>\n                    <Item ID=\"0x30F3\"/>\n                    <Item ID=\"0x30F4\"/>\n                    <Item ID=\"0x30F5\"/>\n                    <Item ID=\"0x30F6\"/>\n                    <Item ID=\"0x30F7\"/>\n                    <Item ID=\"0x30F8\"/>\n                    <Item ID=\"0x30F9\"/>\n                    <Item ID=\"0x30FA\"/>\n                    <Item ID=\"0x30FB\"/>\n                    <Item ID=\"0x30FC\"/>\n                    <Item ID=\"0x30FD\"/>\n                    <Item ID=\"0x30FE\"/>\n                    <Item ID=\"0x30FF\"/>\n                    <Item ID=\"0x3100\"/>\n                    <Item ID=\"0x3101\"/>\n                    <Item ID=\"0x3102\"/>\n                    <Item ID=\"0x3103\"/>\n                    <Item ID=\"0x3104\"/>\n                    <Item ID=\"0x3105\"/>\n                    <Item ID=\"0x3106\"/>\n                    <Item ID=\"0x3107\"/>\n                    <Item ID=\"0x3108\"/>\n                    <Item ID=\"0x3109\"/>\n                    <Item ID=\"0x310A\"/>\n                </Group>\n                <Group name=\"Pond\">\n                    <Item ID=\"0x2453\"/>\n                    <Item ID=\"0x2454\"/>\n                    <Item ID=\"0x2455\"/>\n                    <Item ID=\"0x2456\"/>\n                    <Item ID=\"0x2457\"/>\n                    <Item ID=\"0x2458\"/>\n                    <Item ID=\"0x2459\"/>\n                    <Item ID=\"0x245A\"/>\n                    <Item ID=\"0x245B\"/>\n                    <Item ID=\"0x245C\"/>\n                    <Item ID=\"0x245D\"/>\n                </Group>\n                <Group name=\"Sand Garden\">\n                    <Item ID=\"0x245E\"/>\n                    <Item ID=\"0x245F\"/>\n                    <Item ID=\"0x2460\"/>\n                    <Item ID=\"0x2461\"/>\n                    <Item ID=\"0x2462\"/>\n                    <Item ID=\"0x2463\"/>\n                    <Item ID=\"0x2464\"/>\n                    <Item ID=\"0x2465\"/>\n                    <Item ID=\"0x2466\"/>\n                    <Item ID=\"0x2467\"/>\n                    <Item ID=\"0x2468\"/>\n                    <Item ID=\"0x2469\"/>\n                    <Item ID=\"0x246A\"/>\n                    <Item ID=\"0x246B\"/>\n                </Group>\n                <Group name=\"Spotted\">\n                    <Item ID=\"0x3B27\"/>\n                    <Item ID=\"0x3B28\"/>\n                    <Item ID=\"0x3B29\"/>\n                    <Item ID=\"0x3B2A\"/>\n                    <Item ID=\"0x3B2B\"/>\n                    <Item ID=\"0x3B2C\"/>\n                    <Item ID=\"0x3B2D\"/>\n                    <Item ID=\"0x3B2E\"/>\n                    <Item ID=\"0x3B2F\"/>\n                    <Item ID=\"0x3B30\"/>\n                    <Item ID=\"0x3B31\"/>\n                    <Item ID=\"0x3B32\"/>\n                    <Item ID=\"0x3B33\"/>\n                    <Item ID=\"0x3B34\"/>\n                    <Item ID=\"0x3B35\"/>\n                    <Item ID=\"0x3B36\"/>\n                    <Item ID=\"0x3B37\"/>\n                </Group>\n                <Group name=\"Tree\">\n                    <Item ID=\"0x2e69\"/>\n                    <Item ID=\"0x2e6a\"/>\n                    <Item ID=\"0x2e6b\"/>\n                    <Item ID=\"0x2e6c\"/>\n                    <Item ID=\"0x2e6d\"/>\n                    <Item ID=\"0x2e6e\"/>\n                    <Item ID=\"0x2e6f\"/>\n                    <Item ID=\"0x2e70\"/>\n                    <Item ID=\"0x2e71\"/>\n                    <Item ID=\"0x2e72\"/>\n                    <Item ID=\"0x2e73\"/>\n                    <Item ID=\"0x2e74\"/>\n                    <Item ID=\"0x2e75\"/>\n                    <Item ID=\"0x2e76\"/>\n                    <Item ID=\"0x2e77\"/>\n                    <Item ID=\"0x2e78\"/>\n                    <Item ID=\"0x2e79\"/>\n                    <Item ID=\"0x2e7a\"/>\n                    <Item ID=\"0x2e7b\"/>\n                    <Item ID=\"0x2e7c\"/>\n                    <Item ID=\"0x2e7d\"/>\n                    <Item ID=\"0x2e7e\"/>\n                    <Item ID=\"0x2e7f\"/>\n                    <Item ID=\"0x2e80\"/>\n                    <Item ID=\"0x2e81\"/>\n                    <Item ID=\"0x2e82\"/>\n                    <Item ID=\"0x2e83\"/>\n                    <Item ID=\"0x2e84\"/>\n                    <Item ID=\"0x2e85\"/>\n                    <Item ID=\"0x2e86\"/>\n                    <Item ID=\"0x2e87\"/>\n                    <Item ID=\"0x2e88\"/>\n                    <Item ID=\"0x2e89\"/>\n                    <Item ID=\"0x2e8a\"/>\n                    <Item ID=\"0x2e8b\"/>\n                    <Item ID=\"0x2e8c\"/>\n                    <Item ID=\"0x2e8d\"/>\n                    <Item ID=\"0x2e8e\"/>\n                    <Item ID=\"0x2e8f\"/>\n                    <Item ID=\"0x2e90\"/>\n                    <Item ID=\"0x2e91\"/>\n                    <Item ID=\"0x2e92\"/>\n                    <Item ID=\"0x2e93\"/>\n                    <Item ID=\"0x2e94\"/>\n                    <Item ID=\"0x2e95\"/>\n                    <Item ID=\"0x2e96\"/>\n                    <Item ID=\"0x2e97\"/>\n                    <Item ID=\"0x2e98\"/>\n                    <Item ID=\"0x2e99\"/>\n                    <Item ID=\"0x2e9a\"/>\n                    <Item ID=\"0x2e9b\"/>\n                    <Item ID=\"0x2e9c\"/>\n                    <Item ID=\"0x2e9d\"/>\n                    <Item ID=\"0x2e9e\"/>\n                    <Item ID=\"0x2e9f\"/>\n                    <Item ID=\"0x2ea0\"/>\n                    <Item ID=\"0x2ea1\"/>\n                    <Item ID=\"0x2ea2\"/>\n                    <Item ID=\"0x2ea3\"/>\n                    <Item ID=\"0x2ea4\"/>\n                    <Item ID=\"0x2ea5\"/>\n                    <Item ID=\"0x2ea6\"/>\n                    <Item ID=\"0x2ea7\"/>\n                    <Item ID=\"0x2ea8\"/>\n                    <Item ID=\"0x2ea9\"/>\n                    <Item ID=\"0x2eaa\"/>\n                    <Item ID=\"0x2eab\"/>\n                    <Item ID=\"0x2eac\"/>\n                    <Item ID=\"0x2ead\"/>\n                    <Item ID=\"0x2eae\"/>\n                    <Item ID=\"0x2eaf\"/>\n                    <Item ID=\"0x2eb0\"/>\n                    <Item ID=\"0x2eb1\"/>\n                    <Item ID=\"0x2eb2\"/>\n                    <Item ID=\"0x2eb3\"/>\n                    <Item ID=\"0x2eb4\"/>\n                    <Item ID=\"0x2eb5\"/>\n                    <Item ID=\"0x2eb6\"/>\n                    <Item ID=\"0x2eb7\"/>\n                    <Item ID=\"0x2eb8\"/>\n                    <Item ID=\"0x2eb9\"/>\n                    <Item ID=\"0x2eba\"/>\n                    <Item ID=\"0x2ebb\"/>\n                    <Item ID=\"0x2ebc\"/>\n                    <Item ID=\"0x2ebd\"/>\n                    <Item ID=\"0x2ebe\"/>\n                    <Item ID=\"0x2ebf\"/>\n                    <Item ID=\"0x2ec0\"/>\n                    <Item ID=\"0x2ec1\"/>\n                    <Item ID=\"0x2ec2\"/>\n                    <Item ID=\"0x2ec3\"/>\n                    <Item ID=\"0x2ec4\"/>\n                    <Item ID=\"0x2ec5\"/>\n                    <Item ID=\"0x2ec6\"/>\n                    <Item ID=\"0x2ec7\"/>\n                    <Item ID=\"0x2ec8\"/>\n                    <Item ID=\"0x2ec9\"/>\n                    <Item ID=\"0x2eca\"/>\n                    <Item ID=\"0x2ecb\"/>\n                    <Item ID=\"0x2ecc\"/>\n                    <Item ID=\"0x2ecd\"/>\n                    <Item ID=\"0x2ece\"/>\n                    <Item ID=\"0x2ecf\"/>\n                    <Item ID=\"0x2ed0\"/>\n                    <Item ID=\"0x2ed1\"/>\n                    <Item ID=\"0x2ed2\"/>\n                    <Item ID=\"0x2ed3\"/>\n                    <Item ID=\"0x2ed4\"/>\n                    <Item ID=\"0x2ed5\"/>\n                    <Item ID=\"0x2ed6\"/>\n                    <Item ID=\"0x2ed7\"/>\n                    <Item ID=\"0x2ed8\"/>\n                    <Item ID=\"0x2ed9\"/>\n                    <Item ID=\"0x2eda\"/>\n                    <Item ID=\"0x2edb\"/>\n                    <Item ID=\"0x2ee1\"/>\n                    <Item ID=\"0x2ee2\"/>\n                    <Item ID=\"0x2ee3\"/>\n                    <Item ID=\"0x2ee4\"/>\n                    <Item ID=\"0x2ee5\"/>\n                    <Item ID=\"0x2ee6\"/>\n                    <Item ID=\"0x2ee7\"/>\n                    <Item ID=\"0x2ee8\"/>\n                    <Item ID=\"0x2ee9\"/>\n                    <Item ID=\"0x2eea\"/>\n                    <Item ID=\"0x2eeb\"/>\n                    <Item ID=\"0x2eec\"/>\n                    <Item ID=\"0x2eed\"/>\n                    <Item ID=\"0x2eee\"/>\n                    <Item ID=\"0x2eef\"/>\n                    <Item ID=\"0x2ef0\"/>\n                    <Item ID=\"0x2ef1\"/>\n                    <Item ID=\"0x2ef2\"/>\n                    <Item ID=\"0x2ef3\"/>\n                    <Item ID=\"0x2ef4\"/>\n                    <Item ID=\"0x2ef5\"/>\n                    <Item ID=\"0x2ef6\"/>\n                    <Item ID=\"0x2ef7\"/>\n                    <Item ID=\"0x2ef8\"/>\n                    <Item ID=\"0x2ef9\"/>\n                    <Item ID=\"0x2efa\"/>\n                    <Item ID=\"0x2efb\"/>\n                    <Item ID=\"0x2efc\"/>\n                    <Item ID=\"0x2efd\"/>\n                    <Item ID=\"0x2efe\"/>\n                    <Item ID=\"0x2eff\"/>\n                    <Item ID=\"0x2f00\"/>\n                    <Item ID=\"0x2f01\"/>\n                    <Item ID=\"0x2f02\"/>\n                    <Item ID=\"0x2f03\"/>\n                    <Item ID=\"0x2f04\"/>\n                    <Item ID=\"0x2f05\"/>\n                    <Item ID=\"0x2f06\"/>\n                    <Item ID=\"0x2f07\"/>\n                    <Item ID=\"0x2f08\"/>\n                    <Item ID=\"0x2f09\"/>\n                    <Item ID=\"0x2f0a\"/>\n                    <Item ID=\"0x2f0b\"/>\n                    <Item ID=\"0x2f0c\"/>\n                    <Item ID=\"0x2f0d\"/>\n                    <Item ID=\"0x2f0e\"/>\n                    <Item ID=\"0x39da\"/>\n                    <Item ID=\"0x39db\"/>\n                    <Item ID=\"0x39dc\"/>\n                    <Item ID=\"0x39dd\"/>\n                    <Item ID=\"0x39de\"/>\n                    <Item ID=\"0x39df\"/>\n                    <Item ID=\"0x39e0\"/>\n                    <Item ID=\"0x39e1\"/>\n                    <Item ID=\"0x39e2\"/>\n                    <Item ID=\"0x39e3\"/>\n                    <Item ID=\"0x39e4\"/>\n                    <Item ID=\"0x39e5\"/>\n                    <Item ID=\"0x39e6\"/>\n                    <Item ID=\"0x3a1f\"/>\n                    <Item ID=\"0x3a20\"/>\n                    <Item ID=\"0x3a21\"/>\n                    <Item ID=\"0x3a22\"/>\n                    <Item ID=\"0x3a23\"/>\n                    <Item ID=\"0x3a24\"/>\n                    <Item ID=\"0x3a25\"/>\n                    <Item ID=\"0x3a26\"/>\n                    <Item ID=\"0x3a27\"/>\n                    <Item ID=\"0x3a28\"/>\n                    <Item ID=\"0x3a29\"/>\n                    <Item ID=\"0x3a2a\"/>\n                    <Item ID=\"0x3a2b\"/>\n                    <Item ID=\"0x3a2c\"/>\n                    <Item ID=\"0x3a2d\"/>\n                    <Item ID=\"0x3a2e\"/>\n                    <Item ID=\"0x3a2f\"/>\n                    <Item ID=\"0x3a30\"/>\n                    <Item ID=\"0x3a31\"/>\n                    <Item ID=\"0x3a32\"/>\n                    <Item ID=\"0x3a45\"/>\n                    <Item ID=\"0x3a46\"/>\n                    <Item ID=\"0x3a47\"/>\n                    <Item ID=\"0x3a48\"/>\n                    <Item ID=\"0x3a49\"/>\n                    <Item ID=\"0x3a4a\"/>\n                    <Item ID=\"0x3a4b\"/>\n                    <Item ID=\"0x3a4c\"/>\n                    <Item ID=\"0x3a4d\"/>\n                    <Item ID=\"0x3a4e\"/>\n                    <Item ID=\"0x3a4f\"/>\n                    <Item ID=\"0x3a50\"/>\n                    <Item ID=\"0x3a51\"/>\n                    <Item ID=\"0x3a52\"/>\n                    <Item ID=\"0x3a53\"/>\n                    <Item ID=\"0x3a54\"/>\n                    <Item ID=\"0x3af0\"/>\n                    <Item ID=\"0x3af1\"/>\n                    <Item ID=\"0x3af2\"/>\n                    <Item ID=\"0x3af3\"/>\n                    <Item ID=\"0x3af4\"/>\n                    <Item ID=\"0x3af5\"/>\n                    <Item ID=\"0x3af6\"/>\n                    <Item ID=\"0x3af7\"/>\n                    <Item ID=\"0x3af8\"/>\n                </Group>\n            </Group>\n            <Group name=\"Rough Stone\">\n                <Group name=\"Blueish Stone\">\n                    <Item ID=\"0x063b\"/>\n                    <Item ID=\"0x063c\"/>\n                    <Item ID=\"0x063d\"/>\n                    <Item ID=\"0x063e\"/>\n                    <Item ID=\"0x0652\"/>\n                    <Item ID=\"0x0653\"/>\n                </Group>\n                <Group name=\"Flagstone\">\n                    <Item ID=\"0x04Fc\"/>\n                    <Item ID=\"0x04Fd\"/>\n                    <Item ID=\"0x04Fe\"/>\n                    <Item ID=\"0x04Ff\"/>\n                    <Item ID=\"0x0500\"/>\n                    <Item ID=\"0x0501\"/>\n                    <Item ID=\"0x0502\"/>\n                    <Item ID=\"0x0503\"/>\n                </Group>\n                <Group name=\"Gray Stone\">\n                    <Item ID=\"0x0579\"/>\n                    <Item ID=\"0x057a\"/>\n                    <Item ID=\"0x057b\"/>\n                    <Item ID=\"0x057c\"/>\n                    <Item ID=\"0x057d\"/>\n                    <Item ID=\"0x057e\"/>\n                </Group>\n                <Group name=\"Red Brick\">\n                    <Item ID=\"0x04E2\"/>\n                    <Item ID=\"0x04E3\"/>\n                    <Item ID=\"0x04E4\"/>\n                    <Item ID=\"0x04E5\"/>\n                    <Item ID=\"0x04E6\"/>\n                    <Item ID=\"0x04E7\"/>\n                    <Item ID=\"0x04E8\"/>\n                    <Item ID=\"0x04E9\"/>\n                    <Item ID=\"0x0537\"/>\n                    <Item ID=\"0x0538\"/>\n                    <Item ID=\"0x0539\"/>\n                    <Item ID=\"0x053a\"/>\n                </Group>\n                <Group name=\"Red Stone\">\n                    <Item ID=\"0x0554\"/>\n                    <Item ID=\"0x0555\"/>\n                    <Item ID=\"0x0556\"/>\n                    <Item ID=\"0x0557\"/>\n                    <Item ID=\"0x055C\"/>\n                    <Item ID=\"0x055d\"/>\n                    <Item ID=\"0x055e\"/>\n                    <Item ID=\"0x055f\"/>\n                    <Item ID=\"0x0560\"/>\n                    <Item ID=\"0x0561\"/>\n                    <Item ID=\"0x0562\"/>\n                    <Item ID=\"0x0563\"/>\n                    <Item ID=\"0x0564\"/>\n                    <Item ID=\"0x0565\"/>\n                    <Item ID=\"0x0566\"/>\n                    <Item ID=\"0x0567\"/>\n                    <Item ID=\"0x0568\"/>\n                    <Item ID=\"0x0569\"/>\n                    <Item ID=\"0x062f\"/>\n                    <Item ID=\"0x0630\"/>\n                    <Item ID=\"0x0631\"/>\n                    <Item ID=\"0x0631\"/>\n                    <Item ID=\"0x0632\"/>\n                    <Item ID=\"0x0632\"/>\n                    <Item ID=\"0x0656\"/>\n                    <Item ID=\"0x0657\"/>\n                </Group>\n                <Group name=\"Slate\">\n                    <Item ID=\"0x057F\"/>\n                    <Item ID=\"0x0580\"/>\n                    <Item ID=\"0x0581\"/>\n                    <Item ID=\"0x0582\"/>\n                    <Item ID=\"0x0583\"/>\n                    <Item ID=\"0x0584\"/>\n                    <Item ID=\"0x0585\"/>\n                    <Item ID=\"0x0658\"/>\n                    <Item ID=\"0x0659\"/>\n                </Group>\n                <Group name=\"Stone Pavers\">\n                    <Item ID=\"0x0519\"/>\n                    <Item ID=\"0x051a\"/>\n                    <Item ID=\"0x051b\"/>\n                    <Item ID=\"0x051c\"/>\n                    <Item ID=\"0x051d\"/>\n                    <Item ID=\"0x051e\"/>\n                    <Item ID=\"0x051f\"/>\n                    <Item ID=\"0x0520\"/>\n                    <Item ID=\"0x0521\"/>\n                    <Item ID=\"0x0522\"/>\n                    <Item ID=\"0x0523\"/>\n                    <Item ID=\"0x0524\"/>\n                </Group>\n                <Group name=\"White Stone\">\n                    <Item ID=\"0x0550\"/>\n                    <Item ID=\"0x0558\"/>\n                    <Item ID=\"0x0559\"/>\n                    <Item ID=\"0x055A\"/>\n                    <Item ID=\"0x055B\"/>\n                    <Item ID=\"0x055a\"/>\n                    <Item ID=\"0x055b\"/>\n                    <Item ID=\"0x056B\"/>\n                    <Item ID=\"0x056C\"/>\n                    <Item ID=\"0x056D\"/>\n                    <Item ID=\"0x056E\"/>\n                    <Item ID=\"0x056F\"/>\n                    <Item ID=\"0x0570\"/>\n                    <Item ID=\"0x0571\"/>\n                    <Item ID=\"0x0572\"/>\n                    <Item ID=\"0x0573\"/>\n                    <Item ID=\"0x0574\"/>\n                    <Item ID=\"0x0575\"/>\n                    <Item ID=\"0x0576\"/>\n                    <Item ID=\"0x0577\"/>\n                    <Item ID=\"0x05ef\"/>\n                    <Item ID=\"0x062D\"/>\n                    <Item ID=\"0x062E\"/>\n                    <Item ID=\"0x062b\"/>\n                    <Item ID=\"0x062c\"/>\n                    <Item ID=\"0x062d\"/>\n                    <Item ID=\"0x062e\"/>\n                    <Item ID=\"0x0637\"/>\n                    <Item ID=\"0x0638\"/>\n                    <Item ID=\"0x0639\"/>\n                    <Item ID=\"0x063a\"/>\n                    <Item ID=\"0x065a\"/>\n                    <Item ID=\"0x065b\"/>\n                    <Item ID=\"0x065c\"/>\n                    <Item ID=\"0x065d\"/>\n                </Group>\n                <Group name=\"sandstone\">\n                    <Item ID=\"0x049D\"/>\n                    <Item ID=\"0x049e\"/>\n                    <Item ID=\"0x049f\"/>\n                    <Item ID=\"0x04a0\"/>\n                    <Item ID=\"0x0525\"/>\n                    <Item ID=\"0x0525\"/>\n                    <Item ID=\"0x0526\"/>\n                    <Item ID=\"0x0527\"/>\n                    <Item ID=\"0x0528\"/>\n                    <Item ID=\"0x0529\"/>\n                    <Item ID=\"0x052F\"/>\n                    <Item ID=\"0x052a\"/>\n                    <Item ID=\"0x052b\"/>\n                    <Item ID=\"0x052c\"/>\n                    <Item ID=\"0x0530\"/>\n                    <Item ID=\"0x0531\"/>\n                    <Item ID=\"0x0532\"/>\n                    <Item ID=\"0x0533\"/>\n                    <Item ID=\"0x0534\"/>\n                    <Item ID=\"0x0535\"/>\n                    <Item ID=\"0x0536\"/>\n                    <Item ID=\"0x1383\"/>\n                    <Item ID=\"0x1384\"/>\n                    <Item ID=\"0x1385\"/>\n                    <Item ID=\"0x1386\"/>\n                </Group>\n            </Group>\n            <Group name=\"Wood\">\n                <Group name=\"Bamboo Logs\">\n                    <Item ID=\"0x04C1\"/>\n                    <Item ID=\"0x04C2\"/>\n                    <Item ID=\"0x04C3\"/>\n                    <Item ID=\"0x04C4\"/>\n                    <Item ID=\"0x04C5\"/>\n                    <Item ID=\"0x0504\"/>\n                    <Item ID=\"0x0505\"/>\n                    <Item ID=\"0x0506\"/>\n                    <Item ID=\"0x0507\"/>\n                    <Item ID=\"0x0508\"/>\n                    <Item ID=\"0x0509\"/>\n                    <Item ID=\"0x050A\"/>\n                    <Item ID=\"0x050B\"/>\n                    <Item ID=\"0x050C\"/>\n                </Group>\n                <Group name=\"Brown Board\">\n                    <Item ID=\"0x2978\"/>\n                    <Item ID=\"0x2979\"/>\n                    <Item ID=\"0x297A\"/>\n                    <Item ID=\"0x297B\"/>\n                    <Item ID=\"0x297C\"/>\n                    <Item ID=\"0x297D\"/>\n                    <Item ID=\"0x297E\"/>\n                    <Item ID=\"0x297F\"/>\n                    <Item ID=\"0x2980\"/>\n                    <Item ID=\"0x2981\"/>\n                    <Item ID=\"0x2982\"/>\n                    <Item ID=\"0x2983\"/>\n                    <Item ID=\"0x2984\"/>\n                    <Item ID=\"0x2985\"/>\n                    <Item ID=\"0x2986\"/>\n                    <Item ID=\"0x2987\"/>\n                    <Item ID=\"0x2988\"/>\n                    <Item ID=\"0x2989\"/>\n                    <Item ID=\"0x298A\"/>\n                    <Item ID=\"0x298B\"/>\n                    <Item ID=\"0x298C\"/>\n                    <Item ID=\"0x298D\"/>\n                    <Item ID=\"0x298E\"/>\n                    <Item ID=\"0x298F\"/>\n                </Group>\n                <Group name=\"Dark Wood Board\">\n                    <Item ID=\"0x04A5\"/>\n                    <Item ID=\"0x04A6\"/>\n                    <Item ID=\"0x04A7\"/>\n                    <Item ID=\"0x04A8\"/>\n                    <Item ID=\"0x04A9\"/>\n                    <Item ID=\"0x04AA\"/>\n                    <Item ID=\"0x04AB\"/>\n                    <Item ID=\"0x04AC\"/>\n                    <Item ID=\"0x04AD\"/>\n                    <Item ID=\"0x04AE\"/>\n                    <Item ID=\"0x04AF\"/>\n                    <Item ID=\"0x04B0\"/>\n                    <Item ID=\"0x04B1\"/>\n                    <Item ID=\"0x04B2\"/>\n                    <Item ID=\"0x04B3\"/>\n                    <Item ID=\"0x04B4\"/>\n                    <Item ID=\"0x04B5\"/>\n                    <Item ID=\"0x04B6\"/>\n                    <Item ID=\"0x04B7\"/>\n                    <Item ID=\"0x04B8\"/>\n                    <Item ID=\"0x04B9\"/>\n                    <Item ID=\"0x04BA\"/>\n                    <Item ID=\"0x04BB\"/>\n                    <Item ID=\"0x04BC\"/>\n                    <Item ID=\"0x04BD\"/>\n                    <Item ID=\"0x04BE\"/>\n                    <Item ID=\"0x04BF\"/>\n                    <Item ID=\"0x04C0\"/>\n                </Group>\n                <Group name=\"Floral Wood\">\n                    <Item ID=\"0x2BB5\"/>\n                    <Item ID=\"0x2BB6\"/>\n                    <Item ID=\"0x2BB7\"/>\n                    <Item ID=\"0x2BB8\"/>\n                    <Item ID=\"0x2BCF\"/>\n                    <Item ID=\"0x2CEC\"/>\n                    <Item ID=\"0x2CED\"/>\n                    <Item ID=\"0x2CEE\"/>\n                    <Item ID=\"0x2D38\"/>\n                    <Item ID=\"0x2D39\"/>\n                    <Item ID=\"0x2D3A\"/>\n                    <Item ID=\"0x2D3B\"/>\n                    <Item ID=\"0x2DCB\"/>\n                    <Item ID=\"0x2DCC\"/>\n                    <Item ID=\"0x2DCD\"/>\n                    <Item ID=\"0x2DCE\"/>\n                    <Item ID=\"0x3004\"/>\n                    <Item ID=\"0x3005\"/>\n                    <Item ID=\"0x3006\"/>\n                    <Item ID=\"0x3007\"/>\n                </Group>\n                <Group name=\"Light Brown Board\">\n                    <Item ID=\"0x273A\"/>\n                    <Item ID=\"0x273B\"/>\n                    <Item ID=\"0x273C\"/>\n                    <Item ID=\"0x273D\"/>\n                    <Item ID=\"0x273E\"/>\n                    <Item ID=\"0x273F\"/>\n                    <Item ID=\"0x2740\"/>\n                    <Item ID=\"0x2741\"/>\n                    <Item ID=\"0x2742\"/>\n                    <Item ID=\"0x2743\"/>\n                    <Item ID=\"0x2744\"/>\n                    <Item ID=\"0x2745\"/>\n                    <Item ID=\"0x2746\"/>\n                    <Item ID=\"0x2747\"/>\n                    <Item ID=\"0x2748\"/>\n                    <Item ID=\"0x2749\"/>\n                    <Item ID=\"0x274A\"/>\n                    <Item ID=\"0x274B\"/>\n                    <Item ID=\"0x274C\"/>\n                    <Item ID=\"0x274D\"/>\n                    <Item ID=\"0x274E\"/>\n                    <Item ID=\"0x274F\"/>\n                    <Item ID=\"0x2750\"/>\n                    <Item ID=\"0x2751\"/>\n                </Group>\n                <Group name=\"Light Red Board\">\n                    <Item ID=\"0x2722\"/>\n                    <Item ID=\"0x2723\"/>\n                    <Item ID=\"0x2724\"/>\n                    <Item ID=\"0x2725\"/>\n                    <Item ID=\"0x2726\"/>\n                    <Item ID=\"0x2727\"/>\n                    <Item ID=\"0x2728\"/>\n                    <Item ID=\"0x2729\"/>\n                    <Item ID=\"0x272A\"/>\n                    <Item ID=\"0x272B\"/>\n                    <Item ID=\"0x272C\"/>\n                    <Item ID=\"0x272D\"/>\n                    <Item ID=\"0x272E\"/>\n                    <Item ID=\"0x272F\"/>\n                    <Item ID=\"0x2730\"/>\n                    <Item ID=\"0x2731\"/>\n                    <Item ID=\"0x2732\"/>\n                    <Item ID=\"0x2733\"/>\n                    <Item ID=\"0x2734\"/>\n                    <Item ID=\"0x2735\"/>\n                    <Item ID=\"0x2736\"/>\n                    <Item ID=\"0x2737\"/>\n                    <Item ID=\"0x2738\"/>\n                    <Item ID=\"0x2739\"/>\n                </Group>\n                <Group name=\"Light Wood Planks\">\n                    <Item ID=\"0x04A1\"/>\n                    <Item ID=\"0x04A2\"/>\n                    <Item ID=\"0x04A3\"/>\n                    <Item ID=\"0x04A4\"/>\n                    <Item ID=\"0x04C6\"/>\n                    <Item ID=\"0x04C7\"/>\n                    <Item ID=\"0x04C8\"/>\n                    <Item ID=\"0x04C9\"/>\n                    <Item ID=\"0x04CA\"/>\n                    <Item ID=\"0x04CB\"/>\n                    <Item ID=\"0x04CC\"/>\n                    <Item ID=\"0x04CD\"/>\n                    <Item ID=\"0x04CE\"/>\n                    <Item ID=\"0x04CF\"/>\n                    <Item ID=\"0x04D0\"/>\n                    <Item ID=\"0x04D1\"/>\n                    <Item ID=\"0x04D2\"/>\n                    <Item ID=\"0x04D3\"/>\n                    <Item ID=\"0x04D4\"/>\n                    <Item ID=\"0x04D5\"/>\n                    <Item ID=\"0x04D6\"/>\n                    <Item ID=\"0x04D7\"/>\n                    <Item ID=\"0x04D8\"/>\n                    <Item ID=\"0x04D9\"/>\n                    <Item ID=\"0x04DA\"/>\n                    <Item ID=\"0x04DB\"/>\n                    <Item ID=\"0x04DC\"/>\n                    <Item ID=\"0x04DD\"/>\n                    <Item ID=\"0x04DE\"/>\n                    <Item ID=\"0x04DF\"/>\n                    <Item ID=\"0x04E0\"/>\n                    <Item ID=\"0x04E1\"/>\n                </Group>\n                <Group name=\"Parquet\">\n                    <Item ID=\"0x2425\"/>\n                    <Item ID=\"0x2426\"/>\n                    <Item ID=\"0x2427\"/>\n                    <Item ID=\"0x2428\"/>\n                    <Item ID=\"0x2429\"/>\n                    <Item ID=\"0x242a\"/>\n                    <Item ID=\"0x242b\"/>\n                    <Item ID=\"0x242c\"/>\n                    <Item ID=\"0x242d\"/>\n                    <Item ID=\"0x242e\"/>\n                    <Item ID=\"0x242f\"/>\n                    <Item ID=\"0x2430\"/>\n                    <Item ID=\"0x2431\"/>\n                    <Item ID=\"0x2432\"/>\n                    <Item ID=\"0x2434\"/>\n                    <Item ID=\"0x2435\"/>\n                    <Item ID=\"0x2436\"/>\n                    <Item ID=\"0x2437\"/>\n                    <Item ID=\"0x2438\"/>\n                    <Item ID=\"0x2439\"/>\n                    <Item ID=\"0x243A\"/>\n                </Group>\n                <Group name=\"Red-Brown Board\">\n                    <Item ID=\"0x243B\"/>\n                    <Item ID=\"0x243c\"/>\n                    <Item ID=\"0x243d\"/>\n                    <Item ID=\"0x243e\"/>\n                    <Item ID=\"0x243f\"/>\n                    <Item ID=\"0x2440\"/>\n                    <Item ID=\"0x2441\"/>\n                    <Item ID=\"0x2442\"/>\n                    <Item ID=\"0x2443\"/>\n                    <Item ID=\"0x2444\"/>\n                    <Item ID=\"0x2445\"/>\n                    <Item ID=\"0x2446\"/>\n                    <Item ID=\"0x2447\"/>\n                    <Item ID=\"0x2448\"/>\n                    <Item ID=\"0x2449\"/>\n                    <Item ID=\"0x244B\"/>\n                    <Item ID=\"0x244a\"/>\n                    <Item ID=\"0x244c\"/>\n                    <Item ID=\"0x244d\"/>\n                    <Item ID=\"0x244e\"/>\n                    <Item ID=\"0x244f\"/>\n                    <Item ID=\"0x2450\"/>\n                    <Item ID=\"0x2451\"/>\n                    <Item ID=\"0x2452\"/>\n                    <Item ID=\"0x2960\"/>\n                    <Item ID=\"0x2961\"/>\n                    <Item ID=\"0x2962\"/>\n                    <Item ID=\"0x2963\"/>\n                    <Item ID=\"0x2964\"/>\n                    <Item ID=\"0x2965\"/>\n                    <Item ID=\"0x2966\"/>\n                    <Item ID=\"0x2967\"/>\n                    <Item ID=\"0x2968\"/>\n                    <Item ID=\"0x2969\"/>\n                    <Item ID=\"0x296A\"/>\n                    <Item ID=\"0x296B\"/>\n                    <Item ID=\"0x296C\"/>\n                    <Item ID=\"0x296D\"/>\n                    <Item ID=\"0x296E\"/>\n                    <Item ID=\"0x296F\"/>\n                    <Item ID=\"0x2970\"/>\n                    <Item ID=\"0x2971\"/>\n                    <Item ID=\"0x2972\"/>\n                    <Item ID=\"0x2973\"/>\n                    <Item ID=\"0x2974\"/>\n                    <Item ID=\"0x2975\"/>\n                    <Item ID=\"0x2976\"/>\n                    <Item ID=\"0x2977\"/>\n                </Group>\n                <Group name=\"Yellow Board\">\n                    <Item ID=\"0x286e\"/>\n                    <Item ID=\"0x286f\"/>\n                    <Item ID=\"0x2870\"/>\n                    <Item ID=\"0x2871\"/>\n                    <Item ID=\"0x2872\"/>\n                    <Item ID=\"0x2873\"/>\n                    <Item ID=\"0x2874\"/>\n                    <Item ID=\"0x2875\"/>\n                    <Item ID=\"0x2876\"/>\n                    <Item ID=\"0x2877\"/>\n                    <Item ID=\"0x2878\"/>\n                    <Item ID=\"0x2879\"/>\n                    <Item ID=\"0x287a\"/>\n                    <Item ID=\"0x287b\"/>\n                    <Item ID=\"0x287c\"/>\n                    <Item ID=\"0x287d\"/>\n                    <Item ID=\"0x287e\"/>\n                    <Item ID=\"0x287f\"/>\n                    <Item ID=\"0x2880\"/>\n                    <Item ID=\"0x2881\"/>\n                    <Item ID=\"0x2882\"/>\n                    <Item ID=\"0x2883\"/>\n                    <Item ID=\"0x2884\"/>\n                    <Item ID=\"0x2885\"/>\n                </Group>\n            </Group>\n        </Group>\n        <Group name=\"Roofs\">\n            <Group name=\"Organic\">\n                <Group name=\"Bark\">\n                    <Item ID=\"0x26F8\"/>\n                    <Item ID=\"0x26F9\"/>\n                    <Item ID=\"0x26FA\"/>\n                    <Item ID=\"0x26FB\"/>\n                    <Item ID=\"0x26FC\"/>\n                    <Item ID=\"0x26FD\"/>\n                    <Item ID=\"0x26FE\"/>\n                    <Item ID=\"0x26FF\"/>\n                    <Item ID=\"0x2700\"/>\n                    <Item ID=\"0x2701\"/>\n                    <Item ID=\"0x2702\"/>\n                    <Item ID=\"0x2703\"/>\n                    <Item ID=\"0x2704\"/>\n                    <Item ID=\"0x2705\"/>\n                    <Item ID=\"0x2706\"/>\n                    <Item ID=\"0x2707\"/>\n                    <Item ID=\"0x2708\"/>\n                    <Item ID=\"0x2709\"/>\n                    <Item ID=\"0x270A\"/>\n                    <Item ID=\"0x270B\"/>\n                    <Item ID=\"0x270C\"/>\n                </Group>\n                <Group name=\"Blue Tent\">\n                    <Item ID=\"0x05FF\"/>\n                    <Item ID=\"0x0600\"/>\n                    <Item ID=\"0x0601\"/>\n                    <Item ID=\"0x0602\"/>\n                    <Item ID=\"0x0603\"/>\n                    <Item ID=\"0x0604\"/>\n                    <Item ID=\"0x0605\"/>\n                    <Item ID=\"0x0606\"/>\n                    <Item ID=\"0x0607\"/>\n                    <Item ID=\"0x0608\"/>\n                    <Item ID=\"0x0609\"/>\n                    <Item ID=\"0x060A\"/>\n                    <Item ID=\"0x060B\"/>\n                    <Item ID=\"0x060C\"/>\n                    <Item ID=\"0x060D\"/>\n                    <Item ID=\"0x060E\"/>\n                    <Item ID=\"0x060F\"/>\n                    <Item ID=\"0x0610\"/>\n                    <Item ID=\"0x0611\"/>\n                    <Item ID=\"0x0612\"/>\n                    <Item ID=\"0x0613\"/>\n                    <Item ID=\"0x0614\"/>\n                    <Item ID=\"0x0633\"/>\n                    <Item ID=\"0x0634\"/>\n                    <Item ID=\"0x064C\"/>\n                    <Item ID=\"0x064D\"/>\n                    <Item ID=\"0x064E\"/>\n                </Group>\n                <Group name=\"Green Tent\">\n                    <Item ID=\"0x0615\"/>\n                    <Item ID=\"0x0616\"/>\n                    <Item ID=\"0x0617\"/>\n                    <Item ID=\"0x0618\"/>\n                    <Item ID=\"0x0619\"/>\n                    <Item ID=\"0x061A\"/>\n                    <Item ID=\"0x061B\"/>\n                    <Item ID=\"0x061C\"/>\n                    <Item ID=\"0x061D\"/>\n                    <Item ID=\"0x061E\"/>\n                    <Item ID=\"0x061F\"/>\n                    <Item ID=\"0x0620\"/>\n                    <Item ID=\"0x0621\"/>\n                    <Item ID=\"0x0622\"/>\n                    <Item ID=\"0x0623\"/>\n                    <Item ID=\"0x0624\"/>\n                    <Item ID=\"0x0625\"/>\n                    <Item ID=\"0x0626\"/>\n                    <Item ID=\"0x0627\"/>\n                    <Item ID=\"0x0628\"/>\n                    <Item ID=\"0x0629\"/>\n                    <Item ID=\"0x062A\"/>\n                    <Item ID=\"0x0635\"/>\n                    <Item ID=\"0x0636\"/>\n                    <Item ID=\"0x064F\"/>\n                    <Item ID=\"0x0650\"/>\n                    <Item ID=\"0x0651\"/>\n                </Group>\n                <Group name=\"Hay\">\n                    <Item ID=\"0x26DA\"/>\n                    <Item ID=\"0x26DB\"/>\n                    <Item ID=\"0x26DC\"/>\n                    <Item ID=\"0x26DD\"/>\n                    <Item ID=\"0x26DE\"/>\n                    <Item ID=\"0x26DF\"/>\n                    <Item ID=\"0x26E0\"/>\n                    <Item ID=\"0x26E1\"/>\n                    <Item ID=\"0x26E2\"/>\n                    <Item ID=\"0x26E3\"/>\n                    <Item ID=\"0x26E4\"/>\n                    <Item ID=\"0x26E5\"/>\n                    <Item ID=\"0x26E6\"/>\n                    <Item ID=\"0x26E7\"/>\n                    <Item ID=\"0x26E8\"/>\n                    <Item ID=\"0x26E9\"/>\n                    <Item ID=\"0x26EA\"/>\n                    <Item ID=\"0x26EB\"/>\n                    <Item ID=\"0x26EC\"/>\n                </Group>\n                <Group name=\"Leaves\">\n                    <Item ID=\"0x2B94\"/>\n                    <Item ID=\"0x2B95\"/>\n                    <Item ID=\"0x2B96\"/>\n                    <Item ID=\"0x2B97\"/>\n                    <Item ID=\"0x2B98\"/>\n                    <Item ID=\"0x2B99\"/>\n                    <Item ID=\"0x2B9A\"/>\n                    <Item ID=\"0x2B9B\"/>\n                    <Item ID=\"0x2B9C\"/>\n                    <Item ID=\"0x2B9D\"/>\n                    <Item ID=\"0x2B9E\"/>\n                    <Item ID=\"0x2B9F\"/>\n                    <Item ID=\"0x2BA0\"/>\n                    <Item ID=\"0x2BA1\"/>\n                    <Item ID=\"0x2BA2\"/>\n                    <Item ID=\"0x2BA3\"/>\n                    <Item ID=\"0x2BA4\"/>\n                    <Item ID=\"0x2BA5\"/>\n                    <Item ID=\"0x2BA6\"/>\n                    <Item ID=\"0x2BA7\"/>\n                    <Item ID=\"0x2BA8\"/>\n                    <Item ID=\"0x2F24\"/>\n                    <Item ID=\"0x2F25\"/>\n                    <Item ID=\"0x2F26\"/>\n                    <Item ID=\"0x2F27\"/>\n                    <Item ID=\"0x2F28\"/>\n                </Group>\n                <Group name=\"Light Gray Tent\">\n                    <Item ID=\"0x0648\"/>\n                    <Item ID=\"0x0649\"/>\n                    <Item ID=\"0x064A\"/>\n                    <Item ID=\"0x065E\"/>\n                    <Item ID=\"0x065F\"/>\n                    <Item ID=\"0x0660\"/>\n                    <Item ID=\"0x0661\"/>\n                    <Item ID=\"0x0662\"/>\n                    <Item ID=\"0x0663\"/>\n                    <Item ID=\"0x0664\"/>\n                    <Item ID=\"0x0665\"/>\n                    <Item ID=\"0x0666\"/>\n                    <Item ID=\"0x0667\"/>\n                    <Item ID=\"0x0668\"/>\n                    <Item ID=\"0x0669\"/>\n                    <Item ID=\"0x066A\"/>\n                    <Item ID=\"0x066B\"/>\n                    <Item ID=\"0x066C\"/>\n                    <Item ID=\"0x066D\"/>\n                    <Item ID=\"0x066E\"/>\n                    <Item ID=\"0x066F\"/>\n                    <Item ID=\"0x0670\"/>\n                    <Item ID=\"0x0671\"/>\n                    <Item ID=\"0x0672\"/>\n                    <Item ID=\"0x0673\"/>\n                    <Item ID=\"0x0674\"/>\n                </Group>\n                <Group name=\"Palm\">\n                    <Group name=\"Round Palm Roof\">\n                        <Item ID=\"0x05d1\"/>\n                        <Item ID=\"0x05d2\"/>\n                        <Item ID=\"0x05d3\"/>\n                        <Item ID=\"0x05d4\"/>\n                        <Item ID=\"0x05d6\"/>\n                        <Item ID=\"0x05d7\"/>\n                        <Item ID=\"0x05d8\"/>\n                        <Item ID=\"0x05d9\"/>\n                        <Item ID=\"0x05da\"/>\n                        <Item ID=\"0x05db\"/>\n                        <Item ID=\"0x05dc\"/>\n                        <Item ID=\"0x05dd\"/>\n                        <Item ID=\"0x05de\"/>\n                        <Item ID=\"0x05df\"/>\n                        <Item ID=\"0x05e0\"/>\n                        <Item ID=\"0x05e1\"/>\n                        <Item ID=\"0x05e2\"/>\n                        <Item ID=\"0x05e3\"/>\n                        <Item ID=\"0x05e4\"/>\n                        <Item ID=\"0x05e5\"/>\n                        <Item ID=\"0x05e6\"/>\n                        <Item ID=\"0x05e7\"/>\n                        <Item ID=\"0x05e8\"/>\n                        <Item ID=\"0x05e9\"/>\n                        <Item ID=\"0x05ea\"/>\n                        <Item ID=\"0x05eb\"/>\n                        <Item ID=\"0x05ec\"/>\n                    </Group>\n                    <Item ID=\"0x0586\"/>\n                    <Item ID=\"0x0587\"/>\n                    <Item ID=\"0x0588\"/>\n                    <Item ID=\"0x0589\"/>\n                    <Item ID=\"0x058A\"/>\n                    <Item ID=\"0x058B\"/>\n                    <Item ID=\"0x058C\"/>\n                    <Item ID=\"0x058D\"/>\n                    <Item ID=\"0x058E\"/>\n                    <Item ID=\"0x058F\"/>\n                    <Item ID=\"0x0590\"/>\n                    <Item ID=\"0x0591\"/>\n                    <Item ID=\"0x0592\"/>\n                    <Item ID=\"0x0593\"/>\n                    <Item ID=\"0x0594\"/>\n                    <Item ID=\"0x2180\"/>\n                    <Item ID=\"0x2181\"/>\n                    <Item ID=\"0x2182\"/>\n                    <Item ID=\"0x2183\"/>\n                    <Item ID=\"0x2184\"/>\n                    <Item ID=\"0x2185\"/>\n                    <Item ID=\"0x2186\"/>\n                    <Item ID=\"0x2187\"/>\n                    <Item ID=\"0x2c60\"/>\n                    <Item ID=\"0x2c61\"/>\n                    <Item ID=\"0x2c62\"/>\n                    <Item ID=\"0x2c63\"/>\n                    <Item ID=\"0x2c64\"/>\n                    <Item ID=\"0x2c65\"/>\n                    <Item ID=\"0x2c66\"/>\n                    <Item ID=\"0x2c67\"/>\n                    <Item ID=\"0x2c68\"/>\n                    <Item ID=\"0x2c69\"/>\n                    <Item ID=\"0x2c6a\"/>\n                    <Item ID=\"0x2c6b\"/>\n                    <Item ID=\"0x2c6c\"/>\n                    <Item ID=\"0x2c6d\"/>\n                    <Item ID=\"0x2c6e\"/>\n                </Group>\n                <Group name=\"Thatch\">\n                    <Item ID=\"0x05A4\"/>\n                    <Item ID=\"0x05A5\"/>\n                    <Item ID=\"0x05A6\"/>\n                    <Item ID=\"0x05A7\"/>\n                    <Item ID=\"0x05A8\"/>\n                    <Item ID=\"0x05A9\"/>\n                    <Item ID=\"0x05AA\"/>\n                    <Item ID=\"0x05AB\"/>\n                    <Item ID=\"0x05AC\"/>\n                    <Item ID=\"0x05AD\"/>\n                    <Item ID=\"0x05AE\"/>\n                    <Item ID=\"0x05AF\"/>\n                    <Item ID=\"0x05B0\"/>\n                    <Item ID=\"0x05B1\"/>\n                    <Item ID=\"0x05B2\"/>\n                    <Item ID=\"0x2148\"/>\n                    <Item ID=\"0x2149\"/>\n                    <Item ID=\"0x214a\"/>\n                    <Item ID=\"0x214b\"/>\n                    <Item ID=\"0x214c\"/>\n                    <Item ID=\"0x214d\"/>\n                    <Item ID=\"0x214e\"/>\n                    <Item ID=\"0x214f\"/>\n                    <Item ID=\"0x2c51\"/>\n                    <Item ID=\"0x2c52\"/>\n                    <Item ID=\"0x2c53\"/>\n                    <Item ID=\"0x2c54\"/>\n                    <Item ID=\"0x2c55\"/>\n                    <Item ID=\"0x2c56\"/>\n                    <Item ID=\"0x2c57\"/>\n                    <Item ID=\"0x2c58\"/>\n                    <Item ID=\"0x2c59\"/>\n                    <Item ID=\"0x2c5a\"/>\n                    <Item ID=\"0x2c5b\"/>\n                    <Item ID=\"0x2c5c\"/>\n                    <Item ID=\"0x2c5d\"/>\n                    <Item ID=\"0x2c5e\"/>\n                    <Item ID=\"0x2c5f\"/>\n                </Group>\n            </Group>\n            <Group name=\"Stone, Clay, Ceramic\">\n                <Group name=\"Black Ceramic\">\n                    <Item ID=\"0x23BE\"/>\n                    <Item ID=\"0x23BF\"/>\n                    <Item ID=\"0x23C0\"/>\n                    <Item ID=\"0x23C1\"/>\n                    <Item ID=\"0x23C2\"/>\n                    <Item ID=\"0x23C3\"/>\n                    <Item ID=\"0x23C4\"/>\n                    <Item ID=\"0x23C5\"/>\n                    <Item ID=\"0x23C6\"/>\n                    <Item ID=\"0x23C7\"/>\n                    <Item ID=\"0x23C8\"/>\n                    <Item ID=\"0x23C9\"/>\n                    <Item ID=\"0x23CA\"/>\n                    <Item ID=\"0x23CB\"/>\n                    <Item ID=\"0x23CC\"/>\n                    <Item ID=\"0x23CD\"/>\n                    <Item ID=\"0x23CE\"/>\n                    <Item ID=\"0x23CF\"/>\n                    <Item ID=\"0x23D0\"/>\n                    <Item ID=\"0x23D1\"/>\n                    <Item ID=\"0x23D2\"/>\n                    <Item ID=\"0x23D3\"/>\n                </Group>\n                <Group name=\"Clay Shingle\">\n                    <Item ID=\"0x05B3\"/>\n                    <Item ID=\"0x05B4\"/>\n                    <Item ID=\"0x05B5\"/>\n                    <Item ID=\"0x05B6\"/>\n                    <Item ID=\"0x05B7\"/>\n                    <Item ID=\"0x05B8\"/>\n                    <Item ID=\"0x05B9\"/>\n                    <Item ID=\"0x05BA\"/>\n                    <Item ID=\"0x05BB\"/>\n                    <Item ID=\"0x05BC\"/>\n                    <Item ID=\"0x05BD\"/>\n                    <Item ID=\"0x05BE\"/>\n                    <Item ID=\"0x05BF\"/>\n                    <Item ID=\"0x05C0\"/>\n                    <Item ID=\"0x05C1\"/>\n                    <Item ID=\"0x06fd\"/>\n                    <Item ID=\"0x06fe\"/>\n                    <Item ID=\"0x06ff\"/>\n                    <Item ID=\"0x0700\"/>\n                    <Item ID=\"0x21e9\"/>\n                    <Item ID=\"0x21ea\"/>\n                    <Item ID=\"0x21eb\"/>\n                    <Item ID=\"0x21ec\"/>\n                    <Item ID=\"0x21ed\"/>\n                    <Item ID=\"0x21ee\"/>\n                    <Item ID=\"0x21ef\"/>\n                    <Item ID=\"0x21f0\"/>\n                    <Item ID=\"0x2c24\"/>\n                    <Item ID=\"0x2c25\"/>\n                    <Item ID=\"0x2c26\"/>\n                    <Item ID=\"0x2c27\"/>\n                    <Item ID=\"0x2c28\"/>\n                    <Item ID=\"0x2c29\"/>\n                    <Item ID=\"0x2c2a\"/>\n                    <Item ID=\"0x2c2b\"/>\n                    <Item ID=\"0x2c2c\"/>\n                    <Item ID=\"0x2c2d\"/>\n                    <Item ID=\"0x2c2e\"/>\n                    <Item ID=\"0x2c2f\"/>\n                    <Item ID=\"0x2c30\"/>\n                    <Item ID=\"0x2c31\"/>\n                    <Item ID=\"0x2c32\"/>\n                </Group>\n                <Group name=\"Crystal Roof\">\n                    <Item ID=\"0x35BE\"/>\n                    <Item ID=\"0x35BF\"/>\n                    <Item ID=\"0x35C0\"/>\n                    <Item ID=\"0x35C1\"/>\n                    <Item ID=\"0x35C2\"/>\n                    <Item ID=\"0x35C3\"/>\n                    <Item ID=\"0x35C4\"/>\n                    <Item ID=\"0x35C5\"/>\n                    <Item ID=\"0x35C6\"/>\n                    <Item ID=\"0x35C7\"/>\n                    <Item ID=\"0x35C8\"/>\n                    <Item ID=\"0x35C9\"/>\n                    <Item ID=\"0x35CA\"/>\n                    <Item ID=\"0x35CB\"/>\n                    <Item ID=\"0x35CC\"/>\n                    <Item ID=\"0x35CD\"/>\n                    <Item ID=\"0x35CE\"/>\n                    <Item ID=\"0x35CF\"/>\n                    <Item ID=\"0x35D0\"/>\n                    <Item ID=\"0x35D1\"/>\n                </Group>\n                <Group name=\"Flat\">\n                    <Group name=\"Blueish Stone\">\n                        <Item ID=\"0x063b\"/>\n                        <Item ID=\"0x063c\"/>\n                        <Item ID=\"0x063d\"/>\n                        <Item ID=\"0x063e\"/>\n                        <Item ID=\"0x0652\"/>\n                        <Item ID=\"0x0653\"/>\n                    </Group>\n                    <Group name=\"Gray Stone\">\n                        <Item ID=\"0x0579\"/>\n                        <Item ID=\"0x057a\"/>\n                        <Item ID=\"0x057b\"/>\n                        <Item ID=\"0x057c\"/>\n                        <Item ID=\"0x057d\"/>\n                        <Item ID=\"0x057e\"/>\n                    </Group>\n                    <Group name=\"Red Stone\">\n                        <Item ID=\"0x0554\"/>\n                        <Item ID=\"0x0555\"/>\n                        <Item ID=\"0x0556\"/>\n                        <Item ID=\"0x0557\"/>\n                        <Item ID=\"0x055C\"/>\n                        <Item ID=\"0x055d\"/>\n                        <Item ID=\"0x055e\"/>\n                        <Item ID=\"0x055f\"/>\n                        <Item ID=\"0x0560\"/>\n                        <Item ID=\"0x0561\"/>\n                        <Item ID=\"0x0562\"/>\n                        <Item ID=\"0x0563\"/>\n                        <Item ID=\"0x0564\"/>\n                        <Item ID=\"0x0565\"/>\n                        <Item ID=\"0x0566\"/>\n                        <Item ID=\"0x0567\"/>\n                        <Item ID=\"0x0568\"/>\n                        <Item ID=\"0x0569\"/>\n                        <Item ID=\"0x062f\"/>\n                        <Item ID=\"0x0630\"/>\n                        <Item ID=\"0x0631\"/>\n                        <Item ID=\"0x0631\"/>\n                        <Item ID=\"0x0632\"/>\n                        <Item ID=\"0x0632\"/>\n                        <Item ID=\"0x0656\"/>\n                        <Item ID=\"0x0657\"/>\n                    </Group>\n                    <Group name=\"Slate\">\n                        <Item ID=\"0x057F\"/>\n                        <Item ID=\"0x0580\"/>\n                        <Item ID=\"0x0581\"/>\n                        <Item ID=\"0x0582\"/>\n                        <Item ID=\"0x0583\"/>\n                        <Item ID=\"0x0584\"/>\n                        <Item ID=\"0x0585\"/>\n                        <Item ID=\"0x0658\"/>\n                        <Item ID=\"0x0659\"/>\n                    </Group>\n                    <Group name=\"White Stone\">\n                        <Item ID=\"0x0550\"/>\n                        <Item ID=\"0x0558\"/>\n                        <Item ID=\"0x0559\"/>\n                        <Item ID=\"0x055A\"/>\n                        <Item ID=\"0x055B\"/>\n                        <Item ID=\"0x055a\"/>\n                        <Item ID=\"0x055b\"/>\n                        <Item ID=\"0x056B\"/>\n                        <Item ID=\"0x056C\"/>\n                        <Item ID=\"0x056D\"/>\n                        <Item ID=\"0x056E\"/>\n                        <Item ID=\"0x056F\"/>\n                        <Item ID=\"0x0570\"/>\n                        <Item ID=\"0x0571\"/>\n                        <Item ID=\"0x0572\"/>\n                        <Item ID=\"0x0573\"/>\n                        <Item ID=\"0x0574\"/>\n                        <Item ID=\"0x0575\"/>\n                        <Item ID=\"0x0576\"/>\n                        <Item ID=\"0x0577\"/>\n                        <Item ID=\"0x05ef\"/>\n                        <Item ID=\"0x062D\"/>\n                        <Item ID=\"0x062E\"/>\n                        <Item ID=\"0x062b\"/>\n                        <Item ID=\"0x062c\"/>\n                        <Item ID=\"0x062d\"/>\n                        <Item ID=\"0x062e\"/>\n                        <Item ID=\"0x0637\"/>\n                        <Item ID=\"0x0638\"/>\n                        <Item ID=\"0x0639\"/>\n                        <Item ID=\"0x063a\"/>\n                        <Item ID=\"0x065a\"/>\n                        <Item ID=\"0x065b\"/>\n                        <Item ID=\"0x065c\"/>\n                        <Item ID=\"0x065d\"/>\n                    </Group>\n                </Group>\n                <Group name=\"Green Ceramic\">\n                    <Item ID=\"0x23EA\"/>\n                    <Item ID=\"0x23EB\"/>\n                    <Item ID=\"0x23EC\"/>\n                    <Item ID=\"0x23ED\"/>\n                    <Item ID=\"0x23EE\"/>\n                    <Item ID=\"0x23EF\"/>\n                    <Item ID=\"0x23F0\"/>\n                    <Item ID=\"0x23F1\"/>\n                    <Item ID=\"0x23F2\"/>\n                    <Item ID=\"0x23F3\"/>\n                    <Item ID=\"0x23F4\"/>\n                    <Item ID=\"0x23F5\"/>\n                    <Item ID=\"0x23F6\"/>\n                    <Item ID=\"0x23F7\"/>\n                    <Item ID=\"0x23F8\"/>\n                    <Item ID=\"0x23F9\"/>\n                    <Item ID=\"0x23FA\"/>\n                    <Item ID=\"0x23FB\"/>\n                    <Item ID=\"0x23FC\"/>\n                    <Item ID=\"0x23FD\"/>\n                    <Item ID=\"0x23FE\"/>\n                    <Item ID=\"0x23FF\"/>\n                </Group>\n                <Group name=\"Orange Ceramic\">\n                    <Item ID=\"0x2920\"/>\n                    <Item ID=\"0x2921\"/>\n                    <Item ID=\"0x2922\"/>\n                    <Item ID=\"0x2923\"/>\n                    <Item ID=\"0x2924\"/>\n                    <Item ID=\"0x2925\"/>\n                    <Item ID=\"0x2926\"/>\n                    <Item ID=\"0x2927\"/>\n                    <Item ID=\"0x2928\"/>\n                    <Item ID=\"0x2929\"/>\n                    <Item ID=\"0x292A\"/>\n                    <Item ID=\"0x292B\"/>\n                    <Item ID=\"0x292C\"/>\n                    <Item ID=\"0x292D\"/>\n                    <Item ID=\"0x292E\"/>\n                    <Item ID=\"0x292F\"/>\n                    <Item ID=\"0x2930\"/>\n                    <Item ID=\"0x2931\"/>\n                    <Item ID=\"0x2932\"/>\n                    <Item ID=\"0x2933\"/>\n                    <Item ID=\"0x2934\"/>\n                    <Item ID=\"0x2935\"/>\n                </Group>\n                <Group name=\"Red Ceramic\">\n                    <Item ID=\"0x23D4\"/>\n                    <Item ID=\"0x23D5\"/>\n                    <Item ID=\"0x23D6\"/>\n                    <Item ID=\"0x23D7\"/>\n                    <Item ID=\"0x23D8\"/>\n                    <Item ID=\"0x23D9\"/>\n                    <Item ID=\"0x23DA\"/>\n                    <Item ID=\"0x23DB\"/>\n                    <Item ID=\"0x23DC\"/>\n                    <Item ID=\"0x23DD\"/>\n                    <Item ID=\"0x23DE\"/>\n                    <Item ID=\"0x23DF\"/>\n                    <Item ID=\"0x23E0\"/>\n                    <Item ID=\"0x23E1\"/>\n                    <Item ID=\"0x23E2\"/>\n                    <Item ID=\"0x23E3\"/>\n                    <Item ID=\"0x23E4\"/>\n                    <Item ID=\"0x23E5\"/>\n                    <Item ID=\"0x23E6\"/>\n                    <Item ID=\"0x23E7\"/>\n                    <Item ID=\"0x23E8\"/>\n                    <Item ID=\"0x23E9\"/>\n                </Group>\n                <Group name=\"Slate\">\n                    <Item ID=\"0x0595\"/>\n                    <Item ID=\"0x0596\"/>\n                    <Item ID=\"0x0597\"/>\n                    <Item ID=\"0x0598\"/>\n                    <Item ID=\"0x0599\"/>\n                    <Item ID=\"0x059A\"/>\n                    <Item ID=\"0x059B\"/>\n                    <Item ID=\"0x059C\"/>\n                    <Item ID=\"0x059D\"/>\n                    <Item ID=\"0x059E\"/>\n                    <Item ID=\"0x059F\"/>\n                    <Item ID=\"0x05A0\"/>\n                    <Item ID=\"0x05A1\"/>\n                    <Item ID=\"0x05A2\"/>\n                    <Item ID=\"0x05A3\"/>\n                    <Item ID=\"0x2178\"/>\n                    <Item ID=\"0x2179\"/>\n                    <Item ID=\"0x217a\"/>\n                    <Item ID=\"0x217b\"/>\n                    <Item ID=\"0x217c\"/>\n                    <Item ID=\"0x217d\"/>\n                    <Item ID=\"0x217e\"/>\n                    <Item ID=\"0x217f\"/>\n                    <Item ID=\"0x2c6f\"/>\n                    <Item ID=\"0x2c70\"/>\n                    <Item ID=\"0x2c71\"/>\n                    <Item ID=\"0x2c72\"/>\n                    <Item ID=\"0x2c73\"/>\n                    <Item ID=\"0x2c74\"/>\n                    <Item ID=\"0x2c75\"/>\n                    <Item ID=\"0x2c76\"/>\n                    <Item ID=\"0x2c77\"/>\n                    <Item ID=\"0x2c78\"/>\n                    <Item ID=\"0x2c79\"/>\n                    <Item ID=\"0x2c7a\"/>\n                    <Item ID=\"0x2c7b\"/>\n                    <Item ID=\"0x2c7c\"/>\n                    <Item ID=\"0x2c7d\"/>\n                </Group>\n                <Group name=\"Stone Shingle\">\n                    <Item ID=\"0x28B0\"/>\n                    <Item ID=\"0x28B1\"/>\n                    <Item ID=\"0x28B2\"/>\n                    <Item ID=\"0x28B3\"/>\n                    <Item ID=\"0x28B4\"/>\n                    <Item ID=\"0x28B5\"/>\n                    <Item ID=\"0x28B6\"/>\n                    <Item ID=\"0x28B7\"/>\n                    <Item ID=\"0x28B8\"/>\n                    <Item ID=\"0x28B9\"/>\n                    <Item ID=\"0x28BA\"/>\n                    <Item ID=\"0x28BB\"/>\n                    <Item ID=\"0x28BC\"/>\n                    <Item ID=\"0x28BD\"/>\n                    <Item ID=\"0x28BE\"/>\n                    <Item ID=\"0x28BF\"/>\n                    <Item ID=\"0x28C0\"/>\n                    <Item ID=\"0x28C1\"/>\n                    <Item ID=\"0x28C2\"/>\n                    <Item ID=\"0x28C3\"/>\n                    <Item ID=\"0x28C4\"/>\n                    <Item ID=\"0x28C5\"/>\n                    <Item ID=\"0x28EB\"/>\n                    <Item ID=\"0x28EC\"/>\n                    <Item ID=\"0x28ED\"/>\n                    <Item ID=\"0x28EE\"/>\n                    <Item ID=\"0x2A2B\"/>\n                    <Item ID=\"0x2A2C\"/>\n                    <Item ID=\"0x2A2D\"/>\n                    <Item ID=\"0x2A2E\"/>\n                </Group>\n                <Group name=\"Stone Tile\">\n                    <Item ID=\"0x1939\"/>\n                    <Item ID=\"0x193a\"/>\n                    <Item ID=\"0x193b\"/>\n                    <Item ID=\"0x193c\"/>\n                    <Item ID=\"0x193d\"/>\n                    <Item ID=\"0x193e\"/>\n                </Group>\n                <Group name=\"White Ceramic\">\n                    <Item ID=\"0x2906\"/>\n                    <Item ID=\"0x2907\"/>\n                    <Item ID=\"0x2908\"/>\n                    <Item ID=\"0x2909\"/>\n                    <Item ID=\"0x290A\"/>\n                    <Item ID=\"0x290B\"/>\n                    <Item ID=\"0x290C\"/>\n                    <Item ID=\"0x290D\"/>\n                    <Item ID=\"0x290E\"/>\n                    <Item ID=\"0x290F\"/>\n                    <Item ID=\"0x2910\"/>\n                    <Item ID=\"0x2911\"/>\n                    <Item ID=\"0x2912\"/>\n                    <Item ID=\"0x2913\"/>\n                    <Item ID=\"0x2914\"/>\n                    <Item ID=\"0x2915\"/>\n                    <Item ID=\"0x2916\"/>\n                    <Item ID=\"0x2917\"/>\n                    <Item ID=\"0x2918\"/>\n                    <Item ID=\"0x2919\"/>\n                    <Item ID=\"0x291A\"/>\n                    <Item ID=\"0x291B\"/>\n                </Group>\n                <Group name=\"Yellow Ceramic\">\n                    <Item ID=\"0x28F0\"/>\n                    <Item ID=\"0x28F1\"/>\n                    <Item ID=\"0x28F2\"/>\n                    <Item ID=\"0x28F3\"/>\n                    <Item ID=\"0x28F4\"/>\n                    <Item ID=\"0x28F5\"/>\n                    <Item ID=\"0x28F6\"/>\n                    <Item ID=\"0x28F7\"/>\n                    <Item ID=\"0x28F8\"/>\n                    <Item ID=\"0x28F9\"/>\n                    <Item ID=\"0x28FA\"/>\n                    <Item ID=\"0x28FB\"/>\n                    <Item ID=\"0x28FC\"/>\n                    <Item ID=\"0x28FD\"/>\n                    <Item ID=\"0x28FE\"/>\n                    <Item ID=\"0x28FF\"/>\n                    <Item ID=\"0x2900\"/>\n                    <Item ID=\"0x2901\"/>\n                    <Item ID=\"0x2902\"/>\n                    <Item ID=\"0x2903\"/>\n                    <Item ID=\"0x2904\"/>\n                    <Item ID=\"0x2905\"/>\n                </Group>\n            </Group>\n            <Group name=\"Wood\">\n                <Group name=\"Brown Log\">\n                    <Item ID=\"0x05F0\"/>\n                    <Item ID=\"0x05F1\"/>\n                    <Item ID=\"0x05F2\"/>\n                    <Item ID=\"0x05F3\"/>\n                    <Item ID=\"0x05F4\"/>\n                    <Item ID=\"0x05F5\"/>\n                    <Item ID=\"0x05F6\"/>\n                    <Item ID=\"0x05F7\"/>\n                    <Item ID=\"0x05F8\"/>\n                    <Item ID=\"0x05F9\"/>\n                    <Item ID=\"0x05FA\"/>\n                    <Item ID=\"0x05FB\"/>\n                    <Item ID=\"0x05FC\"/>\n                    <Item ID=\"0x05FD\"/>\n                    <Item ID=\"0x05FE\"/>\n                    <Item ID=\"0x2c42\"/>\n                    <Item ID=\"0x2c43\"/>\n                    <Item ID=\"0x2c44\"/>\n                    <Item ID=\"0x2c45\"/>\n                    <Item ID=\"0x2c46\"/>\n                    <Item ID=\"0x2c47\"/>\n                    <Item ID=\"0x2c48\"/>\n                    <Item ID=\"0x2c49\"/>\n                    <Item ID=\"0x2c4a\"/>\n                    <Item ID=\"0x2c4b\"/>\n                    <Item ID=\"0x2c4c\"/>\n                    <Item ID=\"0x2c4d\"/>\n                    <Item ID=\"0x2c4e\"/>\n                    <Item ID=\"0x2c4f\"/>\n                    <Item ID=\"0x2c50\"/>\n                </Group>\n                <Group name=\"Diamond Shingles\">\n                    <Item ID=\"0x2B82\"/>\n                    <Item ID=\"0x2B83\"/>\n                    <Item ID=\"0x2B84\"/>\n                    <Item ID=\"0x2B85\"/>\n                    <Item ID=\"0x2B86\"/>\n                    <Item ID=\"0x2B87\"/>\n                    <Item ID=\"0x2B88\"/>\n                    <Item ID=\"0x2B89\"/>\n                    <Item ID=\"0x2B8A\"/>\n                    <Item ID=\"0x2B8B\"/>\n                    <Item ID=\"0x2B8C\"/>\n                    <Item ID=\"0x2B8D\"/>\n                    <Item ID=\"0x2B8E\"/>\n                    <Item ID=\"0x2B8F\"/>\n                    <Item ID=\"0x2B90\"/>\n                    <Item ID=\"0x2B91\"/>\n                    <Item ID=\"0x2B92\"/>\n                    <Item ID=\"0x2B93\"/>\n                    <Item ID=\"0x2F1F\"/>\n                    <Item ID=\"0x2F20\"/>\n                    <Item ID=\"0x2F21\"/>\n                    <Item ID=\"0x2F22\"/>\n                    <Item ID=\"0x2F23\"/>\n                    <Item ID=\"0x2b81\"/>\n                </Group>\n                <Group name=\"Grey Log\">\n                    <Item ID=\"0x3623\"/>\n                    <Item ID=\"0x3624\"/>\n                    <Item ID=\"0x3625\"/>\n                    <Item ID=\"0x3626\"/>\n                    <Item ID=\"0x3627\"/>\n                    <Item ID=\"0x3628\"/>\n                    <Item ID=\"0x3629\"/>\n                    <Item ID=\"0x362A\"/>\n                    <Item ID=\"0x362B\"/>\n                    <Item ID=\"0x362C\"/>\n                    <Item ID=\"0x362D\"/>\n                    <Item ID=\"0x362E\"/>\n                    <Item ID=\"0x362F\"/>\n                    <Item ID=\"0x3630\"/>\n                    <Item ID=\"0x3631\"/>\n                    <Item ID=\"0x3632\"/>\n                    <Item ID=\"0x3633\"/>\n                    <Item ID=\"0x3634\"/>\n                    <Item ID=\"0x3635\"/>\n                </Group>\n                <Group name=\"Wood Slat\">\n                    <Item ID=\"0x28C6\"/>\n                    <Item ID=\"0x28C7\"/>\n                    <Item ID=\"0x28C8\"/>\n                    <Item ID=\"0x28C9\"/>\n                    <Item ID=\"0x28CA\"/>\n                    <Item ID=\"0x28CB\"/>\n                    <Item ID=\"0x28CC\"/>\n                    <Item ID=\"0x28CD\"/>\n                    <Item ID=\"0x28CE\"/>\n                    <Item ID=\"0x28CF\"/>\n                    <Item ID=\"0x28D0\"/>\n                    <Item ID=\"0x28D1\"/>\n                    <Item ID=\"0x28D2\"/>\n                    <Item ID=\"0x28D3\"/>\n                    <Item ID=\"0x28D4\"/>\n                    <Item ID=\"0x28D5\"/>\n                    <Item ID=\"0x28D6\"/>\n                    <Item ID=\"0x28D7\"/>\n                    <Item ID=\"0x28D8\"/>\n                    <Item ID=\"0x28D9\"/>\n                    <Item ID=\"0x28DA\"/>\n                    <Item ID=\"0x28DB\"/>\n                    <Item ID=\"0x28E4\"/>\n                    <Item ID=\"0x28E5\"/>\n                    <Item ID=\"0x28E6\"/>\n                    <Item ID=\"0x28E7\"/>\n                    <Item ID=\"0x28E8\"/>\n                    <Item ID=\"0x28E9\"/>\n                    <Item ID=\"0x28EA\"/>\n                </Group>\n                <Group name=\"Wooden Shingle\">\n                    <Item ID=\"0x05C2\"/>\n                    <Item ID=\"0x05C3\"/>\n                    <Item ID=\"0x05C4\"/>\n                    <Item ID=\"0x05C5\"/>\n                    <Item ID=\"0x05C6\"/>\n                    <Item ID=\"0x05C7\"/>\n                    <Item ID=\"0x05C8\"/>\n                    <Item ID=\"0x05C9\"/>\n                    <Item ID=\"0x05CA\"/>\n                    <Item ID=\"0x05CB\"/>\n                    <Item ID=\"0x05CC\"/>\n                    <Item ID=\"0x05CD\"/>\n                    <Item ID=\"0x05CE\"/>\n                    <Item ID=\"0x05CF\"/>\n                    <Item ID=\"0x05D0\"/>\n                    <Item ID=\"0x2170\"/>\n                    <Item ID=\"0x2171\"/>\n                    <Item ID=\"0x2172\"/>\n                    <Item ID=\"0x2173\"/>\n                    <Item ID=\"0x2174\"/>\n                    <Item ID=\"0x2175\"/>\n                    <Item ID=\"0x2176\"/>\n                    <Item ID=\"0x2177\"/>\n                    <Item ID=\"0x2c33\"/>\n                    <Item ID=\"0x2c34\"/>\n                    <Item ID=\"0x2c35\"/>\n                    <Item ID=\"0x2c36\"/>\n                    <Item ID=\"0x2c37\"/>\n                    <Item ID=\"0x2c38\"/>\n                    <Item ID=\"0x2c39\"/>\n                    <Item ID=\"0x2c3a\"/>\n                    <Item ID=\"0x2c3b\"/>\n                    <Item ID=\"0x2c3c\"/>\n                    <Item ID=\"0x2c3d\"/>\n                    <Item ID=\"0x2c3e\"/>\n                    <Item ID=\"0x2c3f\"/>\n                    <Item ID=\"0x2c40\"/>\n                    <Item ID=\"0x2c41\"/>\n                </Group>\n            </Group>\n        </Group>\n        <Group name=\"Stairs + Rails\">\n            <Group name=\"Ladders etc.\">\n                <Group name=\"Ladder\">\n                    <Item ID=\"0x0899\"/>\n                    <Item ID=\"0x089A\"/>\n                    <Item ID=\"0x089B\"/>\n                    <Item ID=\"0x089C\"/>\n                    <Item ID=\"0x089D\"/>\n                    <Item ID=\"0x089E\"/>\n                    <Item ID=\"0x089F\"/>\n                    <Item ID=\"0x08A0\"/>\n                    <Item ID=\"0x08A1\"/>\n                    <Item ID=\"0x08A2\"/>\n                    <Item ID=\"0x08A3\"/>\n                    <Item ID=\"0x08A4\"/>\n                    <Item ID=\"0x08A5\"/>\n                    <Item ID=\"0x08A6\"/>\n                    <Item ID=\"0x2FDE\"/>\n                    <Item ID=\"0x2FDF\"/>\n                    <Item ID=\"0x3db2\"/>\n                    <Item ID=\"0x3db3\"/>\n                    <Item ID=\"0x3db4\"/>\n                    <Item ID=\"0x3db5\"/>\n                </Group>\n            </Group>\n            <Group name=\"Platform\">\n                <Item ID=\"0x07BD\"/>\n                <Item ID=\"0x07BE\"/>\n                <Item ID=\"0x07BF\"/>\n                <Item ID=\"0x07C0\"/>\n                <Item ID=\"0x07C1\"/>\n                <Item ID=\"0x07C2\"/>\n                <Item ID=\"0x07C3\"/>\n                <Item ID=\"0x07C4\"/>\n                <Item ID=\"0x07C5\"/>\n                <Item ID=\"0x07C6\"/>\n                <Item ID=\"0x07C9\"/>\n                <Item ID=\"0x07CA\"/>\n                <Item ID=\"0x07CB\"/>\n                <Item ID=\"0x07CC\"/>\n                <Item ID=\"0x07CD\"/>\n                <Item ID=\"0x07CE\"/>\n                <Item ID=\"0x07CF\"/>\n                <Item ID=\"0x07D0\"/>\n                <Item ID=\"0x0915\"/>\n                <Item ID=\"0x0916\"/>\n                <Item ID=\"0x0917\"/>\n                <Item ID=\"0x0918\"/>\n                <Item ID=\"0x3651\"/>\n                <Item ID=\"0x3652\"/>\n                <Item ID=\"0x3653\"/>\n                <Item ID=\"0x3654\"/>\n                <Item ID=\"0x3655\"/>\n                <Item ID=\"0x3656\"/>\n            </Group>\n            <Group name=\"Rails + Banister\">\n                <Group name=\"Edging\">\n                    <Item ID=\"0x08CB\"/>\n                    <Item ID=\"0x08CC\"/>\n                    <Item ID=\"0x08CD\"/>\n                    <Item ID=\"0x08CE\"/>\n                </Group>\n                <Group name=\"Stone Rail\">\n                    <Item ID=\"0x07D7\"/>\n                    <Item ID=\"0x07D8\"/>\n                    <Item ID=\"0x08EB\"/>\n                    <Item ID=\"0x08EC\"/>\n                    <Item ID=\"0x08ED\"/>\n                    <Item ID=\"0x08EE\"/>\n                    <Item ID=\"0x08EF\"/>\n                    <Item ID=\"0x08F0\"/>\n                    <Item ID=\"0x08F1\"/>\n                    <Item ID=\"0x08F2\"/>\n                    <Item ID=\"0x08F3\"/>\n                    <Item ID=\"0x08F4\"/>\n                    <Item ID=\"0x08F5\"/>\n                    <Item ID=\"0x08F6\"/>\n                    <Item ID=\"0x08F7\"/>\n                    <Item ID=\"0x08F8\"/>\n                    <Item ID=\"0x08F9\"/>\n                    <Item ID=\"0x08FA\"/>\n                    <Item ID=\"0x08FB\"/>\n                    <Item ID=\"0x08FC\"/>\n                    <Item ID=\"0x207d\"/>\n                </Group>\n                <Group name=\"Suspension Bridge\">\n                    <Item ID=\"0x07E1\"/>\n                    <Item ID=\"0x07E2\"/>\n                    <Item ID=\"0x07E3\"/>\n                    <Item ID=\"0x07E4\"/>\n                    <Item ID=\"0x07E5\"/>\n                    <Item ID=\"0x07E6\"/>\n                    <Item ID=\"0x07E7\"/>\n                    <Item ID=\"0x07E8\"/>\n                    <Item ID=\"0x07E9\"/>\n                    <Item ID=\"0x07EA\"/>\n                    <Item ID=\"0x07EB\"/>\n                    <Item ID=\"0x07EC\"/>\n                    <Item ID=\"0x07ED\"/>\n                    <Item ID=\"0x07EE\"/>\n                    <Item ID=\"0x07EF\"/>\n                    <Item ID=\"0x07F0\"/>\n                    <Item ID=\"0x07F1\"/>\n                    <Item ID=\"0x07F2\"/>\n                    <Item ID=\"0x07F3\"/>\n                    <Item ID=\"0x07F4\"/>\n                    <Item ID=\"0x07F5\"/>\n                    <Item ID=\"0x07F6\"/>\n                    <Item ID=\"0x07F7\"/>\n                    <Item ID=\"0x07F8\"/>\n                    <Item ID=\"0x07F9\"/>\n                    <Item ID=\"0x07FA\"/>\n                    <Item ID=\"0x07FB\"/>\n                    <Item ID=\"0x07FC\"/>\n                    <Item ID=\"0x07FD\"/>\n                    <Item ID=\"0x07FE\"/>\n                    <Item ID=\"0x07FF\"/>\n                    <Item ID=\"0x0800\"/>\n                    <Item ID=\"0x0801\"/>\n                    <Item ID=\"0x0802\"/>\n                    <Item ID=\"0x0803\"/>\n                    <Item ID=\"0x0804\"/>\n                    <Item ID=\"0x0805\"/>\n                    <Item ID=\"0x0806\"/>\n                    <Item ID=\"0x0807\"/>\n                    <Item ID=\"0x0808\"/>\n                    <Item ID=\"0x0809\"/>\n                    <Item ID=\"0x080A\"/>\n                    <Item ID=\"0x080B\"/>\n                    <Item ID=\"0x080C\"/>\n                    <Item ID=\"0x080D\"/>\n                    <Item ID=\"0x080E\"/>\n                    <Item ID=\"0x080F\"/>\n                    <Item ID=\"0x0810\"/>\n                    <Item ID=\"0x0811\"/>\n                    <Item ID=\"0x0812\"/>\n                    <Item ID=\"0x0813\"/>\n                    <Item ID=\"0x0814\"/>\n                    <Item ID=\"0x0815\"/>\n                    <Item ID=\"0x0816\"/>\n                    <Item ID=\"0x0817\"/>\n                    <Item ID=\"0x0818\"/>\n                </Group>\n                <Group name=\"Wood Rails\">\n                    <Item ID=\"0x087E\"/>\n                    <Item ID=\"0x087F\"/>\n                    <Item ID=\"0x0880\"/>\n                    <Item ID=\"0x0881\"/>\n                    <Item ID=\"0x0882\"/>\n                    <Item ID=\"0x0883\"/>\n                    <Item ID=\"0x0884\"/>\n                    <Item ID=\"0x0885\"/>\n                    <Item ID=\"0x0886\"/>\n                    <Item ID=\"0x0887\"/>\n                    <Item ID=\"0x0888\"/>\n                    <Item ID=\"0x0889\"/>\n                </Group>\n                <Group name=\"Wooden Banister\">\n                    <Item ID=\"0x08AE\"/>\n                    <Item ID=\"0x08AF\"/>\n                    <Item ID=\"0x08B0\"/>\n                    <Item ID=\"0x08B1\"/>\n                    <Item ID=\"0x08B2\"/>\n                    <Item ID=\"0x08B3\"/>\n                    <Item ID=\"0x08B4\"/>\n                    <Item ID=\"0x08B5\"/>\n                    <Item ID=\"0x08B6\"/>\n                    <Item ID=\"0x08B7\"/>\n                    <Item ID=\"0x08B8\"/>\n                    <Item ID=\"0x08B9\"/>\n                    <Item ID=\"0x08BA\"/>\n                    <Item ID=\"0x08BB\"/>\n                    <Item ID=\"0x08BC\"/>\n                    <Item ID=\"0x08BD\"/>\n                    <Item ID=\"0x08BE\"/>\n                    <Item ID=\"0x08BF\"/>\n                    <Item ID=\"0x08C0\"/>\n                    <Item ID=\"0x08C1\"/>\n                    <Item ID=\"0x08C2\"/>\n                    <Item ID=\"0x08C3\"/>\n                    <Item ID=\"0x08C4\"/>\n                    <Item ID=\"0x08C5\"/>\n                    <Item ID=\"0x08C6\"/>\n                    <Item ID=\"0x08C7\"/>\n                    <Item ID=\"0x08C8\"/>\n                    <Item ID=\"0x08C9\"/>\n                    <Item ID=\"0x08CA\"/>\n                </Group>\n            </Group>\n            <Group name=\"Ramps\">\n                <Item ID=\"0x087A\"/>\n                <Item ID=\"0x087B\"/>\n                <Item ID=\"0x087C\"/>\n                <Item ID=\"0x087D\"/>\n                <Item ID=\"0x11BC\"/>\n                <Item ID=\"0x11BD\"/>\n                <Item ID=\"0x11BE\"/>\n                <Item ID=\"0x11BF\"/>\n            </Group>\n            <Group name=\"Red Carpet\">\n                <Item ID=\"0x07BA\"/>\n                <Item ID=\"0x07BB\"/>\n                <Item ID=\"0x07BC\"/>\n                <Item ID=\"0x07C7\"/>\n                <Item ID=\"0x07C8\"/>\n            </Group>\n            <Group name=\"Solid, Stone\">\n                <Group name=\"Coarse Brown Stone\">\n                    <Item ID=\"0x0784\"/>\n                    <Item ID=\"0x0785\"/>\n                    <Item ID=\"0x0786\"/>\n                    <Item ID=\"0x0787\"/>\n                    <Item ID=\"0x0788\"/>\n                    <Item ID=\"0x0788\"/>\n                    <Item ID=\"0x0789\"/>\n                    <Item ID=\"0x078A\"/>\n                    <Item ID=\"0x078B\"/>\n                    <Item ID=\"0x078C\"/>\n                    <Item ID=\"0x078D\"/>\n                    <Item ID=\"0x078E\"/>\n                    <Item ID=\"0x078F\"/>\n                    <Item ID=\"0x0790\"/>\n                    <Item ID=\"0x0791\"/>\n                    <Item ID=\"0x0792\"/>\n                    <Item ID=\"0x0793\"/>\n                    <Item ID=\"0x0794\"/>\n                    <Item ID=\"0x0795\"/>\n                    <Item ID=\"0x0796\"/>\n                    <Item ID=\"0x0797\"/>\n                    <Item ID=\"0x0798\"/>\n                    <Item ID=\"0x0799\"/>\n                    <Item ID=\"0x079A\"/>\n                    <Item ID=\"0x079B\"/>\n                    <Item ID=\"0x079C\"/>\n                </Group>\n                <Group name=\"Coarse Gray Stone\">\n                    <Item ID=\"0x071E\"/>\n                    <Item ID=\"0x071E\"/>\n                    <Item ID=\"0x071F\"/>\n                    <Item ID=\"0x0736\"/>\n                    <Item ID=\"0x0737\"/>\n                    <Item ID=\"0x0749\"/>\n                    <Item ID=\"0x074A\"/>\n                    <Item ID=\"0x074B\"/>\n                    <Item ID=\"0x074C\"/>\n                    <Item ID=\"0x074D\"/>\n                    <Item ID=\"0x074E\"/>\n                    <Item ID=\"0x074F\"/>\n                    <Item ID=\"0x0782\"/>\n                    <Item ID=\"0x0783\"/>\n                    <Item ID=\"0x07A0\"/>\n                    <Item ID=\"0x07A1\"/>\n                    <Item ID=\"0x07A2\"/>\n                    <Item ID=\"0x07DA\"/>\n                    <Item ID=\"0x07DF\"/>\n                    <Item ID=\"0x07E0\"/>\n                    <Item ID=\"0x0834\"/>\n                    <Item ID=\"0x0876\"/>\n                    <Item ID=\"0x1ecb\"/>\n                </Group>\n                <Group name=\"Coarse Sandstone\">\n                    <Item ID=\"0x03EE\"/>\n                    <Item ID=\"0x03EF\"/>\n                    <Item ID=\"0x03EF\"/>\n                    <Item ID=\"0x03F0\"/>\n                    <Item ID=\"0x03F1\"/>\n                    <Item ID=\"0x03F2\"/>\n                    <Item ID=\"0x03F3\"/>\n                    <Item ID=\"0x03F4\"/>\n                    <Item ID=\"0x03F5\"/>\n                    <Item ID=\"0x03F6\"/>\n                    <Item ID=\"0x03F7\"/>\n                    <Item ID=\"0x03F8\"/>\n                    <Item ID=\"0x03F9\"/>\n                    <Item ID=\"0x03FA\"/>\n                    <Item ID=\"0x03FB\"/>\n                    <Item ID=\"0x03FC\"/>\n                    <Item ID=\"0x03FD\"/>\n                    <Item ID=\"0x03FE\"/>\n                    <Item ID=\"0x03FF\"/>\n                    <Item ID=\"0x0400\"/>\n                    <Item ID=\"0x0401\"/>\n                    <Item ID=\"0x0402\"/>\n                </Group>\n                <Group name=\"Crystal Stairs\">\n                    <Item ID=\"0x35D2\"/>\n                    <Item ID=\"0x35D3\"/>\n                    <Item ID=\"0x35D4\"/>\n                    <Item ID=\"0x35D5\"/>\n                    <Item ID=\"0x35D6\"/>\n                </Group>\n                <Group name=\"Pink Marble\">\n                    <Item ID=\"0x0709\"/>\n                    <Item ID=\"0x0709\"/>\n                    <Item ID=\"0x070A\"/>\n                    <Item ID=\"0x070B\"/>\n                    <Item ID=\"0x070C\"/>\n                    <Item ID=\"0x070D\"/>\n                    <Item ID=\"0x070E\"/>\n                    <Item ID=\"0x070F\"/>\n                    <Item ID=\"0x0710\"/>\n                    <Item ID=\"0x0711\"/>\n                    <Item ID=\"0x0712\"/>\n                    <Item ID=\"0x0713\"/>\n                    <Item ID=\"0x0714\"/>\n                    <Item ID=\"0x0715\"/>\n                    <Item ID=\"0x0716\"/>\n                    <Item ID=\"0x0717\"/>\n                    <Item ID=\"0x0718\"/>\n                    <Item ID=\"0x0719\"/>\n                    <Item ID=\"0x071A\"/>\n                    <Item ID=\"0x071B\"/>\n                    <Item ID=\"0x071C\"/>\n                    <Item ID=\"0x071D\"/>\n                </Group>\n                <Group name=\"Precise Gray Stone\">\n                    <Item ID=\"0x3609\"/>\n                    <Item ID=\"0x360A\"/>\n                    <Item ID=\"0x360B\"/>\n                    <Item ID=\"0x360C\"/>\n                    <Item ID=\"0x360D\"/>\n                </Group>\n                <Group name=\"Precise Greenish Stone\">\n                    <Item ID=\"0x07A3\"/>\n                    <Item ID=\"0x07A4\"/>\n                    <Item ID=\"0x07A5\"/>\n                    <Item ID=\"0x07A6\"/>\n                    <Item ID=\"0x07A7\"/>\n                    <Item ID=\"0x07A8\"/>\n                    <Item ID=\"0x07A9\"/>\n                    <Item ID=\"0x07Aa\"/>\n                    <Item ID=\"0x07Ab\"/>\n                    <Item ID=\"0x07Ac\"/>\n                    <Item ID=\"0x07Ad\"/>\n                    <Item ID=\"0x07Ae\"/>\n                    <Item ID=\"0x07Af\"/>\n                    <Item ID=\"0x1eca\"/>\n                </Group>\n                <Group name=\"Precise Light Gray Stone\">\n                    <Item ID=\"0x0750\"/>\n                    <Item ID=\"0x0750\"/>\n                    <Item ID=\"0x0751\"/>\n                    <Item ID=\"0x0752\"/>\n                    <Item ID=\"0x0753\"/>\n                    <Item ID=\"0x0754\"/>\n                    <Item ID=\"0x0755\"/>\n                    <Item ID=\"0x0756\"/>\n                    <Item ID=\"0x0757\"/>\n                    <Item ID=\"0x0758\"/>\n                    <Item ID=\"0x0759\"/>\n                    <Item ID=\"0x075A\"/>\n                    <Item ID=\"0x075B\"/>\n                    <Item ID=\"0x075C\"/>\n                    <Item ID=\"0x075D\"/>\n                    <Item ID=\"0x075E\"/>\n                    <Item ID=\"0x075F\"/>\n                    <Item ID=\"0x0760\"/>\n                    <Item ID=\"0x0761\"/>\n                    <Item ID=\"0x0762\"/>\n                    <Item ID=\"0x0763\"/>\n                    <Item ID=\"0x0764\"/>\n                    <Item ID=\"0x0765\"/>\n                    <Item ID=\"0x0766\"/>\n                    <Item ID=\"0x0767\"/>\n                    <Item ID=\"0x0768\"/>\n                </Group>\n                <Group name=\"Precise Sandstone\">\n                    <Item ID=\"0x0769\"/>\n                    <Item ID=\"0x076A\"/>\n                    <Item ID=\"0x076B\"/>\n                    <Item ID=\"0x076C\"/>\n                    <Item ID=\"0x076C\"/>\n                    <Item ID=\"0x076D\"/>\n                    <Item ID=\"0x076E\"/>\n                    <Item ID=\"0x076F\"/>\n                    <Item ID=\"0x0770\"/>\n                    <Item ID=\"0x0771\"/>\n                    <Item ID=\"0x0772\"/>\n                    <Item ID=\"0x0773\"/>\n                    <Item ID=\"0x0774\"/>\n                    <Item ID=\"0x0775\"/>\n                    <Item ID=\"0x0776\"/>\n                    <Item ID=\"0x0777\"/>\n                    <Item ID=\"0x0778\"/>\n                    <Item ID=\"0x0779\"/>\n                    <Item ID=\"0x077A\"/>\n                    <Item ID=\"0x077B\"/>\n                    <Item ID=\"0x077C\"/>\n                    <Item ID=\"0x077D\"/>\n                    <Item ID=\"0x077E\"/>\n                    <Item ID=\"0x077F\"/>\n                    <Item ID=\"0x0780\"/>\n                    <Item ID=\"0x0781\"/>\n                    <Item ID=\"0x1ecc\"/>\n                </Group>\n            </Group>\n            <Group name=\"Solid, Wood\">\n                <Group name=\"Dark Wood\">\n                    <Item ID=\"0x0738\"/>\n                    <Item ID=\"0x0738\"/>\n                    <Item ID=\"0x0739\"/>\n                    <Item ID=\"0x073A\"/>\n                    <Item ID=\"0x073B\"/>\n                    <Item ID=\"0x073C\"/>\n                    <Item ID=\"0x073D\"/>\n                    <Item ID=\"0x073E\"/>\n                    <Item ID=\"0x073F\"/>\n                    <Item ID=\"0x0740\"/>\n                    <Item ID=\"0x0741\"/>\n                    <Item ID=\"0x0742\"/>\n                    <Item ID=\"0x0743\"/>\n                    <Item ID=\"0x0744\"/>\n                    <Item ID=\"0x0745\"/>\n                    <Item ID=\"0x0746\"/>\n                    <Item ID=\"0x0747\"/>\n                    <Item ID=\"0x0748\"/>\n                    <Item ID=\"0x07b3\"/>\n                    <Item ID=\"0x07b4\"/>\n                    <Item ID=\"0x07b5\"/>\n                    <Item ID=\"0x07b6\"/>\n                </Group>\n                <Group name=\"Light Wood\">\n                    <Item ID=\"0x0720\"/>\n                    <Item ID=\"0x0720\"/>\n                    <Item ID=\"0x0721\"/>\n                    <Item ID=\"0x0722\"/>\n                    <Item ID=\"0x0723\"/>\n                    <Item ID=\"0x0724\"/>\n                    <Item ID=\"0x0725\"/>\n                    <Item ID=\"0x0726\"/>\n                    <Item ID=\"0x0727\"/>\n                    <Item ID=\"0x0728\"/>\n                    <Item ID=\"0x0729\"/>\n                    <Item ID=\"0x072A\"/>\n                    <Item ID=\"0x072B\"/>\n                    <Item ID=\"0x072C\"/>\n                    <Item ID=\"0x072D\"/>\n                    <Item ID=\"0x072E\"/>\n                    <Item ID=\"0x072F\"/>\n                    <Item ID=\"0x0730\"/>\n                    <Item ID=\"0x0731\"/>\n                    <Item ID=\"0x0732\"/>\n                    <Item ID=\"0x0733\"/>\n                    <Item ID=\"0x0734\"/>\n                    <Item ID=\"0x0735\"/>\n                </Group>\n            </Group>\n            <Group name=\"Stair Cabinet\">\n                <Item ID=\"0x24EC\"/>\n                <Item ID=\"0x24ED\"/>\n                <Item ID=\"0x24EE\"/>\n                <Item ID=\"0x24EF\"/>\n                <Item ID=\"0x24F0\"/>\n                <Item ID=\"0x24F1\"/>\n                <Item ID=\"0x24F2\"/>\n                <Item ID=\"0x24F3\"/>\n            </Group>\n        </Group>\n        <Group name=\"Walls\">\n            <Group name=\"Crystal + Marble\">\n                <Group name=\"Crystal Walls\">\n                    <Item ID=\"0x35D7\"/>\n                    <Item ID=\"0x35D8\"/>\n                    <Item ID=\"0x35D9\"/>\n                    <Item ID=\"0x35DA\"/>\n                    <Item ID=\"0x35DB\"/>\n                    <Item ID=\"0x35DC\"/>\n                    <Item ID=\"0x35DD\"/>\n                    <Item ID=\"0x35DE\"/>\n                    <Item ID=\"0x35DF\"/>\n                    <Item ID=\"0x35E0\"/>\n                    <Item ID=\"0x35E1\"/>\n                    <Item ID=\"0x35E2\"/>\n                    <Item ID=\"0x35E3\"/>\n                    <Item ID=\"0x35E4\"/>\n                    <Item ID=\"0x35E5\"/>\n                    <Item ID=\"0x35E6\"/>\n                    <Item ID=\"0x35E8\"/>\n                    <Item ID=\"0x35EA\"/>\n                    <Item ID=\"0x3670\"/>\n                    <Item ID=\"0x3671\"/>\n                    <Item ID=\"0x3672\"/>\n                    <Item ID=\"0x3673\"/>\n                </Group>\n                <Group name=\"Light Blue Marble\">\n                    <Item ID=\"0x0291\"/>\n                    <Item ID=\"0x0292\"/>\n                    <Item ID=\"0x0293\"/>\n                    <Item ID=\"0x0294\"/>\n                    <Item ID=\"0x0295\"/>\n                    <Item ID=\"0x0296\"/>\n                    <Item ID=\"0x0297\"/>\n                    <Item ID=\"0x0298\"/>\n                    <Item ID=\"0x0299\"/>\n                    <Item ID=\"0x029A\"/>\n                    <Item ID=\"0x029B\"/>\n                    <Item ID=\"0x029C\"/>\n                    <Item ID=\"0x029D\"/>\n                    <Item ID=\"0x029E\"/>\n                    <Item ID=\"0x029F\"/>\n                    <Item ID=\"0x02A0\"/>\n                    <Item ID=\"0x02A1\"/>\n                    <Item ID=\"0x02A2\"/>\n                    <Item ID=\"0x02A3\"/>\n                    <Item ID=\"0x02A4\"/>\n                    <Item ID=\"0x02A7\"/>\n                    <Item ID=\"0x02A8\"/>\n                    <Item ID=\"0x02A9\"/>\n                    <Item ID=\"0x02AA\"/>\n                    <Item ID=\"0x02AB\"/>\n                    <Item ID=\"0x02AC\"/>\n                    <Item ID=\"0x02AD\"/>\n                    <Item ID=\"0x02AE\"/>\n                    <Item ID=\"0x02B5\"/>\n                    <Item ID=\"0x02B6\"/>\n                    <Item ID=\"0x02B7\"/>\n                    <Item ID=\"0x02B8\"/>\n                    <Item ID=\"0x02B9\"/>\n                    <Item ID=\"0x02BA\"/>\n                    <Item ID=\"0x02BB\"/>\n                    <Item ID=\"0x02BC\"/>\n                    <Item ID=\"0x02BD\"/>\n                    <Item ID=\"0x02BE\"/>\n                    <Item ID=\"0x02BF\"/>\n                    <Item ID=\"0x02C0\"/>\n                    <Item ID=\"0x253C\"/>\n                    <Item ID=\"0x253D\"/>\n                    <Item ID=\"0x253e\"/>\n                    <Item ID=\"0x26D0\"/>\n                    <Item ID=\"0x26D2\"/>\n                    <Item ID=\"0x26D4\"/>\n                    <Item ID=\"0x26D5\"/>\n                    <Item ID=\"0x26D6\"/>\n                    <Item ID=\"0x26D8\"/>\n                </Group>\n                <Group name=\"White Marble\">\n                    <Item ID=\"0x00F8\"/>\n                    <Item ID=\"0x00F9\"/>\n                    <Item ID=\"0x00FA\"/>\n                    <Item ID=\"0x00FB\"/>\n                    <Item ID=\"0x00FC\"/>\n                    <Item ID=\"0x00FD\"/>\n                    <Item ID=\"0x00FE\"/>\n                    <Item ID=\"0x00FF\"/>\n                    <Item ID=\"0x0100\"/>\n                    <Item ID=\"0x0101\"/>\n                    <Item ID=\"0x0102\"/>\n                    <Item ID=\"0x0103\"/>\n                    <Item ID=\"0x0104\"/>\n                    <Item ID=\"0x0105\"/>\n                    <Item ID=\"0x0106\"/>\n                    <Item ID=\"0x0107\"/>\n                    <Item ID=\"0x0108\"/>\n                    <Item ID=\"0x0109\"/>\n                    <Item ID=\"0x010A\"/>\n                    <Item ID=\"0x010B\"/>\n                    <Item ID=\"0x010C\"/>\n                    <Item ID=\"0x010D\"/>\n                    <Item ID=\"0x010E\"/>\n                    <Item ID=\"0x010F\"/>\n                    <Item ID=\"0x0110\"/>\n                    <Item ID=\"0x0111\"/>\n                    <Item ID=\"0x0117\"/>\n                    <Item ID=\"0x0118\"/>\n                    <Item ID=\"0x0119\"/>\n                    <Item ID=\"0x011A\"/>\n                    <Item ID=\"0x011B\"/>\n                    <Item ID=\"0x011C\"/>\n                    <Item ID=\"0x011D\"/>\n                    <Item ID=\"0x011E\"/>\n                    <Item ID=\"0x011F\"/>\n                    <Item ID=\"0x0120\"/>\n                    <Item ID=\"0x0121\"/>\n                    <Item ID=\"0x0122\"/>\n                    <Item ID=\"0x0123\"/>\n                    <Item ID=\"0x0124\"/>\n                    <Item ID=\"0x239a\"/>\n                    <Item ID=\"0x239b\"/>\n                    <Item ID=\"0x250C\"/>\n                    <Item ID=\"0x250D\"/>\n                    <Item ID=\"0x250E\"/>\n                    <Item ID=\"0x250f\"/>\n                    <Item ID=\"0x2510\"/>\n                    <Item ID=\"0x2511\"/>\n                    <Item ID=\"0x2512\"/>\n                    <Item ID=\"0x2513\"/>\n                    <Item ID=\"0x2514\"/>\n                    <Item ID=\"0x2515\"/>\n                    <Item ID=\"0x2516\"/>\n                    <Item ID=\"0x2517\"/>\n                    <Item ID=\"0x2518\"/>\n                    <Item ID=\"0x2519\"/>\n                    <Item ID=\"0x251A\"/>\n                    <Item ID=\"0x251C\"/>\n                    <Item ID=\"0x251E\"/>\n                    <Item ID=\"0x251F\"/>\n                    <Item ID=\"0x251b\"/>\n                    <Item ID=\"0x251d\"/>\n                    <Item ID=\"0x2520\"/>\n                    <Item ID=\"0x2521\"/>\n                    <Item ID=\"0x2522\"/>\n                    <Item ID=\"0x2523\"/>\n                    <Item ID=\"0x2524\"/>\n                    <Item ID=\"0x2525\"/>\n                    <Item ID=\"0x2526\"/>\n                    <Item ID=\"0x2527\"/>\n                    <Item ID=\"0x2528\"/>\n                    <Item ID=\"0x2529\"/>\n                    <Item ID=\"0x252A\"/>\n                    <Item ID=\"0x252B\"/>\n                    <Item ID=\"0x252C\"/>\n                    <Item ID=\"0x252E\"/>\n                    <Item ID=\"0x252d\"/>\n                </Group>\n            </Group>\n            <Group name=\"Organic\">\n                <Group name=\"Blue Tent\">\n                    <Item ID=\"0x01F0\"/>\n                    <Item ID=\"0x01F1\"/>\n                    <Item ID=\"0x01F2\"/>\n                    <Item ID=\"0x01F3\"/>\n                    <Item ID=\"0x01F4\"/>\n                    <Item ID=\"0x01F5\"/>\n                    <Item ID=\"0x01F6\"/>\n                    <Item ID=\"0x01F7\"/>\n                    <Item ID=\"0x01F8\"/>\n                    <Item ID=\"0x01F9\"/>\n                </Group>\n                <Group name=\"Cloth Frame\">\n                    <Item ID=\"0x2888\"/>\n                    <Item ID=\"0x2889\"/>\n                    <Item ID=\"0x288a\"/>\n                    <Item ID=\"0x288b\"/>\n                    <Item ID=\"0x288c\"/>\n                    <Item ID=\"0x288d\"/>\n                    <Item ID=\"0x288e\"/>\n                    <Item ID=\"0x288f\"/>\n                    <Item ID=\"0x2890\"/>\n                    <Item ID=\"0x2891\"/>\n                    <Item ID=\"0x2892\"/>\n                    <Item ID=\"0x2893\"/>\n                    <Item ID=\"0x2894\"/>\n                    <Item ID=\"0x2895\"/>\n                    <Item ID=\"0x2896\"/>\n                    <Item ID=\"0x2897\"/>\n                    <Item ID=\"0x2898\"/>\n                    <Item ID=\"0x2899\"/>\n                    <Item ID=\"0x289a\"/>\n                    <Item ID=\"0x289b\"/>\n                    <Item ID=\"0x289c\"/>\n                    <Item ID=\"0x289d\"/>\n                    <Item ID=\"0x289e\"/>\n                    <Item ID=\"0x289f\"/>\n                    <Item ID=\"0x28a0\"/>\n                    <Item ID=\"0x28a1\"/>\n                    <Item ID=\"0x28a2\"/>\n                    <Item ID=\"0x28a3\"/>\n                </Group>\n                <Group name=\"Gray-Blue Tent\">\n                    <Item ID=\"0x02DE\"/>\n                    <Item ID=\"0x02DF\"/>\n                    <Item ID=\"0x02E0\"/>\n                    <Item ID=\"0x02E1\"/>\n                    <Item ID=\"0x02E2\"/>\n                    <Item ID=\"0x02E3\"/>\n                    <Item ID=\"0x02E4\"/>\n                    <Item ID=\"0x02E5\"/>\n                    <Item ID=\"0x02E6\"/>\n                    <Item ID=\"0x02E7\"/>\n                    <Item ID=\"0x02E8\"/>\n                    <Item ID=\"0x02E9\"/>\n                    <Item ID=\"0x02EA\"/>\n                    <Item ID=\"0x02EB\"/>\n                    <Item ID=\"0x02EC\"/>\n                    <Item ID=\"0x02Ef\"/>\n                    <Item ID=\"0x02f0\"/>\n                    <Item ID=\"0x02f1\"/>\n                    <Item ID=\"0x02f2\"/>\n                    <Item ID=\"0x02f3\"/>\n                    <Item ID=\"0x02f4\"/>\n                    <Item ID=\"0x0372\"/>\n                    <Item ID=\"0x0373\"/>\n                    <Item ID=\"0x0374\"/>\n                    <Item ID=\"0x0375\"/>\n                    <Item ID=\"0x0376\"/>\n                </Group>\n                <Group name=\"Green Tent\">\n                    <Item ID=\"0x0230\"/>\n                    <Item ID=\"0x0231\"/>\n                    <Item ID=\"0x0232\"/>\n                    <Item ID=\"0x0233\"/>\n                    <Item ID=\"0x0234\"/>\n                    <Item ID=\"0x0235\"/>\n                    <Item ID=\"0x0236\"/>\n                    <Item ID=\"0x0237\"/>\n                    <Item ID=\"0x0238\"/>\n                    <Item ID=\"0x0239\"/>\n                    <Item ID=\"0x02Ef\"/>\n                    <Item ID=\"0x02f0\"/>\n                    <Item ID=\"0x02f1\"/>\n                    <Item ID=\"0x02f2\"/>\n                    <Item ID=\"0x02f3\"/>\n                    <Item ID=\"0x02f4\"/>\n                    <Item ID=\"0x0372\"/>\n                    <Item ID=\"0x0373\"/>\n                    <Item ID=\"0x0374\"/>\n                    <Item ID=\"0x0375\"/>\n                    <Item ID=\"0x0376\"/>\n                </Group>\n                <Group name=\"Hide\">\n                    <Item ID=\"0x01B6\"/>\n                    <Item ID=\"0x01B7\"/>\n                    <Item ID=\"0x01B8\"/>\n                    <Item ID=\"0x01B9\"/>\n                    <Item ID=\"0x01BA\"/>\n                    <Item ID=\"0x01BB\"/>\n                    <Item ID=\"0x01BC\"/>\n                    <Item ID=\"0x01BD\"/>\n                    <Item ID=\"0x01BE\"/>\n                    <Item ID=\"0x01BF\"/>\n                    <Item ID=\"0x01C0\"/>\n                    <Item ID=\"0x01C1\"/>\n                    <Item ID=\"0x01C2\"/>\n                    <Item ID=\"0x01C3\"/>\n                    <Item ID=\"0x01C4\"/>\n                    <Item ID=\"0x01C5\"/>\n                    <Item ID=\"0x01C6\"/>\n                    <Item ID=\"0x01C7\"/>\n                    <Item ID=\"0x01C8\"/>\n                    <Item ID=\"0x01C9\"/>\n                    <Item ID=\"0x0432\"/>\n                    <Item ID=\"0x0433\"/>\n                    <Item ID=\"0x0434\"/>\n                    <Item ID=\"0x0435\"/>\n                    <Item ID=\"0x0435\"/>\n                </Group>\n                <Group name=\"Light Gray Tent\">\n                    <Item ID=\"0x02Ef\"/>\n                    <Item ID=\"0x02f0\"/>\n                    <Item ID=\"0x02f1\"/>\n                    <Item ID=\"0x02f2\"/>\n                    <Item ID=\"0x02f3\"/>\n                    <Item ID=\"0x02f4\"/>\n                    <Item ID=\"0x0368\"/>\n                    <Item ID=\"0x0369\"/>\n                    <Item ID=\"0x036A\"/>\n                    <Item ID=\"0x036B\"/>\n                    <Item ID=\"0x036C\"/>\n                    <Item ID=\"0x036D\"/>\n                    <Item ID=\"0x036E\"/>\n                    <Item ID=\"0x036F\"/>\n                    <Item ID=\"0x0370\"/>\n                    <Item ID=\"0x0371\"/>\n                    <Item ID=\"0x0372\"/>\n                    <Item ID=\"0x0373\"/>\n                    <Item ID=\"0x0374\"/>\n                    <Item ID=\"0x0375\"/>\n                    <Item ID=\"0x0376\"/>\n                    <Item ID=\"0x0378\"/>\n                    <Item ID=\"0x0379\"/>\n                    <Item ID=\"0x037a\"/>\n                    <Item ID=\"0x037a\"/>\n                    <Item ID=\"0x037b\"/>\n                    <Item ID=\"0x037b\"/>\n                    <Item ID=\"0x037c\"/>\n                    <Item ID=\"0x037c\"/>\n                    <Item ID=\"0x037d\"/>\n                    <Item ID=\"0x037d\"/>\n                </Group>\n                <Group name=\"Rattan\">\n                    <Item ID=\"0x019B\"/>\n                    <Item ID=\"0x019C\"/>\n                    <Item ID=\"0x019D\"/>\n                    <Item ID=\"0x019E\"/>\n                    <Item ID=\"0x019F\"/>\n                    <Item ID=\"0x01A0\"/>\n                    <Item ID=\"0x01A1\"/>\n                    <Item ID=\"0x01A2\"/>\n                    <Item ID=\"0x01A3\"/>\n                    <Item ID=\"0x01A5\"/>\n                    <Item ID=\"0x01A6\"/>\n                    <Item ID=\"0x01A7\"/>\n                    <Item ID=\"0x01A8\"/>\n                    <Item ID=\"0x01A9\"/>\n                    <Item ID=\"0x01AA\"/>\n                    <Item ID=\"0x01AB\"/>\n                    <Item ID=\"0x01AC\"/>\n                    <Item ID=\"0x01AD\"/>\n                    <Item ID=\"0x01AE\"/>\n                    <Item ID=\"0x01AF\"/>\n                    <Item ID=\"0x01B0\"/>\n                    <Item ID=\"0x215A\"/>\n                    <Item ID=\"0x215B\"/>\n                    <Item ID=\"0x215C\"/>\n                    <Item ID=\"0x215b\"/>\n                    <Item ID=\"0x215c\"/>\n                </Group>\n                <Group name=\"Round Bamboo\">\n                    <Item ID=\"0x020F\"/>\n                    <Item ID=\"0x0210\"/>\n                    <Item ID=\"0x0211\"/>\n                    <Item ID=\"0x0212\"/>\n                    <Item ID=\"0x0213\"/>\n                    <Item ID=\"0x0214\"/>\n                    <Item ID=\"0x0215\"/>\n                    <Item ID=\"0x0216\"/>\n                    <Item ID=\"0x0217\"/>\n                    <Item ID=\"0x0218\"/>\n                    <Item ID=\"0x0219\"/>\n                    <Item ID=\"0x021A\"/>\n                </Group>\n                <Group name=\"Tall Tree Wall\">\n                    <Item ID=\"0x3025\"/>\n                    <Item ID=\"0x3026\"/>\n                    <Item ID=\"0x3027\"/>\n                    <Item ID=\"0x3028\"/>\n                    <Item ID=\"0x3029\"/>\n                    <Item ID=\"0x302A\"/>\n                    <Item ID=\"0x302B\"/>\n                    <Item ID=\"0x302C\"/>\n                </Group>\n                <Group name=\"Thorn\">\n                    <Item ID=\"0x2DFF\"/>\n                    <Item ID=\"0x2E00\"/>\n                    <Item ID=\"0x2E01\"/>\n                </Group>\n                <Group name=\"Tree\">\n                    <Item ID=\"0x2f13\"/>\n                    <Item ID=\"0x2f14\"/>\n                    <Item ID=\"0x2f15\"/>\n                    <Item ID=\"0x2f16\"/>\n                    <Item ID=\"0x2f17\"/>\n                    <Item ID=\"0x2f18\"/>\n                    <Item ID=\"0x2f19\"/>\n                    <Item ID=\"0x2f1a\"/>\n                </Group>\n            </Group>\n            <Group name=\"Plaster + Clay\">\n                <Group name=\"Brown Clay\">\n                    <Item ID=\"0x2944\"/>\n                    <Item ID=\"0x2945\"/>\n                    <Item ID=\"0x2946\"/>\n                    <Item ID=\"0x2947\"/>\n                    <Item ID=\"0x2948\"/>\n                    <Item ID=\"0x2949\"/>\n                    <Item ID=\"0x294A\"/>\n                    <Item ID=\"0x294B\"/>\n                    <Item ID=\"0x294C\"/>\n                    <Item ID=\"0x294D\"/>\n                    <Item ID=\"0x294E\"/>\n                    <Item ID=\"0x294F\"/>\n                </Group>\n                <Group name=\"Dark Half Timber\">\n                    <Item ID=\"0x29DC\"/>\n                    <Item ID=\"0x29DD\"/>\n                    <Item ID=\"0x29DE\"/>\n                    <Item ID=\"0x29DF\"/>\n                    <Item ID=\"0x29E0\"/>\n                    <Item ID=\"0x29E1\"/>\n                    <Item ID=\"0x29E2\"/>\n                    <Item ID=\"0x29E3\"/>\n                    <Item ID=\"0x29E4\"/>\n                    <Item ID=\"0x29E5\"/>\n                    <Item ID=\"0x29E6\"/>\n                    <Item ID=\"0x29E7\"/>\n                    <Item ID=\"0x29E8\"/>\n                    <Item ID=\"0x29E9\"/>\n                    <Item ID=\"0x29EA\"/>\n                    <Item ID=\"0x29EB\"/>\n                    <Item ID=\"0x29EC\"/>\n                    <Item ID=\"0x29ED\"/>\n                    <Item ID=\"0x29EE\"/>\n                    <Item ID=\"0x29EF\"/>\n                    <Item ID=\"0x29F0\"/>\n                    <Item ID=\"0x29F1\"/>\n                    <Item ID=\"0x29F2\"/>\n                    <Item ID=\"0x29F3\"/>\n                    <Item ID=\"0x29F4\"/>\n                    <Item ID=\"0x29F5\"/>\n                    <Item ID=\"0x29F6\"/>\n                    <Item ID=\"0x29F7\"/>\n                    <Item ID=\"0x29F8\"/>\n                    <Item ID=\"0x29F9\"/>\n                    <Item ID=\"0x29FA\"/>\n                    <Item ID=\"0x29FB\"/>\n                    <Item ID=\"0x29FC\"/>\n                </Group>\n                <Group name=\"Light Brown Clay\">\n                    <Item ID=\"0x2950\"/>\n                    <Item ID=\"0x2951\"/>\n                    <Item ID=\"0x2952\"/>\n                    <Item ID=\"0x2953\"/>\n                    <Item ID=\"0x2954\"/>\n                    <Item ID=\"0x2955\"/>\n                    <Item ID=\"0x2956\"/>\n                    <Item ID=\"0x2957\"/>\n                    <Item ID=\"0x2958\"/>\n                    <Item ID=\"0x2959\"/>\n                    <Item ID=\"0x295A\"/>\n                    <Item ID=\"0x295B\"/>\n                </Group>\n                <Group name=\"Light Half Timber\">\n                    <Item ID=\"0x0127\"/>\n                    <Item ID=\"0x0128\"/>\n                    <Item ID=\"0x0129\"/>\n                    <Item ID=\"0x012A\"/>\n                    <Item ID=\"0x012B\"/>\n                    <Item ID=\"0x012C\"/>\n                    <Item ID=\"0x012D\"/>\n                    <Item ID=\"0x012E\"/>\n                    <Item ID=\"0x012F\"/>\n                    <Item ID=\"0x0130\"/>\n                    <Item ID=\"0x0131\"/>\n                    <Item ID=\"0x0132\"/>\n                    <Item ID=\"0x0133\"/>\n                    <Item ID=\"0x0134\"/>\n                    <Item ID=\"0x0135\"/>\n                    <Item ID=\"0x0136\"/>\n                    <Item ID=\"0x0137\"/>\n                    <Item ID=\"0x0138\"/>\n                    <Item ID=\"0x0139\"/>\n                    <Item ID=\"0x013A\"/>\n                    <Item ID=\"0x013B\"/>\n                    <Item ID=\"0x013C\"/>\n                    <Item ID=\"0x013D\"/>\n                    <Item ID=\"0x013E\"/>\n                    <Item ID=\"0x013F\"/>\n                    <Item ID=\"0x0140\"/>\n                    <Item ID=\"0x0149\"/>\n                    <Item ID=\"0x014C\"/>\n                    <Item ID=\"0x014D\"/>\n                    <Item ID=\"0x014E\"/>\n                    <Item ID=\"0x014F\"/>\n                    <Item ID=\"0x0150\"/>\n                    <Item ID=\"0x0151\"/>\n                    <Item ID=\"0x0152\"/>\n                    <Item ID=\"0x0153\"/>\n                    <Item ID=\"0x0154\"/>\n                    <Item ID=\"0x0155\"/>\n                    <Item ID=\"0x0156\"/>\n                    <Item ID=\"0x0157\"/>\n                    <Item ID=\"0x037F\"/>\n                    <Item ID=\"0x0380\"/>\n                    <Item ID=\"0x0381\"/>\n                    <Item ID=\"0x0383\"/>\n                    <Item ID=\"0x0384\"/>\n                    <Item ID=\"0x0385\"/>\n                    <Item ID=\"0x0386\"/>\n                    <Item ID=\"0x0387\"/>\n                    <Item ID=\"0x0388\"/>\n                    <Item ID=\"0x0389\"/>\n                    <Item ID=\"0x038B\"/>\n                    <Item ID=\"0x038C\"/>\n                    <Item ID=\"0x038D\"/>\n                    <Item ID=\"0x038E\"/>\n                    <Item ID=\"0x038F\"/>\n                    <Item ID=\"0x0390\"/>\n                    <Item ID=\"0x0391\"/>\n                    <Item ID=\"0x0393\"/>\n                    <Item ID=\"0x0394\"/>\n                    <Item ID=\"0x0395\"/>\n                    <Item ID=\"0x0396\"/>\n                    <Item ID=\"0x0397\"/>\n                    <Item ID=\"0x0398\"/>\n                    <Item ID=\"0x0399\"/>\n                    <Item ID=\"0x039A\"/>\n                    <Item ID=\"0x039B\"/>\n                    <Item ID=\"0x039C\"/>\n                    <Item ID=\"0x039D\"/>\n                    <Item ID=\"0x039E\"/>\n                    <Item ID=\"0x039F\"/>\n                    <Item ID=\"0x03A0\"/>\n                </Group>\n                <Group name=\"Partial Cover\">\n                    <Group name=\"ruined\">\n                        <Item ID=\"0x03B7\"/>\n                        <Item ID=\"0x03B8\"/>\n                        <Item ID=\"0x03B9\"/>\n                        <Item ID=\"0x03BF\"/>\n                        <Item ID=\"0x03Ba\"/>\n                        <Item ID=\"0x03Bb\"/>\n                        <Item ID=\"0x03Bc\"/>\n                        <Item ID=\"0x03Bd\"/>\n                        <Item ID=\"0x03C3\"/>\n                        <Item ID=\"0x03C4\"/>\n                        <Item ID=\"0x03C5\"/>\n                        <Item ID=\"0x03C6\"/>\n                    </Group>\n                    <Item ID=\"0x01FF\"/>\n                    <Item ID=\"0x0200\"/>\n                    <Item ID=\"0x0201\"/>\n                    <Item ID=\"0x0203\"/>\n                    <Item ID=\"0x0204\"/>\n                    <Item ID=\"0x0205\"/>\n                    <Item ID=\"0x0206\"/>\n                    <Item ID=\"0x0209\"/>\n                    <Item ID=\"0x020A\"/>\n                    <Item ID=\"0x03C2\"/>\n                    <Item ID=\"0x03C7\"/>\n                    <Item ID=\"0x03C8\"/>\n                    <Item ID=\"0x03C9\"/>\n                    <Item ID=\"0x03CA\"/>\n                    <Item ID=\"0x03CB\"/>\n                    <Item ID=\"0x03CC\"/>\n                    <Item ID=\"0x03CD\"/>\n                    <Item ID=\"0x03CE\"/>\n                    <Item ID=\"0x03CF\"/>\n                    <Item ID=\"0x03D0\"/>\n                    <Item ID=\"0x03D1\"/>\n                    <Item ID=\"0x03D2\"/>\n                    <Item ID=\"0x03D3\"/>\n                    <Item ID=\"0x03D4\"/>\n                    <Item ID=\"0x03D5\"/>\n                    <Item ID=\"0x03D6\"/>\n                    <Item ID=\"0x03D8\"/>\n                    <Item ID=\"0x03DD\"/>\n                    <Item ID=\"0x03DE\"/>\n                    <Item ID=\"0x03DF\"/>\n                    <Item ID=\"0x03E0\"/>\n                    <Item ID=\"0x03E1\"/>\n                    <Item ID=\"0x252F\"/>\n                    <Item ID=\"0x2530\"/>\n                    <Item ID=\"0x2531\"/>\n                    <Item ID=\"0x2532\"/>\n                    <Item ID=\"0x2534\"/>\n                    <Item ID=\"0x2535\"/>\n                    <Item ID=\"0x2536\"/>\n                    <Item ID=\"0x2537\"/>\n                    <Item ID=\"0x2538\"/>\n                    <Item ID=\"0x2539\"/>\n                    <Item ID=\"0x253A\"/>\n                    <Item ID=\"0x253b\"/>\n                </Group>\n                <Group name=\"Pink Clay\">\n                    <Item ID=\"0x2938\"/>\n                    <Item ID=\"0x2939\"/>\n                    <Item ID=\"0x293A\"/>\n                    <Item ID=\"0x293B\"/>\n                    <Item ID=\"0x293C\"/>\n                    <Item ID=\"0x293D\"/>\n                    <Item ID=\"0x293E\"/>\n                    <Item ID=\"0x293F\"/>\n                    <Item ID=\"0x2940\"/>\n                    <Item ID=\"0x2941\"/>\n                    <Item ID=\"0x2942\"/>\n                    <Item ID=\"0x2943\"/>\n                </Group>\n                <Group name=\"Stone Trim\">\n                    <Item ID=\"0x2499\"/>\n                    <Item ID=\"0x249B\"/>\n                    <Item ID=\"0x249C\"/>\n                    <Item ID=\"0x249D\"/>\n                    <Item ID=\"0x249E\"/>\n                    <Item ID=\"0x249F\"/>\n                    <Item ID=\"0x249a\"/>\n                    <Item ID=\"0x249c\"/>\n                    <Item ID=\"0x24A0\"/>\n                    <Item ID=\"0x24A0\"/>\n                    <Item ID=\"0x24A1\"/>\n                    <Item ID=\"0x24A2\"/>\n                    <Item ID=\"0x24A3\"/>\n                    <Item ID=\"0x24A4\"/>\n                    <Item ID=\"0x24A5\"/>\n                    <Item ID=\"0x24A6\"/>\n                    <Item ID=\"0x24A7\"/>\n                    <Item ID=\"0x24A8\"/>\n                    <Item ID=\"0x24A9\"/>\n                    <Item ID=\"0x24AA\"/>\n                    <Item ID=\"0x24AB\"/>\n                    <Item ID=\"0x24AC\"/>\n                    <Item ID=\"0x2A30\"/>\n                    <Item ID=\"0x2A31\"/>\n                    <Item ID=\"0x2A32\"/>\n                    <Item ID=\"0x2A33\"/>\n                    <Item ID=\"0x2A33\"/>\n                    <Item ID=\"0x2A34\"/>\n                    <Item ID=\"0x2A34\"/>\n                    <Item ID=\"0x2A35\"/>\n                    <Item ID=\"0x2A35\"/>\n                    <Item ID=\"0x2A36\"/>\n                    <Item ID=\"0x2A36\"/>\n                    <Item ID=\"0x2A37\"/>\n                    <Item ID=\"0x2A37\"/>\n                    <Item ID=\"0x2A38\"/>\n                    <Item ID=\"0x2A38\"/>\n                    <Item ID=\"0x2A38\"/>\n                    <Item ID=\"0x2A39\"/>\n                    <Item ID=\"0x2A39\"/>\n                    <Item ID=\"0x2A3A\"/>\n                    <Item ID=\"0x2A3a\"/>\n                    <Item ID=\"0x2A3b\"/>\n                </Group>\n            </Group>\n            <Group name=\"Stone\">\n                <Group name=\"Bricks\">\n                    <Group name=\"Blueish Brick\">\n                        <Item ID=\"0x360E\"/>\n                        <Item ID=\"0x360F\"/>\n                        <Item ID=\"0x3610\"/>\n                        <Item ID=\"0x3611\"/>\n                        <Item ID=\"0x3612\"/>\n                        <Item ID=\"0x3613\"/>\n                        <Item ID=\"0x3614\"/>\n                        <Item ID=\"0x3615\"/>\n                        <Item ID=\"0x3616\"/>\n                        <Item ID=\"0x3617\"/>\n                        <Item ID=\"0x3618\"/>\n                        <Item ID=\"0x3619\"/>\n                        <Item ID=\"0x3636\"/>\n                        <Item ID=\"0x3637\"/>\n                        <Item ID=\"0x3638\"/>\n                        <Item ID=\"0x3639\"/>\n                        <Item ID=\"0x363A\"/>\n                        <Item ID=\"0x363B\"/>\n                        <Item ID=\"0x363C\"/>\n                        <Item ID=\"0x363D\"/>\n                        <Item ID=\"0x363E\"/>\n                        <Item ID=\"0x363F\"/>\n                        <Item ID=\"0x369F\"/>\n                    </Group>\n                    <Group name=\"Brownish Brick\">\n                        <Item ID=\"0x0033\"/>\n                        <Item ID=\"0x0034\"/>\n                        <Item ID=\"0x0035\"/>\n                        <Item ID=\"0x0036\"/>\n                        <Item ID=\"0x0037\"/>\n                        <Item ID=\"0x0038\"/>\n                        <Item ID=\"0x0039\"/>\n                        <Item ID=\"0x003A\"/>\n                        <Item ID=\"0x003B\"/>\n                        <Item ID=\"0x003C\"/>\n                        <Item ID=\"0x003D\"/>\n                        <Item ID=\"0x003E\"/>\n                        <Item ID=\"0x003F\"/>\n                        <Item ID=\"0x0040\"/>\n                        <Item ID=\"0x0041\"/>\n                        <Item ID=\"0x0042\"/>\n                        <Item ID=\"0x0043\"/>\n                        <Item ID=\"0x0044\"/>\n                        <Item ID=\"0x0045\"/>\n                        <Item ID=\"0x0046\"/>\n                        <Item ID=\"0x0047\"/>\n                        <Item ID=\"0x0048\"/>\n                        <Item ID=\"0x0049\"/>\n                        <Item ID=\"0x0052\"/>\n                        <Item ID=\"0x0053\"/>\n                        <Item ID=\"0x0054\"/>\n                        <Item ID=\"0x29B6\"/>\n                        <Item ID=\"0x29B7\"/>\n                        <Item ID=\"0x29B8\"/>\n                        <Item ID=\"0x29B9\"/>\n                        <Item ID=\"0x29BA\"/>\n                        <Item ID=\"0x29BB\"/>\n                        <Item ID=\"0x29BC\"/>\n                        <Item ID=\"0x29BD\"/>\n                        <Item ID=\"0x29BE\"/>\n                        <Item ID=\"0x29BF\"/>\n                    </Group>\n                    <Group name=\"Greenish Brick\">\n                        <Item ID=\"0x0241\"/>\n                        <Item ID=\"0x0242\"/>\n                        <Item ID=\"0x0243\"/>\n                        <Item ID=\"0x0244\"/>\n                        <Item ID=\"0x0245\"/>\n                        <Item ID=\"0x0246\"/>\n                        <Item ID=\"0x0247\"/>\n                        <Item ID=\"0x0248\"/>\n                        <Item ID=\"0x0249\"/>\n                        <Item ID=\"0x024A\"/>\n                        <Item ID=\"0x02F9\"/>\n                        <Item ID=\"0x02FA\"/>\n                        <Item ID=\"0x02FB\"/>\n                        <Item ID=\"0x02FC\"/>\n                        <Item ID=\"0x02FD\"/>\n                        <Item ID=\"0x02FE\"/>\n                        <Item ID=\"0x02FF\"/>\n                        <Item ID=\"0x0300\"/>\n                        <Item ID=\"0x21dd\"/>\n                        <Item ID=\"0x21de\"/>\n                        <Item ID=\"0x21df\"/>\n                        <Item ID=\"0x21e0\"/>\n                        <Item ID=\"0x21e1\"/>\n                        <Item ID=\"0x21e2\"/>\n                        <Item ID=\"0x21e3\"/>\n                        <Item ID=\"0x21e4\"/>\n                        <Item ID=\"0x21e5\"/>\n                        <Item ID=\"0x21e6\"/>\n                        <Item ID=\"0x21e7\"/>\n                        <Item ID=\"0x21e8\"/>\n                    </Group>\n                    <Group name=\"Light Brick\">\n                        <Item ID=\"0x0057\"/>\n                        <Item ID=\"0x0058\"/>\n                        <Item ID=\"0x0059\"/>\n                        <Item ID=\"0x005A\"/>\n                        <Item ID=\"0x005B\"/>\n                        <Item ID=\"0x005C\"/>\n                        <Item ID=\"0x005D\"/>\n                        <Item ID=\"0x005E\"/>\n                        <Item ID=\"0x005F\"/>\n                        <Item ID=\"0x0060\"/>\n                        <Item ID=\"0x0061\"/>\n                        <Item ID=\"0x0062\"/>\n                        <Item ID=\"0x0063\"/>\n                        <Item ID=\"0x0064\"/>\n                        <Item ID=\"0x0065\"/>\n                        <Item ID=\"0x0066\"/>\n                        <Item ID=\"0x0069\"/>\n                        <Item ID=\"0x006A\"/>\n                        <Item ID=\"0x006B\"/>\n                        <Item ID=\"0x006C\"/>\n                        <Item ID=\"0x006D\"/>\n                        <Item ID=\"0x006E\"/>\n                        <Item ID=\"0x006F\"/>\n                        <Item ID=\"0x0070\"/>\n                        <Item ID=\"0x0071\"/>\n                        <Item ID=\"0x0277\"/>\n                        <Item ID=\"0x0278\"/>\n                        <Item ID=\"0x0279\"/>\n                        <Item ID=\"0x027a\"/>\n                        <Item ID=\"0x027b\"/>\n                        <Item ID=\"0x027c\"/>\n                        <Item ID=\"0x0281\"/>\n                        <Item ID=\"0x0282\"/>\n                        <Item ID=\"0x21fd\"/>\n                        <Item ID=\"0x21ff\"/>\n                        <Item ID=\"0x2200\"/>\n                        <Item ID=\"0x2201\"/>\n                        <Item ID=\"0x2202\"/>\n                        <Item ID=\"0x29A0\"/>\n                        <Item ID=\"0x29A1\"/>\n                        <Item ID=\"0x29A2\"/>\n                        <Item ID=\"0x29A3\"/>\n                    </Group>\n                </Group>\n                <Group name=\"Precise\">\n                    <Group name=\"Dark Gray Gothic\">\n                        <Item ID=\"0x300C\"/>\n                        <Item ID=\"0x300D\"/>\n                        <Item ID=\"0x300E\"/>\n                        <Item ID=\"0x300F\"/>\n                        <Item ID=\"0x310B\"/>\n                        <Item ID=\"0x310C\"/>\n                        <Item ID=\"0x310D\"/>\n                        <Item ID=\"0x310E\"/>\n                        <Item ID=\"0x310F\"/>\n                        <Item ID=\"0x3110\"/>\n                        <Item ID=\"0x3111\"/>\n                        <Item ID=\"0x3112\"/>\n                        <Item ID=\"0x3113\"/>\n                        <Item ID=\"0x3114\"/>\n                        <Item ID=\"0x3115\"/>\n                        <Item ID=\"0x3116\"/>\n                        <Item ID=\"0x3117\"/>\n                        <Item ID=\"0x3118\"/>\n                        <Item ID=\"0x3119\"/>\n                    </Group>\n                    <Group name=\"Patterned Sandstone\">\n                        <Item ID=\"0x024C\"/>\n                        <Item ID=\"0x024D\"/>\n                        <Item ID=\"0x024E\"/>\n                        <Item ID=\"0x024F\"/>\n                        <Item ID=\"0x0250\"/>\n                        <Item ID=\"0x0251\"/>\n                        <Item ID=\"0x0252\"/>\n                        <Item ID=\"0x0253\"/>\n                        <Item ID=\"0x0254\"/>\n                        <Item ID=\"0x0255\"/>\n                        <Item ID=\"0x0256\"/>\n                        <Item ID=\"0x0257\"/>\n                        <Item ID=\"0x0258\"/>\n                        <Item ID=\"0x0259\"/>\n                        <Item ID=\"0x025A\"/>\n                        <Item ID=\"0x025B\"/>\n                    </Group>\n                    <Group name=\"Precise Gray\">\n                        <Group name=\"Battlements\">\n                            <Item ID=\"0x02C7\"/>\n                            <Item ID=\"0x02C8\"/>\n                            <Item ID=\"0x02C9\"/>\n                            <Item ID=\"0x02CA\"/>\n                            <Item ID=\"0x02CB\"/>\n                            <Item ID=\"0x02CC\"/>\n                            <Item ID=\"0x02CD\"/>\n                        </Group>\n                        <Item ID=\"0x007A\"/>\n                        <Item ID=\"0x007B\"/>\n                        <Item ID=\"0x007C\"/>\n                        <Item ID=\"0x007D\"/>\n                        <Item ID=\"0x007E\"/>\n                        <Item ID=\"0x007F\"/>\n                        <Item ID=\"0x0081\"/>\n                        <Item ID=\"0x0086\"/>\n                        <Item ID=\"0x0087\"/>\n                        <Item ID=\"0x0088\"/>\n                        <Item ID=\"0x0089\"/>\n                        <Item ID=\"0x008A\"/>\n                        <Item ID=\"0x008B\"/>\n                        <Item ID=\"0x008C\"/>\n                        <Item ID=\"0x008D\"/>\n                        <Item ID=\"0x008E\"/>\n                        <Item ID=\"0x008F\"/>\n                        <Item ID=\"0x02CE\"/>\n                        <Item ID=\"0x02CF\"/>\n                        <Item ID=\"0x02D0\"/>\n                        <Item ID=\"0x02D1\"/>\n                        <Item ID=\"0x02D3\"/>\n                        <Item ID=\"0x02D4\"/>\n                        <Item ID=\"0x02D7\"/>\n                        <Item ID=\"0x02D8\"/>\n                        <Item ID=\"0x0354\"/>\n                        <Item ID=\"0x035C\"/>\n                    </Group>\n                    <Group name=\"Sandstone 1\">\n                        <Group name=\"Battlements\">\n                            <Item ID=\"0x0173\"/>\n                            <Item ID=\"0x0179\"/>\n                            <Item ID=\"0x017A\"/>\n                            <Item ID=\"0x017B\"/>\n                            <Item ID=\"0x017C\"/>\n                            <Item ID=\"0x017D\"/>\n                            <Item ID=\"0x01A4\"/>\n                        </Group>\n                        <Item ID=\"0x0158\"/>\n                        <Item ID=\"0x0159\"/>\n                        <Item ID=\"0x015A\"/>\n                        <Item ID=\"0x015B\"/>\n                        <Item ID=\"0x015C\"/>\n                        <Item ID=\"0x015D\"/>\n                        <Item ID=\"0x015E\"/>\n                        <Item ID=\"0x015F\"/>\n                        <Item ID=\"0x0160\"/>\n                        <Item ID=\"0x0161\"/>\n                        <Item ID=\"0x0162\"/>\n                        <Item ID=\"0x0163\"/>\n                        <Item ID=\"0x0164\"/>\n                        <Item ID=\"0x0165\"/>\n                        <Item ID=\"0x0166\"/>\n                        <Item ID=\"0x0167\"/>\n                        <Item ID=\"0x0168\"/>\n                        <Item ID=\"0x0169\"/>\n                        <Item ID=\"0x016A\"/>\n                        <Item ID=\"0x016B\"/>\n                        <Item ID=\"0x016C\"/>\n                        <Item ID=\"0x016D\"/>\n                        <Item ID=\"0x016E\"/>\n                        <Item ID=\"0x016F\"/>\n                        <Item ID=\"0x0170\"/>\n                        <Item ID=\"0x0171\"/>\n                        <Item ID=\"0x0172\"/>\n                        <Item ID=\"0x0174\"/>\n                        <Item ID=\"0x017E\"/>\n                        <Item ID=\"0x017F\"/>\n                        <Item ID=\"0x0180\"/>\n                        <Item ID=\"0x0181\"/>\n                        <Item ID=\"0x0182\"/>\n                        <Item ID=\"0x0183\"/>\n                        <Item ID=\"0x0186\"/>\n                        <Item ID=\"0x0187\"/>\n                        <Item ID=\"0x0188\"/>\n                        <Item ID=\"0x0189\"/>\n                        <Item ID=\"0x018A\"/>\n                        <Item ID=\"0x018B\"/>\n                        <Item ID=\"0x018C\"/>\n                        <Item ID=\"0x018D\"/>\n                        <Item ID=\"0x0190\"/>\n                        <Item ID=\"0x0191\"/>\n                        <Item ID=\"0x0192\"/>\n                        <Item ID=\"0x0193\"/>\n                        <Item ID=\"0x0194\"/>\n                        <Item ID=\"0x0195\"/>\n                        <Item ID=\"0x0196\"/>\n                        <Item ID=\"0x0197\"/>\n                        <Item ID=\"0x0198\"/>\n                        <Item ID=\"0x0199\"/>\n                        <Item ID=\"0x019A\"/>\n                        <Item ID=\"0x01B1\"/>\n                        <Item ID=\"0x01B2\"/>\n                        <Item ID=\"0x01B3\"/>\n                        <Item ID=\"0x01B4\"/>\n                        <Item ID=\"0x01CA\"/>\n                        <Item ID=\"0x0202\"/>\n                        <Item ID=\"0x0769\"/>\n                        <Item ID=\"0x076A\"/>\n                        <Item ID=\"0x076B\"/>\n                        <Item ID=\"0x0781\"/>\n                    </Group>\n                    <Group name=\"Tall Gray Gothic\">\n                        <Item ID=\"0x2FEC\"/>\n                        <Item ID=\"0x2FED\"/>\n                        <Item ID=\"0x2FFB\"/>\n                        <Item ID=\"0x2FFC\"/>\n                        <Item ID=\"0x2FFD\"/>\n                        <Item ID=\"0x2FFE\"/>\n                        <Item ID=\"0x2FFF\"/>\n                        <Item ID=\"0x2FFd\"/>\n                        <Item ID=\"0x2FFe\"/>\n                        <Item ID=\"0x3001\"/>\n                        <Item ID=\"0x3008\"/>\n                        <Item ID=\"0x3008\"/>\n                        <Item ID=\"0x3009\"/>\n                        <Item ID=\"0x300A\"/>\n                        <Item ID=\"0x300B\"/>\n                        <Item ID=\"0x300a\"/>\n                        <Item ID=\"0x300b\"/>\n                        <Item ID=\"0x300c\"/>\n                        <Item ID=\"0x300d\"/>\n                        <Item ID=\"0x300e\"/>\n                        <Item ID=\"0x300f\"/>\n                        <Item ID=\"0x3010\"/>\n                        <Item ID=\"0x3010\"/>\n                        <Item ID=\"0x3011\"/>\n                        <Item ID=\"0x3012\"/>\n                        <Item ID=\"0x3012\"/>\n                        <Item ID=\"0x3013\"/>\n                        <Item ID=\"0x3013\"/>\n                        <Item ID=\"0x3014\"/>\n                        <Item ID=\"0x3014\"/>\n                        <Item ID=\"0x3015\"/>\n                        <Item ID=\"0x3016\"/>\n                        <Item ID=\"0x3016\"/>\n                        <Item ID=\"0x3017\"/>\n                        <Item ID=\"0x3017\"/>\n                        <Item ID=\"0x311A\"/>\n                        <Item ID=\"0x311B\"/>\n                        <Item ID=\"0x311C\"/>\n                        <Item ID=\"0x311D\"/>\n                        <Item ID=\"0x311E\"/>\n                        <Item ID=\"0x311F\"/>\n                        <Item ID=\"0x3120\"/>\n                        <Item ID=\"0x3121\"/>\n                    </Group>\n                </Group>\n                <Group name=\"Rough + Worn\">\n                    <Group name=\"Black Block\">\n                        <Item ID=\"0x3674\"/>\n                        <Item ID=\"0x3675\"/>\n                        <Item ID=\"0x3676\"/>\n                        <Item ID=\"0x3677\"/>\n                    </Group>\n                    <Group name=\"Brownish Blocks\">\n                        <Group name=\"Battlements\">\n                            <Item ID=\"0x01DA\"/>\n                            <Item ID=\"0x01E1\"/>\n                            <Item ID=\"0x01E2\"/>\n                            <Item ID=\"0x01E3\"/>\n                            <Item ID=\"0x01E4\"/>\n                            <Item ID=\"0x01E6\"/>\n                            <Item ID=\"0x01E7\"/>\n                        </Group>\n                        <Item ID=\"0x01CF\"/>\n                        <Item ID=\"0x01D0\"/>\n                        <Item ID=\"0x01D1\"/>\n                        <Item ID=\"0x01D2\"/>\n                        <Item ID=\"0x01D3\"/>\n                        <Item ID=\"0x01D4\"/>\n                        <Item ID=\"0x01D5\"/>\n                        <Item ID=\"0x01D6\"/>\n                        <Item ID=\"0x01D7\"/>\n                        <Item ID=\"0x01D8\"/>\n                        <Item ID=\"0x01D9\"/>\n                        <Item ID=\"0x01DB\"/>\n                        <Item ID=\"0x01DC\"/>\n                        <Item ID=\"0x01DD\"/>\n                        <Item ID=\"0x01DE\"/>\n                        <Item ID=\"0x01DF\"/>\n                        <Item ID=\"0x01E8\"/>\n                        <Item ID=\"0x01E9\"/>\n                        <Item ID=\"0x01EA\"/>\n                        <Item ID=\"0x01EB\"/>\n                        <Item ID=\"0x29A4\"/>\n                        <Item ID=\"0x29A5\"/>\n                        <Item ID=\"0x29A6\"/>\n                        <Item ID=\"0x29A7\"/>\n                        <Item ID=\"0x29A8\"/>\n                        <Item ID=\"0x29A9\"/>\n                        <Item ID=\"0x29AA\"/>\n                        <Item ID=\"0x29AB\"/>\n                    </Group>\n                    <Group name=\"Brownish Round\">\n                        <Item ID=\"0x253f\"/>\n                        <Item ID=\"0x2540\"/>\n                        <Item ID=\"0x2541\"/>\n                        <Item ID=\"0x2542\"/>\n                        <Item ID=\"0x2543\"/>\n                        <Item ID=\"0x2544\"/>\n                        <Item ID=\"0x2545\"/>\n                        <Item ID=\"0x2546\"/>\n                        <Item ID=\"0x2547\"/>\n                        <Item ID=\"0x2548\"/>\n                        <Item ID=\"0x2549\"/>\n                        <Item ID=\"0x254a\"/>\n                        <Item ID=\"0x254b\"/>\n                        <Item ID=\"0x254c\"/>\n                        <Item ID=\"0x254d\"/>\n                        <Item ID=\"0x254e\"/>\n                        <Item ID=\"0x254f\"/>\n                        <Item ID=\"0x2550\"/>\n                        <Item ID=\"0x2551\"/>\n                        <Item ID=\"0x2552\"/>\n                        <Item ID=\"0x2553\"/>\n                        <Item ID=\"0x3EF2\"/>\n                        <Item ID=\"0x3EF3\"/>\n                        <Item ID=\"0x3EF4\"/>\n                        <Item ID=\"0x3EF5\"/>\n                        <Item ID=\"0x3EF6\"/>\n                        <Item ID=\"0x3EF7\"/>\n                        <Item ID=\"0x3EF8\"/>\n                        <Item ID=\"0x3EF9\"/>\n                        <Item ID=\"0x3EFA\"/>\n                        <Item ID=\"0x3EFB\"/>\n                        <Item ID=\"0x3EFC\"/>\n                        <Item ID=\"0x3EFD\"/>\n                        <Item ID=\"0x3EFE\"/>\n                        <Item ID=\"0x3EFF\"/>\n                        <Item ID=\"0x3F00\"/>\n                        <Item ID=\"0x3F01\"/>\n                        <Item ID=\"0x3F02\"/>\n                        <Item ID=\"0x3F03\"/>\n                        <Item ID=\"0x3F04\"/>\n                        <Item ID=\"0x3F05\"/>\n                        <Item ID=\"0x3F06\"/>\n                        <Item ID=\"0x3ef2\"/>\n                        <Item ID=\"0x3ef3\"/>\n                        <Item ID=\"0x3ef4\"/>\n                        <Item ID=\"0x3ef5\"/>\n                        <Item ID=\"0x3ef6\"/>\n                        <Item ID=\"0x3ef7\"/>\n                        <Item ID=\"0x3ef8\"/>\n                        <Item ID=\"0x3ef9\"/>\n                        <Item ID=\"0x3efa\"/>\n                        <Item ID=\"0x3efb\"/>\n                        <Item ID=\"0x3efc\"/>\n                        <Item ID=\"0x3efd\"/>\n                        <Item ID=\"0x3efe\"/>\n                        <Item ID=\"0x3eff\"/>\n                        <Item ID=\"0x3f00\"/>\n                        <Item ID=\"0x3f01\"/>\n                        <Item ID=\"0x3f02\"/>\n                        <Item ID=\"0x3f03\"/>\n                        <Item ID=\"0x3f04\"/>\n                        <Item ID=\"0x3f05\"/>\n                        <Item ID=\"0x3f06\"/>\n                    </Group>\n                    <Group name=\"Gray Block\">\n                        <Group name=\"Battlements\">\n                            <Item ID=\"0x00D2\"/>\n                            <Item ID=\"0x00D3\"/>\n                            <Item ID=\"0x00DB\"/>\n                            <Item ID=\"0x00E0\"/>\n                            <Item ID=\"0x00E1\"/>\n                            <Item ID=\"0x00E2\"/>\n                            <Item ID=\"0x00E3\"/>\n                        </Group>\n                        <Item ID=\"0x00C5\"/>\n                        <Item ID=\"0x00C7\"/>\n                        <Item ID=\"0x00C8\"/>\n                        <Item ID=\"0x00C9\"/>\n                        <Item ID=\"0x00CA\"/>\n                        <Item ID=\"0x00CB\"/>\n                        <Item ID=\"0x00CC\"/>\n                        <Item ID=\"0x00CD\"/>\n                        <Item ID=\"0x00CE\"/>\n                        <Item ID=\"0x00CF\"/>\n                        <Item ID=\"0x00D0\"/>\n                        <Item ID=\"0x00D1\"/>\n                        <Item ID=\"0x00D4\"/>\n                        <Item ID=\"0x00D7\"/>\n                        <Item ID=\"0x00D8\"/>\n                        <Item ID=\"0x00D9\"/>\n                        <Item ID=\"0x00DA\"/>\n                        <Item ID=\"0x00DC\"/>\n                        <Item ID=\"0x00DD\"/>\n                        <Item ID=\"0x00DE\"/>\n                        <Item ID=\"0x00DF\"/>\n                    </Group>\n                    <Group name=\"Light Boulder\">\n                        <Item ID=\"0x001A\"/>\n                        <Item ID=\"0x001B\"/>\n                        <Item ID=\"0x001C\"/>\n                        <Item ID=\"0x001D\"/>\n                        <Item ID=\"0x001E\"/>\n                        <Item ID=\"0x001F\"/>\n                        <Item ID=\"0x0020\"/>\n                        <Item ID=\"0x0021\"/>\n                        <Item ID=\"0x0022\"/>\n                        <Item ID=\"0x0023\"/>\n                        <Item ID=\"0x0024\"/>\n                        <Item ID=\"0x0025\"/>\n                        <Item ID=\"0x0026\"/>\n                        <Item ID=\"0x0027\"/>\n                        <Item ID=\"0x0028\"/>\n                        <Item ID=\"0x0029\"/>\n                        <Item ID=\"0x002A\"/>\n                        <Item ID=\"0x002B\"/>\n                        <Item ID=\"0x002C\"/>\n                        <Item ID=\"0x002D\"/>\n                        <Item ID=\"0x002E\"/>\n                        <Item ID=\"0x002F\"/>\n                        <Item ID=\"0x0030\"/>\n                        <Item ID=\"0x0031\"/>\n                        <Item ID=\"0x0032\"/>\n                        <Item ID=\"0x29AC\"/>\n                        <Item ID=\"0x29AD\"/>\n                        <Item ID=\"0x29AE\"/>\n                        <Item ID=\"0x29AF\"/>\n                        <Item ID=\"0x29B0\"/>\n                        <Item ID=\"0x29B1\"/>\n                        <Item ID=\"0x29B2\"/>\n                        <Item ID=\"0x29B3\"/>\n                        <Item ID=\"0x29B4\"/>\n                        <Item ID=\"0x29B5\"/>\n                        <Item ID=\"0x3127\"/>\n                    </Group>\n                </Group>\n            </Group>\n            <Group name=\"Wood\">\n                <Group name=\"Black Board\">\n                    <Item ID=\"0x248D\"/>\n                    <Item ID=\"0x248E\"/>\n                    <Item ID=\"0x248F\"/>\n                    <Item ID=\"0x248b\"/>\n                    <Item ID=\"0x248c\"/>\n                    <Item ID=\"0x2490\"/>\n                    <Item ID=\"0x2491\"/>\n                    <Item ID=\"0x2492\"/>\n                    <Item ID=\"0x2493\"/>\n                    <Item ID=\"0x2494\"/>\n                    <Item ID=\"0x2495\"/>\n                    <Item ID=\"0x2496\"/>\n                    <Item ID=\"0x2497\"/>\n                    <Item ID=\"0x2498\"/>\n                </Group>\n                <Group name=\"Brown Floral\">\n                    <Item ID=\"0x2D14\"/>\n                    <Item ID=\"0x2D15\"/>\n                    <Item ID=\"0x2D16\"/>\n                    <Item ID=\"0x2D17\"/>\n                    <Item ID=\"0x2D18\"/>\n                    <Item ID=\"0x2D19\"/>\n                    <Item ID=\"0x2D1A\"/>\n                    <Item ID=\"0x2D1B\"/>\n                    <Item ID=\"0x2D1C\"/>\n                    <Item ID=\"0x2D1D\"/>\n                    <Item ID=\"0x2D36\"/>\n                    <Item ID=\"0x2D37\"/>\n                    <Item ID=\"0x2D3C\"/>\n                    <Item ID=\"0x2D3D\"/>\n                    <Item ID=\"0x2D3E\"/>\n                    <Item ID=\"0x2D3F\"/>\n                    <Item ID=\"0x2D40\"/>\n                    <Item ID=\"0x2D41\"/>\n                    <Item ID=\"0x2D42\"/>\n                    <Item ID=\"0x2D43\"/>\n                    <Item ID=\"0x2D44\"/>\n                    <Item ID=\"0x2D45\"/>\n                    <Item ID=\"0x2DFB\"/>\n                    <Item ID=\"0x2DFC\"/>\n                    <Item ID=\"0x2DFD\"/>\n                    <Item ID=\"0x2DFE\"/>\n                    <Item ID=\"0x2F1E\"/>\n                </Group>\n                <Group name=\"Cloth Frame\">\n                    <Item ID=\"0x2888\"/>\n                    <Item ID=\"0x2889\"/>\n                    <Item ID=\"0x288a\"/>\n                    <Item ID=\"0x288b\"/>\n                    <Item ID=\"0x288c\"/>\n                    <Item ID=\"0x288d\"/>\n                    <Item ID=\"0x288e\"/>\n                    <Item ID=\"0x288f\"/>\n                    <Item ID=\"0x2890\"/>\n                    <Item ID=\"0x2891\"/>\n                    <Item ID=\"0x2892\"/>\n                    <Item ID=\"0x2893\"/>\n                    <Item ID=\"0x2894\"/>\n                    <Item ID=\"0x2895\"/>\n                    <Item ID=\"0x2896\"/>\n                    <Item ID=\"0x2897\"/>\n                    <Item ID=\"0x2898\"/>\n                    <Item ID=\"0x2899\"/>\n                    <Item ID=\"0x289a\"/>\n                    <Item ID=\"0x289b\"/>\n                    <Item ID=\"0x289c\"/>\n                    <Item ID=\"0x289d\"/>\n                    <Item ID=\"0x289e\"/>\n                    <Item ID=\"0x289f\"/>\n                    <Item ID=\"0x28a0\"/>\n                    <Item ID=\"0x28a1\"/>\n                    <Item ID=\"0x28a2\"/>\n                    <Item ID=\"0x28a3\"/>\n                </Group>\n                <Group name=\"Dark Board\">\n                    <Item ID=\"0x0006\"/>\n                    <Item ID=\"0x0007\"/>\n                    <Item ID=\"0x0008\"/>\n                    <Item ID=\"0x0009\"/>\n                    <Item ID=\"0x000A\"/>\n                    <Item ID=\"0x000B\"/>\n                    <Item ID=\"0x000C\"/>\n                    <Item ID=\"0x000D\"/>\n                    <Item ID=\"0x000E\"/>\n                    <Item ID=\"0x000F\"/>\n                    <Item ID=\"0x0010\"/>\n                    <Item ID=\"0x0011\"/>\n                    <Item ID=\"0x0012\"/>\n                    <Item ID=\"0x0013\"/>\n                    <Item ID=\"0x0014\"/>\n                    <Item ID=\"0x0015\"/>\n                    <Item ID=\"0x0016\"/>\n                    <Item ID=\"0x0017\"/>\n                </Group>\n                <Group name=\"Dark Latticed\">\n                    <Item ID=\"0x2753\"/>\n                    <Item ID=\"0x2754\"/>\n                    <Item ID=\"0x2755\"/>\n                    <Item ID=\"0x275A\"/>\n                    <Item ID=\"0x275B\"/>\n                    <Item ID=\"0x275C\"/>\n                    <Item ID=\"0x275D\"/>\n                    <Item ID=\"0x275E\"/>\n                    <Item ID=\"0x275F\"/>\n                    <Item ID=\"0x2760\"/>\n                    <Item ID=\"0x2761\"/>\n                    <Item ID=\"0x2762\"/>\n                </Group>\n                <Group name=\"Dark Panel\">\n                    <Item ID=\"0x2992\"/>\n                    <Item ID=\"0x2993\"/>\n                    <Item ID=\"0x2994\"/>\n                    <Item ID=\"0x2995\"/>\n                    <Item ID=\"0x2996\"/>\n                    <Item ID=\"0x2997\"/>\n                    <Item ID=\"0x2998\"/>\n                    <Item ID=\"0x2999\"/>\n                    <Item ID=\"0x299A\"/>\n                    <Item ID=\"0x299B\"/>\n                    <Item ID=\"0x299C\"/>\n                    <Item ID=\"0x299D\"/>\n                </Group>\n                <Group name=\"Light Boards\">\n                    <Item ID=\"0x00A6\"/>\n                    <Item ID=\"0x00A7\"/>\n                    <Item ID=\"0x00A8\"/>\n                    <Item ID=\"0x00A9\"/>\n                    <Item ID=\"0x00AA\"/>\n                    <Item ID=\"0x00AB\"/>\n                    <Item ID=\"0x00AC\"/>\n                    <Item ID=\"0x00AD\"/>\n                    <Item ID=\"0x00AE\"/>\n                    <Item ID=\"0x00AF\"/>\n                    <Item ID=\"0x00B0\"/>\n                    <Item ID=\"0x00B1\"/>\n                    <Item ID=\"0x00B2\"/>\n                    <Item ID=\"0x00B3\"/>\n                    <Item ID=\"0x00B4\"/>\n                    <Item ID=\"0x00B5\"/>\n                    <Item ID=\"0x00B9\"/>\n                    <Item ID=\"0x00BA\"/>\n                    <Item ID=\"0x00BB\"/>\n                    <Item ID=\"0x00BC\"/>\n                    <Item ID=\"0x00BD\"/>\n                    <Item ID=\"0x00BE\"/>\n                    <Item ID=\"0x00BF\"/>\n                    <Item ID=\"0x00C0\"/>\n                    <Item ID=\"0x03B3\"/>\n                    <Item ID=\"0x03B4\"/>\n                    <Item ID=\"0x03B5\"/>\n                    <Item ID=\"0x03B6\"/>\n                    <Item ID=\"0x21cd\"/>\n                    <Item ID=\"0x21ce\"/>\n                    <Item ID=\"0x21cf\"/>\n                    <Item ID=\"0x21d0\"/>\n                    <Item ID=\"0x21d1\"/>\n                    <Item ID=\"0x21d2\"/>\n                    <Item ID=\"0x21d3\"/>\n                    <Item ID=\"0x21d4\"/>\n                    <Item ID=\"0x21d5\"/>\n                    <Item ID=\"0x21d6\"/>\n                    <Item ID=\"0x21d7\"/>\n                    <Item ID=\"0x21d8\"/>\n                    <Item ID=\"0x21d9\"/>\n                    <Item ID=\"0x21da\"/>\n                    <Item ID=\"0x21db\"/>\n                    <Item ID=\"0x21dc\"/>\n                    <Item ID=\"0x2500\"/>\n                    <Item ID=\"0x2501\"/>\n                    <Item ID=\"0x2502\"/>\n                    <Item ID=\"0x2503\"/>\n                    <Item ID=\"0x2504\"/>\n                    <Item ID=\"0x2505\"/>\n                    <Item ID=\"0x2506\"/>\n                    <Item ID=\"0x2507\"/>\n                    <Item ID=\"0x2508\"/>\n                    <Item ID=\"0x2509\"/>\n                    <Item ID=\"0x250A\"/>\n                    <Item ID=\"0x250b\"/>\n                </Group>\n                <Group name=\"Light Latticed\">\n                    <Item ID=\"0x2713\"/>\n                    <Item ID=\"0x2714\"/>\n                    <Item ID=\"0x2715\"/>\n                    <Item ID=\"0x2716\"/>\n                    <Item ID=\"0x2717\"/>\n                    <Item ID=\"0x2718\"/>\n                    <Item ID=\"0x2719\"/>\n                    <Item ID=\"0x271A\"/>\n                    <Item ID=\"0x271B\"/>\n                    <Item ID=\"0x271C\"/>\n                    <Item ID=\"0x271D\"/>\n                    <Item ID=\"0x271E\"/>\n                    <Item ID=\"0x271F\"/>\n                    <Item ID=\"0x275A\"/>\n                    <Item ID=\"0x275B\"/>\n                    <Item ID=\"0x275C\"/>\n                </Group>\n                <Group name=\"Light Panel\">\n                    <Item ID=\"0x247F\"/>\n                    <Item ID=\"0x2480\"/>\n                    <Item ID=\"0x2481\"/>\n                    <Item ID=\"0x2482\"/>\n                    <Item ID=\"0x2483\"/>\n                    <Item ID=\"0x2484\"/>\n                    <Item ID=\"0x2485\"/>\n                    <Item ID=\"0x2486\"/>\n                    <Item ID=\"0x2487\"/>\n                    <Item ID=\"0x2488\"/>\n                    <Item ID=\"0x2489\"/>\n                    <Item ID=\"0x248A\"/>\n                </Group>\n                <Group name=\"Log\">\n                    <Item ID=\"0x0090\"/>\n                    <Item ID=\"0x0091\"/>\n                    <Item ID=\"0x0092\"/>\n                    <Item ID=\"0x0093\"/>\n                    <Item ID=\"0x0094\"/>\n                    <Item ID=\"0x0095\"/>\n                    <Item ID=\"0x0096\"/>\n                    <Item ID=\"0x0097\"/>\n                    <Item ID=\"0x0098\"/>\n                    <Item ID=\"0x0099\"/>\n                    <Item ID=\"0x009A\"/>\n                    <Item ID=\"0x009B\"/>\n                    <Item ID=\"0x009C\"/>\n                    <Item ID=\"0x009D\"/>\n                    <Item ID=\"0x009E\"/>\n                    <Item ID=\"0x009F\"/>\n                    <Item ID=\"0x00A0\"/>\n                    <Item ID=\"0x00A1\"/>\n                    <Item ID=\"0x00A2\"/>\n                    <Item ID=\"0x00A3\"/>\n                    <Item ID=\"0x00A4\"/>\n                    <Item ID=\"0x00A5\"/>\n                    <Item ID=\"0x0145\"/>\n                    <Item ID=\"0x0146\"/>\n                    <Item ID=\"0x0147\"/>\n                    <Item ID=\"0x0148\"/>\n                    <Item ID=\"0x21af\"/>\n                    <Item ID=\"0x21b0\"/>\n                    <Item ID=\"0x21b1\"/>\n                    <Item ID=\"0x21b2\"/>\n                    <Item ID=\"0x21b3\"/>\n                    <Item ID=\"0x21b4\"/>\n                    <Item ID=\"0x21b5\"/>\n                    <Item ID=\"0x21b6\"/>\n                    <Item ID=\"0x21b7\"/>\n                    <Item ID=\"0x21b8\"/>\n                    <Item ID=\"0x21bd\"/>\n                    <Item ID=\"0x21be\"/>\n                    <Item ID=\"0x21bf\"/>\n                    <Item ID=\"0x21c0\"/>\n                    <Item ID=\"0x21c1\"/>\n                    <Item ID=\"0x21c2\"/>\n                    <Item ID=\"0x21c3\"/>\n                    <Item ID=\"0x21c4\"/>\n                    <Item ID=\"0x21c5\"/>\n                    <Item ID=\"0x21c6\"/>\n                    <Item ID=\"0x21c7\"/>\n                    <Item ID=\"0x21c8\"/>\n                    <Item ID=\"0x21c9\"/>\n                    <Item ID=\"0x21ca\"/>\n                    <Item ID=\"0x21cb\"/>\n                    <Item ID=\"0x21cc\"/>\n                    <Item ID=\"0x24F4\"/>\n                    <Item ID=\"0x24F5\"/>\n                    <Item ID=\"0x24F6\"/>\n                    <Item ID=\"0x24F8\"/>\n                    <Item ID=\"0x24FA\"/>\n                    <Item ID=\"0x24FB\"/>\n                    <Item ID=\"0x24FC\"/>\n                    <Item ID=\"0x24FE\"/>\n                    <Item ID=\"0x24f7\"/>\n                    <Item ID=\"0x24f9\"/>\n                    <Item ID=\"0x24fd\"/>\n                    <Item ID=\"0x24ff\"/>\n                </Group>\n                <Group name=\"Palisade\">\n                    <Item ID=\"0x021D\"/>\n                    <Item ID=\"0x021E\"/>\n                    <Item ID=\"0x021F\"/>\n                    <Item ID=\"0x0220\"/>\n                    <Item ID=\"0x0221\"/>\n                    <Item ID=\"0x0222\"/>\n                    <Item ID=\"0x0223\"/>\n                    <Item ID=\"0x0226\"/>\n                    <Item ID=\"0x0227\"/>\n                    <Item ID=\"0x0228\"/>\n                    <Item ID=\"0x0229\"/>\n                    <Item ID=\"0x022A\"/>\n                    <Item ID=\"0x022B\"/>\n                    <Item ID=\"0x0421\"/>\n                    <Item ID=\"0x0422\"/>\n                    <Item ID=\"0x0423\"/>\n                    <Item ID=\"0x0424\"/>\n                    <Item ID=\"0x0425\"/>\n                    <Item ID=\"0x0430\"/>\n                    <Item ID=\"0x0431\"/>\n                    <Item ID=\"0x2188\"/>\n                    <Item ID=\"0x2189\"/>\n                    <Item ID=\"0x218a\"/>\n                    <Item ID=\"0x218b\"/>\n                    <Item ID=\"0x218c\"/>\n                    <Item ID=\"0x218d\"/>\n                    <Item ID=\"0x218e\"/>\n                    <Item ID=\"0x218f\"/>\n                    <Item ID=\"0x2190\"/>\n                    <Item ID=\"0x2191\"/>\n                    <Item ID=\"0x2192\"/>\n                    <Item ID=\"0x2193\"/>\n                    <Item ID=\"0x2194\"/>\n                    <Item ID=\"0x2195\"/>\n                    <Item ID=\"0x2196\"/>\n                    <Item ID=\"0x2197\"/>\n                    <Item ID=\"0x21a5\"/>\n                    <Item ID=\"0x21a6\"/>\n                    <Item ID=\"0x21a7\"/>\n                    <Item ID=\"0x21a8\"/>\n                    <Item ID=\"0x21a9\"/>\n                    <Item ID=\"0x21aa\"/>\n                    <Item ID=\"0x21ab\"/>\n                    <Item ID=\"0x21ac\"/>\n                    <Item ID=\"0x21ad\"/>\n                    <Item ID=\"0x21ae\"/>\n                </Group>\n                <Group name=\"Pink Floral\">\n                    <Item ID=\"0x2BA9\"/>\n                    <Item ID=\"0x2BAA\"/>\n                    <Item ID=\"0x2BAB\"/>\n                    <Item ID=\"0x2BAC\"/>\n                    <Item ID=\"0x2BAD\"/>\n                    <Item ID=\"0x2BAE\"/>\n                    <Item ID=\"0x2BAF\"/>\n                    <Item ID=\"0x2BB0\"/>\n                    <Item ID=\"0x2BB1\"/>\n                    <Item ID=\"0x2BB2\"/>\n                    <Item ID=\"0x2BB3\"/>\n                    <Item ID=\"0x2BB4\"/>\n                    <Item ID=\"0x2BB9\"/>\n                    <Item ID=\"0x2BBA\"/>\n                    <Item ID=\"0x2BBB\"/>\n                    <Item ID=\"0x2BBC\"/>\n                    <Item ID=\"0x2BBD\"/>\n                    <Item ID=\"0x2BBE\"/>\n                    <Item ID=\"0x2BBF\"/>\n                    <Item ID=\"0x2BC0\"/>\n                    <Item ID=\"0x2BC1\"/>\n                    <Item ID=\"0x2BC2\"/>\n                    <Item ID=\"0x2F1C\"/>\n                </Group>\n                <Group name=\"Reddish Floral\">\n                    <Item ID=\"0x2BC3\"/>\n                    <Item ID=\"0x2BC4\"/>\n                    <Item ID=\"0x2BC5\"/>\n                    <Item ID=\"0x2BC6\"/>\n                    <Item ID=\"0x2BC7\"/>\n                    <Item ID=\"0x2BC8\"/>\n                    <Item ID=\"0x2BC9\"/>\n                    <Item ID=\"0x2BCA\"/>\n                    <Item ID=\"0x2BCB\"/>\n                    <Item ID=\"0x2BCC\"/>\n                    <Item ID=\"0x2CEF\"/>\n                    <Item ID=\"0x2CF0\"/>\n                    <Item ID=\"0x2CF1\"/>\n                    <Item ID=\"0x2CF2\"/>\n                    <Item ID=\"0x2CF3\"/>\n                    <Item ID=\"0x2CF4\"/>\n                    <Item ID=\"0x2CF5\"/>\n                    <Item ID=\"0x2CF6\"/>\n                    <Item ID=\"0x2CF7\"/>\n                    <Item ID=\"0x2CF8\"/>\n                    <Item ID=\"0x2F1D\"/>\n                </Group>\n                <Group name=\"Yellow Board\">\n                    <Item ID=\"0x285f\"/>\n                    <Item ID=\"0x2860\"/>\n                    <Item ID=\"0x2861\"/>\n                    <Item ID=\"0x2862\"/>\n                    <Item ID=\"0x2863\"/>\n                    <Item ID=\"0x2864\"/>\n                    <Item ID=\"0x2865\"/>\n                    <Item ID=\"0x2866\"/>\n                    <Item ID=\"0x2867\"/>\n                    <Item ID=\"0x2868\"/>\n                    <Item ID=\"0x2869\"/>\n                    <Item ID=\"0x286a\"/>\n                    <Item ID=\"0x286b\"/>\n                    <Item ID=\"0x286c\"/>\n                    <Item ID=\"0x286d\"/>\n                </Group>\n                <Group name=\"Yellow Floral\">\n                    <Item ID=\"0x2B7A\"/>\n                    <Item ID=\"0x2B7B\"/>\n                    <Item ID=\"0x2B7C\"/>\n                    <Item ID=\"0x2B7D\"/>\n                    <Item ID=\"0x2B7E\"/>\n                    <Item ID=\"0x2B7F\"/>\n                    <Item ID=\"0x2B80\"/>\n                    <Item ID=\"0x2DBF\"/>\n                    <Item ID=\"0x2DC0\"/>\n                    <Item ID=\"0x2DC1\"/>\n                    <Item ID=\"0x2DC2\"/>\n                    <Item ID=\"0x2DC3\"/>\n                    <Item ID=\"0x2DC4\"/>\n                    <Item ID=\"0x2DC5\"/>\n                    <Item ID=\"0x2DC6\"/>\n                    <Item ID=\"0x2DC7\"/>\n                    <Item ID=\"0x2DC8\"/>\n                    <Item ID=\"0x2DC9\"/>\n                    <Item ID=\"0x2DCA\"/>\n                    <Item ID=\"0x2DCF\"/>\n                    <Item ID=\"0x2DD0\"/>\n                    <Item ID=\"0x2DD1\"/>\n                    <Item ID=\"0x2DF7\"/>\n                    <Item ID=\"0x2DF8\"/>\n                    <Item ID=\"0x2DF9\"/>\n                    <Item ID=\"0x2DFA\"/>\n                    <Item ID=\"0x2F1B\"/>\n                </Group>\n            </Group>\n        </Group>\n    </Group>\n    <Group name=\"Creepy and Barbarism\">\n        <Group name=\"Barbaric\">\n            <Item ID=\"0x041F\"/>\n            <Item ID=\"0x0420\"/>\n            <Item ID=\"0x0426\"/>\n            <Item ID=\"0x0427\"/>\n            <Item ID=\"0x0428\"/>\n            <Item ID=\"0x0429\"/>\n            <Item ID=\"0x042A\"/>\n            <Item ID=\"0x042B\"/>\n            <Item ID=\"0x042C\"/>\n            <Item ID=\"0x042D\"/>\n            <Item ID=\"0x042E\"/>\n            <Item ID=\"0x042F\"/>\n            <Item ID=\"0x1096\"/>\n            <Item ID=\"0x2F59\"/>\n            <Item ID=\"0x2F5A\"/>\n            <Item ID=\"0x2F5B\"/>\n            <Item ID=\"0x2F5C\"/>\n            <Item ID=\"0x364C\"/>\n            <Item ID=\"0x364D\"/>\n            <Item ID=\"0x3650\"/>\n            <Item ID=\"0x365C\"/>\n            <Item ID=\"0x365D\"/>\n            <Item ID=\"0x365E\"/>\n            <Item ID=\"0x365F\"/>\n            <Item ID=\"0x3679\"/>\n            <Item ID=\"0x369c\"/>\n        </Group>\n        <Group name=\"Blood\">\n            <Item ID=\"0x122A\"/>\n            <Item ID=\"0x122B\"/>\n            <Item ID=\"0x122C\"/>\n            <Item ID=\"0x122D\"/>\n            <Item ID=\"0x122E\"/>\n            <Item ID=\"0x122F\"/>\n            <Item ID=\"0x1645\"/>\n            <Item ID=\"0x1CC7\"/>\n            <Item ID=\"0x1CC8\"/>\n            <Item ID=\"0x1CC9\"/>\n            <Item ID=\"0x1CCA\"/>\n            <Item ID=\"0x1CCB\"/>\n            <Item ID=\"0x1CCC\"/>\n            <Item ID=\"0x1CCC\"/>\n            <Item ID=\"0x1CCE\"/>\n            <Item ID=\"0x1CCF\"/>\n            <Item ID=\"0x1CD0\"/>\n            <Item ID=\"0x1CD1\"/>\n            <Item ID=\"0x1CD2\"/>\n            <Item ID=\"0x1CD3\"/>\n            <Item ID=\"0x1CD4\"/>\n            <Item ID=\"0x1CD5\"/>\n            <Item ID=\"0x1CD6\"/>\n            <Item ID=\"0x1CD7\"/>\n            <Item ID=\"0x1CD8\"/>\n            <Item ID=\"0x1CD9\"/>\n            <Item ID=\"0x1CF1\"/>\n            <Item ID=\"0x1CF2\"/>\n            <Item ID=\"0x1CF3\"/>\n            <Item ID=\"0x1CF4\"/>\n            <Item ID=\"0x1CF5\"/>\n            <Item ID=\"0x1CF6\"/>\n            <Item ID=\"0x1CF7\"/>\n            <Item ID=\"0x1CF8\"/>\n            <Item ID=\"0x1CF9\"/>\n            <Item ID=\"0x1CFA\"/>\n            <Item ID=\"0x1CFB\"/>\n            <Item ID=\"0x1CFC\"/>\n            <Item ID=\"0x1CFD\"/>\n            <Item ID=\"0x1CFE\"/>\n            <Item ID=\"0x1CFF\"/>\n            <Item ID=\"0x1D00\"/>\n            <Item ID=\"0x1D01\"/>\n            <Item ID=\"0x1D02\"/>\n            <Item ID=\"0x1D03\"/>\n            <Item ID=\"0x1D04\"/>\n            <Item ID=\"0x1D05\"/>\n            <Item ID=\"0x1D06\"/>\n            <Item ID=\"0x1D07\"/>\n            <Item ID=\"0x1D08\"/>\n            <Item ID=\"0x1D09\"/>\n            <Item ID=\"0x1D0A\"/>\n            <Item ID=\"0x1D0B\"/>\n            <Item ID=\"0x1D0C\"/>\n            <Item ID=\"0x1D0D\"/>\n            <Item ID=\"0x1D0E\"/>\n            <Item ID=\"0x1D0F\"/>\n            <Item ID=\"0x1D10\"/>\n            <Item ID=\"0x1D11\"/>\n            <Item ID=\"0x1D12\"/>\n            <Item ID=\"0x1D92\"/>\n            <Item ID=\"0x1D93\"/>\n            <Item ID=\"0x1D94\"/>\n            <Item ID=\"0x1D95\"/>\n            <Item ID=\"0x1D96\"/>\n        </Group>\n        <Group name=\"Body Parts\">\n            <Item ID=\"0x1CDD\"/>\n            <Item ID=\"0x1CDE\"/>\n            <Item ID=\"0x1CDF\"/>\n            <Item ID=\"0x1CE0\"/>\n            <Item ID=\"0x1CE1\"/>\n            <Item ID=\"0x1CE2\"/>\n            <Item ID=\"0x1CE3\"/>\n            <Item ID=\"0x1CE4\"/>\n            <Item ID=\"0x1CE5\"/>\n            <Item ID=\"0x1CE6\"/>\n            <Item ID=\"0x1CE7\"/>\n            <Item ID=\"0x1CE8\"/>\n            <Item ID=\"0x1CE9\"/>\n            <Item ID=\"0x1CEA\"/>\n            <Item ID=\"0x1CEB\"/>\n            <Item ID=\"0x1CEC\"/>\n            <Item ID=\"0x1CED\"/>\n            <Item ID=\"0x1CEE\"/>\n            <Item ID=\"0x1CEF\"/>\n            <Item ID=\"0x1CF0\"/>\n            <Item ID=\"0x1D9F\"/>\n            <Item ID=\"0x1DA0\"/>\n            <Item ID=\"0x1DA1\"/>\n            <Item ID=\"0x1DA2\"/>\n            <Item ID=\"0x1DA3\"/>\n            <Item ID=\"0x1DA4\"/>\n            <Item ID=\"0x1DAD\"/>\n            <Item ID=\"0x1DAE\"/>\n            <Item ID=\"0x1DAF\"/>\n            <Item ID=\"0x1DB0\"/>\n            <Item ID=\"0x1DB1\"/>\n            <Item ID=\"0x1DB2\"/>\n        </Group>\n        <Group name=\"Bone Roof\">\n            <Item ID=\"0x3623\"/>\n            <Item ID=\"0x3624\"/>\n            <Item ID=\"0x3625\"/>\n            <Item ID=\"0x3626\"/>\n        </Group>\n        <Group name=\"Bones\">\n            <Item ID=\"0x0ECA\"/>\n            <Item ID=\"0x0ECB\"/>\n            <Item ID=\"0x0ECC\"/>\n            <Item ID=\"0x0ECD\"/>\n            <Item ID=\"0x0ECE\"/>\n            <Item ID=\"0x0ECF\"/>\n            <Item ID=\"0x0ED0\"/>\n            <Item ID=\"0x0ED1\"/>\n            <Item ID=\"0x0ED2\"/>\n            <Item ID=\"0x1B09\"/>\n            <Item ID=\"0x1B0A\"/>\n            <Item ID=\"0x1B0B\"/>\n            <Item ID=\"0x1B0C\"/>\n            <Item ID=\"0x1B0D\"/>\n            <Item ID=\"0x1B0E\"/>\n            <Item ID=\"0x1B0F\"/>\n            <Item ID=\"0x1B10\"/>\n            <Item ID=\"0x1B11\"/>\n            <Item ID=\"0x1B12\"/>\n            <Item ID=\"0x1B13\"/>\n            <Item ID=\"0x1B14\"/>\n            <Item ID=\"0x1B15\"/>\n            <Item ID=\"0x1B16\"/>\n            <Item ID=\"0x1B17\"/>\n            <Item ID=\"0x1B18\"/>\n            <Item ID=\"0x1B19\"/>\n            <Item ID=\"0x1B1A\"/>\n            <Item ID=\"0x1B1B\"/>\n            <Item ID=\"0x1B1C\"/>\n        </Group>\n        <Group name=\"Coffins etc.\">\n            <Item ID=\"0x1C22\"/>\n            <Item ID=\"0x1C23\"/>\n            <Item ID=\"0x1C24\"/>\n            <Item ID=\"0x1C25\"/>\n            <Item ID=\"0x1C26\"/>\n            <Item ID=\"0x1C27\"/>\n            <Item ID=\"0x1C28\"/>\n            <Item ID=\"0x1C29\"/>\n            <Item ID=\"0x1C2A\"/>\n            <Item ID=\"0x1C2B\"/>\n            <Item ID=\"0x1C2C\"/>\n            <Item ID=\"0x1C2D\"/>\n            <Item ID=\"0x1C2E\"/>\n            <Item ID=\"0x1C2F\"/>\n            <Item ID=\"0x1C30\"/>\n            <Item ID=\"0x1C31\"/>\n            <Item ID=\"0x1C32\"/>\n            <Item ID=\"0x1C33\"/>\n            <Item ID=\"0x1C34\"/>\n            <Item ID=\"0x1C35\"/>\n            <Item ID=\"0x1C36\"/>\n            <Item ID=\"0x1C37\"/>\n            <Item ID=\"0x1C38\"/>\n            <Item ID=\"0x1C39\"/>\n            <Item ID=\"0x1C3B\"/>\n            <Item ID=\"0x1C3C\"/>\n            <Item ID=\"0x1C3D\"/>\n            <Item ID=\"0x1C3E\"/>\n            <Item ID=\"0x1C3F\"/>\n            <Item ID=\"0x1C40\"/>\n            <Item ID=\"0x1C41\"/>\n            <Item ID=\"0x1C42\"/>\n            <Item ID=\"0x1C43\"/>\n            <Item ID=\"0x1C44\"/>\n            <Item ID=\"0x1C45\"/>\n            <Item ID=\"0x1C46\"/>\n            <Item ID=\"0x1C47\"/>\n            <Item ID=\"0x1C48\"/>\n            <Item ID=\"0x1C49\"/>\n            <Item ID=\"0x1C4A\"/>\n            <Item ID=\"0x1C4B\"/>\n            <Item ID=\"0x1C4C\"/>\n            <Item ID=\"0x1C4D\"/>\n            <Item ID=\"0x1C4F\"/>\n            <Item ID=\"0x1C50\"/>\n            <Item ID=\"0x1C51\"/>\n            <Item ID=\"0x1C52\"/>\n            <Item ID=\"0x1C53\"/>\n            <Item ID=\"0x1C54\"/>\n            <Item ID=\"0x1C55\"/>\n            <Item ID=\"0x1C56\"/>\n            <Item ID=\"0x1C57\"/>\n            <Item ID=\"0x1C58\"/>\n            <Item ID=\"0x1C59\"/>\n            <Item ID=\"0x1C5A\"/>\n            <Item ID=\"0x1C5B\"/>\n            <Item ID=\"0x1C5C\"/>\n            <Item ID=\"0x1C5D\"/>\n            <Item ID=\"0x1C5E\"/>\n            <Item ID=\"0x1C5F\"/>\n            <Item ID=\"0x1D34\"/>\n            <Item ID=\"0x1D73\"/>\n        </Group>\n        <Group name=\"Corpses\">\n            <Item ID=\"0x3d64\"/>\n            <Item ID=\"0x3d65\"/>\n            <Item ID=\"0x3d66\"/>\n            <Item ID=\"0x3d67\"/>\n            <Item ID=\"0x3d68\"/>\n        </Group>\n        <Group name=\"Evil Decor\">\n            <Item ID=\"0x2A58\"/>\n            <Item ID=\"0x2A59\"/>\n            <Item ID=\"0x2A5A\"/>\n            <Item ID=\"0x2A5B\"/>\n            <Item ID=\"0x2A5C\"/>\n            <Item ID=\"0x2A7F\"/>\n            <Item ID=\"0x2A80\"/>\n            <Item ID=\"0x2A81\"/>\n            <Item ID=\"0x2A82\"/>\n            <Item ID=\"0x2A83\"/>\n            <Item ID=\"0x2A84\"/>\n            <Item ID=\"0x2A85\"/>\n            <Item ID=\"0x2A86\"/>\n            <Item ID=\"0x2A87\"/>\n            <Item ID=\"0x2A88\"/>\n            <Item ID=\"0x2A89\"/>\n            <Item ID=\"0x2A8A\"/>\n            <Item ID=\"0x2A8B\"/>\n            <Item ID=\"0x2A8C\"/>\n            <Item ID=\"0x2A8D\"/>\n            <Item ID=\"0x2A8E\"/>\n            <Item ID=\"0x2A8F\"/>\n            <Item ID=\"0x2A90\"/>\n            <Item ID=\"0x2A91\"/>\n            <Item ID=\"0x2A92\"/>\n            <Item ID=\"0x2A98\"/>\n            <Item ID=\"0x2A99\"/>\n        </Group>\n        <Group name=\"Grave\">\n            <Item ID=\"0x0ED3\"/>\n            <Item ID=\"0x0ED4\"/>\n            <Item ID=\"0x0ED5\"/>\n            <Item ID=\"0x0ED6\"/>\n            <Item ID=\"0x0ED7\"/>\n            <Item ID=\"0x0ED8\"/>\n            <Item ID=\"0x0ED9\"/>\n            <Item ID=\"0x0EDA\"/>\n            <Item ID=\"0x0EDB\"/>\n            <Item ID=\"0x0EDC\"/>\n            <Item ID=\"0x0EDD\"/>\n            <Item ID=\"0x0EDE\"/>\n            <Item ID=\"0x0EE0\"/>\n            <Item ID=\"0x0EE1\"/>\n            <Item ID=\"0x0EE2\"/>\n            <Item ID=\"0x1165\"/>\n            <Item ID=\"0x1166\"/>\n            <Item ID=\"0x1167\"/>\n            <Item ID=\"0x1168\"/>\n            <Item ID=\"0x1169\"/>\n            <Item ID=\"0x116A\"/>\n            <Item ID=\"0x116B\"/>\n            <Item ID=\"0x116C\"/>\n            <Item ID=\"0x116D\"/>\n            <Item ID=\"0x116E\"/>\n            <Item ID=\"0x116F\"/>\n            <Item ID=\"0x1170\"/>\n            <Item ID=\"0x1171\"/>\n            <Item ID=\"0x1172\"/>\n            <Item ID=\"0x1173\"/>\n            <Item ID=\"0x1174\"/>\n            <Item ID=\"0x1175\"/>\n            <Item ID=\"0x1176\"/>\n            <Item ID=\"0x1177\"/>\n            <Item ID=\"0x1178\"/>\n            <Item ID=\"0x1179\"/>\n            <Item ID=\"0x117A\"/>\n            <Item ID=\"0x117B\"/>\n            <Item ID=\"0x117C\"/>\n            <Item ID=\"0x117D\"/>\n            <Item ID=\"0x117E\"/>\n            <Item ID=\"0x117F\"/>\n            <Item ID=\"0x1180\"/>\n            <Item ID=\"0x1181\"/>\n            <Item ID=\"0x1182\"/>\n            <Item ID=\"0x1183\"/>\n            <Item ID=\"0x1184\"/>\n            <Item ID=\"0x1185\"/>\n            <Item ID=\"0x1186\"/>\n            <Item ID=\"0x1187\"/>\n            <Item ID=\"0x1188\"/>\n            <Item ID=\"0x1189\"/>\n        </Group>\n        <Group name=\"Mummy N\">\n            <Item ID=\"0x1C38\"/>\n            <Item ID=\"0x1C3B\"/>\n            <Item ID=\"0x1C4A\"/>\n            <Item ID=\"0x1C4B\"/>\n            <Item ID=\"0x1C4C\"/>\n            <Item ID=\"0x1C9E\"/>\n            <Item ID=\"0x1C9F\"/>\n            <Item ID=\"0x1CA5\"/>\n            <Item ID=\"0x1CA6\"/>\n            <Item ID=\"0x1CB5\"/>\n            <Item ID=\"0x1CB6\"/>\n            <Item ID=\"0x1CB7\"/>\n            <Item ID=\"0x1CBA\"/>\n            <Item ID=\"0x1CBB\"/>\n            <Item ID=\"0x1CBD\"/>\n            <Item ID=\"0x1CBE\"/>\n            <Item ID=\"0x1CBF\"/>\n            <Item ID=\"0x1D30\"/>\n            <Item ID=\"0x1D31\"/>\n            <Item ID=\"0x1D32\"/>\n            <Item ID=\"0x1D33\"/>\n            <Item ID=\"0x1D34\"/>\n            <Item ID=\"0x1D35\"/>\n            <Item ID=\"0x1D36\"/>\n            <Item ID=\"0x1D37\"/>\n            <Item ID=\"0x1D38\"/>\n            <Item ID=\"0x1D39\"/>\n            <Item ID=\"0x1D3A\"/>\n            <Item ID=\"0x1D3B\"/>\n            <Item ID=\"0x1D3C\"/>\n            <Item ID=\"0x1D3D\"/>\n            <Item ID=\"0x1D3E\"/>\n            <Item ID=\"0x1D3F\"/>\n            <Item ID=\"0x1D40\"/>\n            <Item ID=\"0x1D41\"/>\n            <Item ID=\"0x1D42\"/>\n            <Item ID=\"0x1D43\"/>\n            <Item ID=\"0x1D44\"/>\n            <Item ID=\"0x1D45\"/>\n            <Item ID=\"0x1D46\"/>\n            <Item ID=\"0x1D47\"/>\n            <Item ID=\"0x1D48\"/>\n            <Item ID=\"0x1D49\"/>\n            <Item ID=\"0x1D4A\"/>\n            <Item ID=\"0x1D4B\"/>\n        </Group>\n        <Group name=\"Mummy W\">\n            <Item ID=\"0x1C2B\"/>\n            <Item ID=\"0x1C2E\"/>\n            <Item ID=\"0x1C3C\"/>\n            <Item ID=\"0x1C6F\"/>\n            <Item ID=\"0x1C75\"/>\n            <Item ID=\"0x1C76\"/>\n            <Item ID=\"0x1C85\"/>\n            <Item ID=\"0x1C86\"/>\n            <Item ID=\"0x1C87\"/>\n            <Item ID=\"0x1C8B\"/>\n            <Item ID=\"0x1C8D\"/>\n            <Item ID=\"0x1C8E\"/>\n            <Item ID=\"0x1C8F\"/>\n            <Item ID=\"0x1D13\"/>\n            <Item ID=\"0x1D14\"/>\n            <Item ID=\"0x1D15\"/>\n            <Item ID=\"0x1D16\"/>\n            <Item ID=\"0x1D17\"/>\n            <Item ID=\"0x1D18\"/>\n            <Item ID=\"0x1D19\"/>\n            <Item ID=\"0x1D1A\"/>\n            <Item ID=\"0x1D1B\"/>\n            <Item ID=\"0x1D1C\"/>\n            <Item ID=\"0x1D1D\"/>\n            <Item ID=\"0x1D1E\"/>\n            <Item ID=\"0x1D1F\"/>\n            <Item ID=\"0x1D20\"/>\n            <Item ID=\"0x1D21\"/>\n            <Item ID=\"0x1D22\"/>\n            <Item ID=\"0x1D23\"/>\n            <Item ID=\"0x1D24\"/>\n            <Item ID=\"0x1D25\"/>\n            <Item ID=\"0x1D26\"/>\n            <Item ID=\"0x1D27\"/>\n            <Item ID=\"0x1D28\"/>\n            <Item ID=\"0x1D29\"/>\n            <Item ID=\"0x1D2A\"/>\n            <Item ID=\"0x1D2B\"/>\n            <Item ID=\"0x1D2C\"/>\n            <Item ID=\"0x1D2D\"/>\n            <Item ID=\"0x1D2E\"/>\n            <Item ID=\"0x1D2F\"/>\n            <Item ID=\"0x1D52\"/>\n            <Item ID=\"0x1D58\"/>\n            <Item ID=\"0x1D6A\"/>\n        </Group>\n        <Group name=\"Palisade\">\n            <Item ID=\"0x021D\"/>\n            <Item ID=\"0x021E\"/>\n            <Item ID=\"0x021F\"/>\n            <Item ID=\"0x0220\"/>\n            <Item ID=\"0x0221\"/>\n            <Item ID=\"0x0222\"/>\n            <Item ID=\"0x0223\"/>\n            <Item ID=\"0x0226\"/>\n            <Item ID=\"0x0227\"/>\n            <Item ID=\"0x0228\"/>\n            <Item ID=\"0x0229\"/>\n            <Item ID=\"0x022A\"/>\n            <Item ID=\"0x022B\"/>\n            <Item ID=\"0x0421\"/>\n            <Item ID=\"0x0422\"/>\n            <Item ID=\"0x0423\"/>\n            <Item ID=\"0x0424\"/>\n            <Item ID=\"0x0425\"/>\n            <Item ID=\"0x0430\"/>\n            <Item ID=\"0x0431\"/>\n            <Item ID=\"0x2188\"/>\n            <Item ID=\"0x2189\"/>\n            <Item ID=\"0x218a\"/>\n            <Item ID=\"0x218b\"/>\n            <Item ID=\"0x218c\"/>\n            <Item ID=\"0x218d\"/>\n            <Item ID=\"0x218e\"/>\n            <Item ID=\"0x218f\"/>\n            <Item ID=\"0x2190\"/>\n            <Item ID=\"0x2191\"/>\n            <Item ID=\"0x2192\"/>\n            <Item ID=\"0x2193\"/>\n            <Item ID=\"0x2194\"/>\n            <Item ID=\"0x2195\"/>\n            <Item ID=\"0x2196\"/>\n            <Item ID=\"0x2197\"/>\n            <Item ID=\"0x21a5\"/>\n            <Item ID=\"0x21a6\"/>\n            <Item ID=\"0x21a7\"/>\n            <Item ID=\"0x21a8\"/>\n            <Item ID=\"0x21a9\"/>\n            <Item ID=\"0x21aa\"/>\n            <Item ID=\"0x21ab\"/>\n            <Item ID=\"0x21ac\"/>\n            <Item ID=\"0x21ad\"/>\n            <Item ID=\"0x21ae\"/>\n        </Group>\n        <Group name=\"Ready to Bury\">\n            <Item ID=\"0x1C20\"/>\n            <Item ID=\"0x1C21\"/>\n            <Item ID=\"0x1D8A\"/>\n            <Item ID=\"0x1D8B\"/>\n            <Item ID=\"0x1D8C\"/>\n            <Item ID=\"0x1D8D\"/>\n            <Item ID=\"0x1D8E\"/>\n            <Item ID=\"0x1D8F\"/>\n            <Item ID=\"0x1D90\"/>\n            <Item ID=\"0x1D91\"/>\n        </Group>\n        <Group name=\"Sarcophagus\">\n            <Item ID=\"0x1C60\"/>\n            <Item ID=\"0x1C61\"/>\n            <Item ID=\"0x1C62\"/>\n            <Item ID=\"0x1C63\"/>\n            <Item ID=\"0x1C64\"/>\n            <Item ID=\"0x1C65\"/>\n            <Item ID=\"0x1C66\"/>\n            <Item ID=\"0x1C67\"/>\n            <Item ID=\"0x1C68\"/>\n            <Item ID=\"0x1C69\"/>\n            <Item ID=\"0x1C6A\"/>\n            <Item ID=\"0x1C6B\"/>\n            <Item ID=\"0x1C6C\"/>\n            <Item ID=\"0x1C6D\"/>\n            <Item ID=\"0x1C6E\"/>\n            <Item ID=\"0x1C6F\"/>\n            <Item ID=\"0x1C70\"/>\n            <Item ID=\"0x1C71\"/>\n            <Item ID=\"0x1C72\"/>\n            <Item ID=\"0x1C73\"/>\n            <Item ID=\"0x1C74\"/>\n            <Item ID=\"0x1C75\"/>\n            <Item ID=\"0x1C76\"/>\n            <Item ID=\"0x1C77\"/>\n            <Item ID=\"0x1C78\"/>\n            <Item ID=\"0x1C79\"/>\n            <Item ID=\"0x1C7A\"/>\n            <Item ID=\"0x1C7B\"/>\n            <Item ID=\"0x1C7C\"/>\n            <Item ID=\"0x1C7D\"/>\n            <Item ID=\"0x1C7E\"/>\n            <Item ID=\"0x1C7F\"/>\n            <Item ID=\"0x1C80\"/>\n            <Item ID=\"0x1C81\"/>\n            <Item ID=\"0x1C82\"/>\n            <Item ID=\"0x1C83\"/>\n            <Item ID=\"0x1C84\"/>\n            <Item ID=\"0x1C85\"/>\n            <Item ID=\"0x1C86\"/>\n            <Item ID=\"0x1C87\"/>\n            <Item ID=\"0x1C88\"/>\n            <Item ID=\"0x1C89\"/>\n            <Item ID=\"0x1C8A\"/>\n            <Item ID=\"0x1C8B\"/>\n            <Item ID=\"0x1C8C\"/>\n            <Item ID=\"0x1C8D\"/>\n            <Item ID=\"0x1C8E\"/>\n            <Item ID=\"0x1C8F\"/>\n            <Item ID=\"0x1C90\"/>\n            <Item ID=\"0x1C91\"/>\n            <Item ID=\"0x1C92\"/>\n            <Item ID=\"0x1C93\"/>\n            <Item ID=\"0x1C94\"/>\n            <Item ID=\"0x1C95\"/>\n            <Item ID=\"0x1C96\"/>\n            <Item ID=\"0x1C97\"/>\n            <Item ID=\"0x1C98\"/>\n            <Item ID=\"0x1C99\"/>\n            <Item ID=\"0x1C9A\"/>\n            <Item ID=\"0x1C9A\"/>\n            <Item ID=\"0x1C9B\"/>\n            <Item ID=\"0x1C9C\"/>\n            <Item ID=\"0x1C9D\"/>\n            <Item ID=\"0x1C9E\"/>\n            <Item ID=\"0x1C9F\"/>\n            <Item ID=\"0x1CA0\"/>\n            <Item ID=\"0x1CA2\"/>\n            <Item ID=\"0x1CA3\"/>\n            <Item ID=\"0x1CA4\"/>\n            <Item ID=\"0x1CA5\"/>\n            <Item ID=\"0x1CA6\"/>\n            <Item ID=\"0x1CA7\"/>\n            <Item ID=\"0x1CA8\"/>\n            <Item ID=\"0x1CA9\"/>\n            <Item ID=\"0x1CAA\"/>\n            <Item ID=\"0x1CAB\"/>\n            <Item ID=\"0x1CAC\"/>\n            <Item ID=\"0x1CAD\"/>\n            <Item ID=\"0x1CAE\"/>\n            <Item ID=\"0x1CAF\"/>\n            <Item ID=\"0x1CB0\"/>\n            <Item ID=\"0x1CB2\"/>\n            <Item ID=\"0x1CB3\"/>\n            <Item ID=\"0x1CB4\"/>\n            <Item ID=\"0x1CB5\"/>\n            <Item ID=\"0x1CB6\"/>\n            <Item ID=\"0x1CB7\"/>\n            <Item ID=\"0x1CB8\"/>\n            <Item ID=\"0x1CB9\"/>\n            <Item ID=\"0x1CB9\"/>\n            <Item ID=\"0x1CBA\"/>\n            <Item ID=\"0x1CBB\"/>\n            <Item ID=\"0x1CBC\"/>\n            <Item ID=\"0x1CBD\"/>\n            <Item ID=\"0x1CBE\"/>\n            <Item ID=\"0x1CBF\"/>\n            <Item ID=\"0x2FF9\"/>\n            <Item ID=\"0x2FFA\"/>\n            <Item ID=\"0x3048\"/>\n            <Item ID=\"0x3049\"/>\n            <Item ID=\"0x304a\"/>\n            <Item ID=\"0x304b\"/>\n            <Item ID=\"0x365A\"/>\n            <Item ID=\"0x365B\"/>\n            <Item ID=\"0x369d\"/>\n            <Item ID=\"0x369e\"/>\n        </Group>\n        <Group name=\"Skeleton N\">\n            <Item ID=\"0x1C38\"/>\n            <Item ID=\"0x1C4A\"/>\n            <Item ID=\"0x1C4B\"/>\n            <Item ID=\"0x1C4C\"/>\n            <Item ID=\"0x1C8A\"/>\n            <Item ID=\"0x1C8A\"/>\n            <Item ID=\"0x1C9E\"/>\n            <Item ID=\"0x1C9F\"/>\n            <Item ID=\"0x1CA5\"/>\n            <Item ID=\"0x1CA6\"/>\n            <Item ID=\"0x1CB6\"/>\n            <Item ID=\"0x1CB7\"/>\n            <Item ID=\"0x1CBD\"/>\n            <Item ID=\"0x1CBE\"/>\n            <Item ID=\"0x1CBF\"/>\n            <Item ID=\"0x1D6C\"/>\n            <Item ID=\"0x1D6D\"/>\n            <Item ID=\"0x1D6E\"/>\n            <Item ID=\"0x1D6F\"/>\n            <Item ID=\"0x1D70\"/>\n            <Item ID=\"0x1D71\"/>\n            <Item ID=\"0x1D72\"/>\n            <Item ID=\"0x1D73\"/>\n            <Item ID=\"0x1D74\"/>\n            <Item ID=\"0x1D75\"/>\n            <Item ID=\"0x1D76\"/>\n            <Item ID=\"0x1D77\"/>\n            <Item ID=\"0x1D78\"/>\n            <Item ID=\"0x1D78\"/>\n            <Item ID=\"0x1D79\"/>\n            <Item ID=\"0x1D79\"/>\n            <Item ID=\"0x1D7A\"/>\n            <Item ID=\"0x1D7A\"/>\n            <Item ID=\"0x1D7B\"/>\n            <Item ID=\"0x1D7C\"/>\n            <Item ID=\"0x1D80\"/>\n            <Item ID=\"0x1D81\"/>\n            <Item ID=\"0x1D82\"/>\n            <Item ID=\"0x1D83\"/>\n            <Item ID=\"0x1D84\"/>\n            <Item ID=\"0x1D85\"/>\n            <Item ID=\"0x1D86\"/>\n            <Item ID=\"0x1D87\"/>\n            <Item ID=\"0x1D88\"/>\n            <Item ID=\"0x1D89\"/>\n        </Group>\n        <Group name=\"Skeleton W\">\n            <Item ID=\"0x1C2B\"/>\n            <Item ID=\"0x1C3C\"/>\n            <Item ID=\"0x1C6E\"/>\n            <Item ID=\"0x1C6F\"/>\n            <Item ID=\"0x1C75\"/>\n            <Item ID=\"0x1C76\"/>\n            <Item ID=\"0x1C85\"/>\n            <Item ID=\"0x1C86\"/>\n            <Item ID=\"0x1C87\"/>\n            <Item ID=\"0x1C8B\"/>\n            <Item ID=\"0x1C8D\"/>\n            <Item ID=\"0x1C8E\"/>\n            <Item ID=\"0x1C8F\"/>\n            <Item ID=\"0x1D4C\"/>\n            <Item ID=\"0x1D4D\"/>\n            <Item ID=\"0x1D4E\"/>\n            <Item ID=\"0x1D4F\"/>\n            <Item ID=\"0x1D50\"/>\n            <Item ID=\"0x1D51\"/>\n            <Item ID=\"0x1D52\"/>\n            <Item ID=\"0x1D53\"/>\n            <Item ID=\"0x1D54\"/>\n            <Item ID=\"0x1D55\"/>\n            <Item ID=\"0x1D56\"/>\n            <Item ID=\"0x1D57\"/>\n            <Item ID=\"0x1D58\"/>\n            <Item ID=\"0x1D59\"/>\n            <Item ID=\"0x1D5A\"/>\n            <Item ID=\"0x1D5B\"/>\n            <Item ID=\"0x1D5C\"/>\n            <Item ID=\"0x1D5D\"/>\n            <Item ID=\"0x1D5E\"/>\n            <Item ID=\"0x1D5F\"/>\n            <Item ID=\"0x1D60\"/>\n            <Item ID=\"0x1D61\"/>\n            <Item ID=\"0x1D62\"/>\n            <Item ID=\"0x1D63\"/>\n            <Item ID=\"0x1D64\"/>\n            <Item ID=\"0x1D65\"/>\n            <Item ID=\"0x1D66\"/>\n            <Item ID=\"0x1D67\"/>\n            <Item ID=\"0x1D68\"/>\n            <Item ID=\"0x1D69\"/>\n            <Item ID=\"0x1D6A\"/>\n            <Item ID=\"0x1D6B\"/>\n        </Group>\n        <Group name=\"Skeleton\">\n            <Item ID=\"0x1A01\"/>\n            <Item ID=\"0x1A02\"/>\n            <Item ID=\"0x1A03\"/>\n            <Item ID=\"0x1A04\"/>\n            <Item ID=\"0x1A05\"/>\n            <Item ID=\"0x1A06\"/>\n            <Item ID=\"0x1A07\"/>\n            <Item ID=\"0x1A08\"/>\n            <Item ID=\"0x1A09\"/>\n            <Item ID=\"0x1A0A\"/>\n            <Item ID=\"0x1A0B\"/>\n            <Item ID=\"0x1A0C\"/>\n            <Item ID=\"0x1A0D\"/>\n            <Item ID=\"0x1A0E\"/>\n            <Item ID=\"0x1B1D\"/>\n            <Item ID=\"0x1B1E\"/>\n            <Item ID=\"0x1b7c\"/>\n            <Item ID=\"0x1b7d\"/>\n            <Item ID=\"0x1b7f\"/>\n            <Item ID=\"0x1b80\"/>\n        </Group>\n        <Group name=\"Skulls\">\n            <Item ID=\"0x1853\"/>\n            <Item ID=\"0x1854\"/>\n            <Item ID=\"0x1857\"/>\n            <Item ID=\"0x1858\"/>\n            <Item ID=\"0x1AD8\"/>\n            <Item ID=\"0x1AD9\"/>\n            <Item ID=\"0x1ADA\"/>\n            <Item ID=\"0x1ADB\"/>\n            <Item ID=\"0x1ADC\"/>\n            <Item ID=\"0x1ADD\"/>\n            <Item ID=\"0x1ADE\"/>\n            <Item ID=\"0x1ADF\"/>\n            <Item ID=\"0x1AE0\"/>\n            <Item ID=\"0x1AE1\"/>\n            <Item ID=\"0x1AE2\"/>\n            <Item ID=\"0x1AE3\"/>\n            <Item ID=\"0x1AE4\"/>\n            <Item ID=\"0x21FC\"/>\n            <Item ID=\"0x2203\"/>\n            <Item ID=\"0x2204\"/>\n        </Group>\n        <Group name=\"Spiders\">\n            <Item ID=\"0x0EE3\"/>\n            <Item ID=\"0x0EE4\"/>\n            <Item ID=\"0x0EE5\"/>\n            <Item ID=\"0x0EE6\"/>\n            <Item ID=\"0x10B8\"/>\n            <Item ID=\"0x10B9\"/>\n            <Item ID=\"0x10Ba\"/>\n            <Item ID=\"0x10Bb\"/>\n            <Item ID=\"0x10Bc\"/>\n            <Item ID=\"0x10Bd\"/>\n            <Item ID=\"0x10Be\"/>\n            <Item ID=\"0x10Bf\"/>\n            <Item ID=\"0x10c0\"/>\n            <Item ID=\"0x10c1\"/>\n            <Item ID=\"0x10c2\"/>\n            <Item ID=\"0x10c3\"/>\n            <Item ID=\"0x10c4\"/>\n            <Item ID=\"0x10c5\"/>\n            <Item ID=\"0x10c6\"/>\n            <Item ID=\"0x10c7\"/>\n            <Item ID=\"0x10c8\"/>\n            <Item ID=\"0x10c9\"/>\n            <Item ID=\"0x10ca\"/>\n            <Item ID=\"0x10cb\"/>\n            <Item ID=\"0x10cc\"/>\n            <Item ID=\"0x10cd\"/>\n            <Item ID=\"0x10ce\"/>\n            <Item ID=\"0x10cf\"/>\n            <Item ID=\"0x10d0\"/>\n            <Item ID=\"0x10d1\"/>\n            <Item ID=\"0x10d2\"/>\n            <Item ID=\"0x10d3\"/>\n            <Item ID=\"0x10d4\"/>\n            <Item ID=\"0x10d5\"/>\n            <Item ID=\"0x10d6\"/>\n            <Item ID=\"0x10d7\"/>\n            <Item ID=\"0x10d8\"/>\n            <Item ID=\"0x10d9\"/>\n            <Item ID=\"0x10da\"/>\n            <Item ID=\"0x10db\"/>\n            <Item ID=\"0x10dc\"/>\n            <Item ID=\"0x10dd\"/>\n        </Group>\n        <Group name=\"Torture + Execution\">\n            <Item ID=\"0x1230\"/>\n            <Item ID=\"0x1245\"/>\n            <Item ID=\"0x1246\"/>\n            <Item ID=\"0x1247\"/>\n            <Item ID=\"0x1249\"/>\n            <Item ID=\"0x124B\"/>\n            <Item ID=\"0x124C\"/>\n            <Item ID=\"0x124D\"/>\n            <Item ID=\"0x124E\"/>\n            <Item ID=\"0x124F\"/>\n            <Item ID=\"0x1250\"/>\n            <Item ID=\"0x1251\"/>\n            <Item ID=\"0x1252\"/>\n            <Item ID=\"0x1253\"/>\n            <Item ID=\"0x1254\"/>\n            <Item ID=\"0x1255\"/>\n            <Item ID=\"0x1256\"/>\n            <Item ID=\"0x1257\"/>\n            <Item ID=\"0x1258\"/>\n            <Item ID=\"0x1259\"/>\n            <Item ID=\"0x125A\"/>\n            <Item ID=\"0x125B\"/>\n            <Item ID=\"0x125E\"/>\n            <Item ID=\"0x125F\"/>\n            <Item ID=\"0x1260\"/>\n            <Item ID=\"0x1261\"/>\n            <Item ID=\"0x1269\"/>\n            <Item ID=\"0x126B\"/>\n            <Item ID=\"0x126C\"/>\n            <Item ID=\"0x126D\"/>\n            <Item ID=\"0x126E\"/>\n            <Item ID=\"0x126F\"/>\n            <Item ID=\"0x1270\"/>\n            <Item ID=\"0x1271\"/>\n            <Item ID=\"0x1272\"/>\n            <Item ID=\"0x1273\"/>\n            <Item ID=\"0x1274\"/>\n            <Item ID=\"0x1275\"/>\n            <Item ID=\"0x1276\"/>\n            <Item ID=\"0x1277\"/>\n            <Item ID=\"0x1278\"/>\n            <Item ID=\"0x1279\"/>\n            <Item ID=\"0x127A\"/>\n            <Item ID=\"0x127B\"/>\n            <Item ID=\"0x127C\"/>\n            <Item ID=\"0x127E\"/>\n            <Item ID=\"0x127F\"/>\n            <Item ID=\"0x1280\"/>\n            <Item ID=\"0x1281\"/>\n            <Item ID=\"0x1282\"/>\n            <Item ID=\"0x1283\"/>\n            <Item ID=\"0x1284\"/>\n            <Item ID=\"0x1285\"/>\n            <Item ID=\"0x1286\"/>\n            <Item ID=\"0x1287\"/>\n            <Item ID=\"0x1288\"/>\n            <Item ID=\"0x1289\"/>\n            <Item ID=\"0x128A\"/>\n            <Item ID=\"0x128B\"/>\n            <Item ID=\"0x128C\"/>\n            <Item ID=\"0x128D\"/>\n            <Item ID=\"0x128F\"/>\n            <Item ID=\"0x1290\"/>\n            <Item ID=\"0x1291\"/>\n            <Item ID=\"0x1292\"/>\n            <Item ID=\"0x1293\"/>\n            <Item ID=\"0x1294\"/>\n            <Item ID=\"0x1295\"/>\n            <Item ID=\"0x1640\"/>\n            <Item ID=\"0x166D\"/>\n            <Item ID=\"0x166E\"/>\n            <Item ID=\"0x166F\"/>\n            <Item ID=\"0x2A71\"/>\n            <Item ID=\"0x2A72\"/>\n            <Item ID=\"0x2A73\"/>\n            <Item ID=\"0x2A74\"/>\n            <Item ID=\"0x2A75\"/>\n            <Item ID=\"0x2A76\"/>\n            <Item ID=\"0x2A77\"/>\n            <Item ID=\"0x2A78\"/>\n            <Item ID=\"0x2A79\"/>\n            <Item ID=\"0x2A7A\"/>\n        </Group>\n    </Group>\n    <Group name=\"Decoration\">\n        <Group name=\"Animal\">\n            <Item ID=\"0x2CFD\"/>\n            <Item ID=\"0x2CFE\"/>\n            <Item ID=\"0x2CFF\"/>\n            <Item ID=\"0x2D00\"/>\n            <Item ID=\"0x2D01\"/>\n            <Item ID=\"0x2D02\"/>\n            <Item ID=\"0x2D03\"/>\n            <Item ID=\"0x2D04\"/>\n        </Group>\n        <Group name=\"Books\">\n            <Item ID=\"0x0C16\"/>\n            <Item ID=\"0x0FBD\"/>\n            <Item ID=\"0x0FBE\"/>\n            <Item ID=\"0x0FBF\"/>\n            <Item ID=\"0x0FC0\"/>\n            <Item ID=\"0x0FC1\"/>\n            <Item ID=\"0x0FEF\"/>\n            <Item ID=\"0x0FF0\"/>\n            <Item ID=\"0x0FF1\"/>\n            <Item ID=\"0x0FF2\"/>\n            <Item ID=\"0x0FF3\"/>\n            <Item ID=\"0x0FF4\"/>\n            <Item ID=\"0x1C11\"/>\n            <Item ID=\"0x1C13\"/>\n            <Item ID=\"0x1E20\"/>\n            <Item ID=\"0x1E21\"/>\n            <Item ID=\"0x1E22\"/>\n            <Item ID=\"0x1E23\"/>\n            <Item ID=\"0x1E24\"/>\n            <Item ID=\"0x1E25\"/>\n            <Item ID=\"0x1E5e\"/>\n            <Item ID=\"0x1E5f\"/>\n            <Item ID=\"0x2252\"/>\n            <Item ID=\"0x2253\"/>\n            <Item ID=\"0x2254\"/>\n            <Item ID=\"0x2259\"/>\n            <Item ID=\"0x225a\"/>\n            <Item ID=\"0x225b\"/>\n            <Item ID=\"0x22C5\"/>\n            <Item ID=\"0x2311\"/>\n            <Item ID=\"0x2312\"/>\n            <Item ID=\"0x238C\"/>\n            <Item ID=\"0x23A0\"/>\n            <Item ID=\"0x2D50\"/>\n            <Item ID=\"0x2d9d\"/>\n            <Item ID=\"0x36a2\"/>\n            <Item ID=\"0x36a3\"/>\n        </Group>\n        <Group name=\"Container\">\n            <Item ID=\"0x0990\"/>\n            <Item ID=\"0x09A8\"/>\n            <Item ID=\"0x09A9\"/>\n            <Item ID=\"0x09AA\"/>\n            <Item ID=\"0x09AB\"/>\n            <Item ID=\"0x09AC\"/>\n            <Item ID=\"0x09B0\"/>\n            <Item ID=\"0x09B1\"/>\n            <Item ID=\"0x09B2\"/>\n            <Item ID=\"0x0E3C\"/>\n            <Item ID=\"0x0E3D\"/>\n            <Item ID=\"0x0E3E\"/>\n            <Item ID=\"0x0E3F\"/>\n            <Item ID=\"0x0E40\"/>\n            <Item ID=\"0x0E41\"/>\n            <Item ID=\"0x0E42\"/>\n            <Item ID=\"0x0E43\"/>\n            <Item ID=\"0x0E75\"/>\n            <Item ID=\"0x0E76\"/>\n            <Item ID=\"0x0E77\"/>\n            <Item ID=\"0x0E78\"/>\n            <Item ID=\"0x0E79\"/>\n            <Item ID=\"0x0E7A\"/>\n            <Item ID=\"0x0E7B\"/>\n            <Item ID=\"0x0E7C\"/>\n            <Item ID=\"0x0E7D\"/>\n            <Item ID=\"0x0E7E\"/>\n            <Item ID=\"0x0E7F\"/>\n            <Item ID=\"0x0E80\"/>\n            <Item ID=\"0x0E83\"/>\n            <Item ID=\"0x0FAE\"/>\n            <Item ID=\"0x154D\"/>\n            <Item ID=\"0x15F8\"/>\n            <Item ID=\"0x15f8\"/>\n            <Item ID=\"0x1603\"/>\n            <Item ID=\"0x1605\"/>\n            <Item ID=\"0x1940\"/>\n            <Item ID=\"0x1AD6\"/>\n            <Item ID=\"0x1AD7\"/>\n            <Item ID=\"0x1fff\"/>\n            <Item ID=\"0x2000\"/>\n            <Item ID=\"0x207b\"/>\n            <Item ID=\"0x24D5\"/>\n            <Item ID=\"0x24D6\"/>\n            <Item ID=\"0x24D7\"/>\n            <Item ID=\"0x24D8\"/>\n            <Item ID=\"0x24D9\"/>\n            <Item ID=\"0x24DA\"/>\n            <Item ID=\"0x24DB\"/>\n            <Item ID=\"0x24DC\"/>\n            <Item ID=\"0x24DD\"/>\n            <Item ID=\"0x280B\"/>\n            <Item ID=\"0x280C\"/>\n            <Item ID=\"0x280D\"/>\n            <Item ID=\"0x280E\"/>\n            <Item ID=\"0x280F\"/>\n            <Item ID=\"0x2810\"/>\n            <Item ID=\"0x2811\"/>\n            <Item ID=\"0x2812\"/>\n            <Item ID=\"0x2813\"/>\n            <Item ID=\"0x2814\"/>\n            <Item ID=\"0x2815\"/>\n            <Item ID=\"0x2816\"/>\n            <Item ID=\"0x2817\"/>\n            <Item ID=\"0x2818\"/>\n            <Item ID=\"0x2857\"/>\n            <Item ID=\"0x2858\"/>\n            <Item ID=\"0x2859\"/>\n            <Item ID=\"0x285A\"/>\n            <Item ID=\"0x285B\"/>\n            <Item ID=\"0x285C\"/>\n            <Item ID=\"0x285D\"/>\n            <Item ID=\"0x285E\"/>\n            <Item ID=\"0x3ed8\"/>\n            <Item ID=\"0x3ed9\"/>\n            <Item ID=\"0x3eda\"/>\n            <Item ID=\"0x3edb\"/>\n        </Group>\n        <Group name=\"Cracks + Dirt\">\n            <Item ID=\"0x0911\"/>\n            <Item ID=\"0x0912\"/>\n            <Item ID=\"0x0913\"/>\n            <Item ID=\"0x0914\"/>\n            <Item ID=\"0x1B01\"/>\n            <Item ID=\"0x1B02\"/>\n            <Item ID=\"0x1B03\"/>\n            <Item ID=\"0x1B04\"/>\n            <Item ID=\"0x1B05\"/>\n            <Item ID=\"0x1B06\"/>\n            <Item ID=\"0x1B07\"/>\n            <Item ID=\"0x1B08\"/>\n            <Item ID=\"0x1B6C\"/>\n            <Item ID=\"0x1B6D\"/>\n            <Item ID=\"0x1B6E\"/>\n            <Item ID=\"0x1B6F\"/>\n            <Item ID=\"0x1dfd\"/>\n            <Item ID=\"0x1dfe\"/>\n            <Item ID=\"0x1dff\"/>\n            <Item ID=\"0x1e00\"/>\n            <Item ID=\"0x1e01\"/>\n            <Item ID=\"0x1e02\"/>\n            <Item ID=\"0x1e03\"/>\n            <Item ID=\"0x1e04\"/>\n            <Item ID=\"0x1e05\"/>\n            <Item ID=\"0x1e06\"/>\n            <Item ID=\"0x1e07\"/>\n            <Item ID=\"0x1e08\"/>\n            <Item ID=\"0x1e09\"/>\n            <Item ID=\"0x1e0a\"/>\n            <Item ID=\"0x1e0b\"/>\n            <Item ID=\"0x1e0c\"/>\n            <Item ID=\"0x1e0d\"/>\n            <Item ID=\"0x1e0e\"/>\n        </Group>\n        <Group name=\"Crystal\">\n            <Item ID=\"0x2206\"/>\n            <Item ID=\"0x2207\"/>\n            <Item ID=\"0x2208\"/>\n            <Item ID=\"0x2209\"/>\n            <Item ID=\"0x220A\"/>\n            <Item ID=\"0x220B\"/>\n            <Item ID=\"0x220C\"/>\n            <Item ID=\"0x220D\"/>\n            <Item ID=\"0x220E\"/>\n            <Item ID=\"0x2210\"/>\n            <Item ID=\"0x2211\"/>\n            <Item ID=\"0x2212\"/>\n            <Item ID=\"0x2213\"/>\n            <Item ID=\"0x2214\"/>\n            <Item ID=\"0x2215\"/>\n            <Item ID=\"0x2216\"/>\n            <Item ID=\"0x2217\"/>\n            <Item ID=\"0x2218\"/>\n            <Item ID=\"0x221A\"/>\n            <Item ID=\"0x221B\"/>\n            <Item ID=\"0x221C\"/>\n            <Item ID=\"0x221D\"/>\n            <Item ID=\"0x221E\"/>\n            <Item ID=\"0x221F\"/>\n            <Item ID=\"0x2220\"/>\n            <Item ID=\"0x2221\"/>\n            <Item ID=\"0x2222\"/>\n            <Item ID=\"0x2224\"/>\n            <Item ID=\"0x2225\"/>\n            <Item ID=\"0x2226\"/>\n            <Item ID=\"0x2227\"/>\n            <Item ID=\"0x2228\"/>\n            <Item ID=\"0x2229\"/>\n            <Item ID=\"0x222A\"/>\n            <Item ID=\"0x222B\"/>\n            <Item ID=\"0x222C\"/>\n            <Item ID=\"0x223a\"/>\n            <Item ID=\"0x223b\"/>\n            <Item ID=\"0x223c\"/>\n            <Item ID=\"0x223d\"/>\n            <Item ID=\"0x223e\"/>\n            <Item ID=\"0x223f\"/>\n            <Item ID=\"0x2240\"/>\n            <Item ID=\"0x2241\"/>\n            <Item ID=\"0x2242\"/>\n            <Item ID=\"0x2243\"/>\n            <Item ID=\"0x2244\"/>\n            <Item ID=\"0x2245\"/>\n            <Item ID=\"0x2246\"/>\n            <Item ID=\"0x2247\"/>\n            <Item ID=\"0x2248\"/>\n            <Item ID=\"0x2249\"/>\n            <Item ID=\"0x2FE6\"/>\n            <Item ID=\"0x2FE7\"/>\n            <Item ID=\"0x2Fdc\"/>\n            <Item ID=\"0x2Fdd\"/>\n            <Item ID=\"0x35EB\"/>\n            <Item ID=\"0x35EC\"/>\n            <Item ID=\"0x35f6\"/>\n            <Item ID=\"0x35f7\"/>\n        </Group>\n        <Group name=\"Directions\">\n            <Group name=\"Pointer\">\n                <Item ID=\"0x1296\"/>\n                <Item ID=\"0x1297\"/>\n                <Item ID=\"0x1298\"/>\n                <Item ID=\"0x1299\"/>\n                <Item ID=\"0x129A\"/>\n                <Item ID=\"0x129B\"/>\n                <Item ID=\"0x129C\"/>\n                <Item ID=\"0x129D\"/>\n                <Item ID=\"0x129E\"/>\n            </Group>\n            <Group name=\"Signs\">\n                <Item ID=\"0x0B95\"/>\n                <Item ID=\"0x0B96\"/>\n                <Item ID=\"0x0B97\"/>\n                <Item ID=\"0x0B98\"/>\n                <Item ID=\"0x0B99\"/>\n                <Item ID=\"0x0B9A\"/>\n                <Item ID=\"0x0B9B\"/>\n                <Item ID=\"0x0B9C\"/>\n                <Item ID=\"0x0B9D\"/>\n                <Item ID=\"0x0B9E\"/>\n                <Item ID=\"0x0B9F\"/>\n                <Item ID=\"0x0BA0\"/>\n                <Item ID=\"0x0BA1\"/>\n                <Item ID=\"0x0BA2\"/>\n                <Item ID=\"0x0BA3\"/>\n                <Item ID=\"0x0BA4\"/>\n                <Item ID=\"0x0BA5\"/>\n                <Item ID=\"0x0BA6\"/>\n                <Item ID=\"0x0BA7\"/>\n                <Item ID=\"0x0BA8\"/>\n                <Item ID=\"0x0BA9\"/>\n                <Item ID=\"0x0BAA\"/>\n                <Item ID=\"0x0BAB\"/>\n                <Item ID=\"0x0BAD\"/>\n                <Item ID=\"0x0BAE\"/>\n                <Item ID=\"0x0BAF\"/>\n                <Item ID=\"0x0BB0\"/>\n                <Item ID=\"0x0BB1\"/>\n                <Item ID=\"0x0BB2\"/>\n                <Item ID=\"0x0BB3\"/>\n                <Item ID=\"0x0BB4\"/>\n                <Item ID=\"0x0BB5\"/>\n                <Item ID=\"0x0BB6\"/>\n                <Item ID=\"0x0BB7\"/>\n                <Item ID=\"0x0BB8\"/>\n                <Item ID=\"0x0BB9\"/>\n                <Item ID=\"0x0BBA\"/>\n                <Item ID=\"0x0BBB\"/>\n                <Item ID=\"0x0BBC\"/>\n                <Item ID=\"0x0BBD\"/>\n                <Item ID=\"0x0BBE\"/>\n                <Item ID=\"0x0BBF\"/>\n                <Item ID=\"0x0BC0\"/>\n                <Item ID=\"0x0BC1\"/>\n                <Item ID=\"0x0BC2\"/>\n                <Item ID=\"0x0BC3\"/>\n                <Item ID=\"0x0BC4\"/>\n                <Item ID=\"0x0BC5\"/>\n                <Item ID=\"0x0BC6\"/>\n                <Item ID=\"0x0BC7\"/>\n                <Item ID=\"0x0BC8\"/>\n                <Item ID=\"0x0BC9\"/>\n                <Item ID=\"0x0BCA\"/>\n                <Item ID=\"0x0BCB\"/>\n                <Item ID=\"0x0BCC\"/>\n                <Item ID=\"0x0BCD\"/>\n                <Item ID=\"0x0BCE\"/>\n                <Item ID=\"0x0BCF\"/>\n                <Item ID=\"0x0BD0\"/>\n                <Item ID=\"0x0BD1\"/>\n                <Item ID=\"0x0BD2\"/>\n                <Item ID=\"0x0BD3\"/>\n                <Item ID=\"0x0BD4\"/>\n                <Item ID=\"0x0BD5\"/>\n                <Item ID=\"0x0BD6\"/>\n                <Item ID=\"0x0BD7\"/>\n                <Item ID=\"0x0BD8\"/>\n                <Item ID=\"0x0BD9\"/>\n                <Item ID=\"0x0BDA\"/>\n                <Item ID=\"0x0BDB\"/>\n                <Item ID=\"0x0BDC\"/>\n                <Item ID=\"0x0BDD\"/>\n                <Item ID=\"0x0BDE\"/>\n                <Item ID=\"0x0BDF\"/>\n                <Item ID=\"0x0BE0\"/>\n                <Item ID=\"0x0BE1\"/>\n                <Item ID=\"0x0BE2\"/>\n                <Item ID=\"0x0BE3\"/>\n                <Item ID=\"0x0BE4\"/>\n                <Item ID=\"0x0BE5\"/>\n                <Item ID=\"0x0BE6\"/>\n                <Item ID=\"0x0BE7\"/>\n                <Item ID=\"0x0BE8\"/>\n                <Item ID=\"0x0BE9\"/>\n                <Item ID=\"0x0BEA\"/>\n                <Item ID=\"0x0BEB\"/>\n                <Item ID=\"0x0BEC\"/>\n                <Item ID=\"0x0BED\"/>\n                <Item ID=\"0x0BEE\"/>\n                <Item ID=\"0x0BEF\"/>\n                <Item ID=\"0x0BF0\"/>\n                <Item ID=\"0x0BF1\"/>\n                <Item ID=\"0x0BF2\"/>\n                <Item ID=\"0x0BF3\"/>\n                <Item ID=\"0x0BF4\"/>\n                <Item ID=\"0x0BF5\"/>\n                <Item ID=\"0x0BF6\"/>\n                <Item ID=\"0x0BF7\"/>\n                <Item ID=\"0x0BF8\"/>\n                <Item ID=\"0x0BF9\"/>\n                <Item ID=\"0x0BFB\"/>\n                <Item ID=\"0x0BFC\"/>\n                <Item ID=\"0x0BFD\"/>\n                <Item ID=\"0x0BFE\"/>\n                <Item ID=\"0x0BFF\"/>\n                <Item ID=\"0x0C00\"/>\n                <Item ID=\"0x0C01\"/>\n                <Item ID=\"0x0C02\"/>\n                <Item ID=\"0x0C03\"/>\n                <Item ID=\"0x0C04\"/>\n                <Item ID=\"0x0C05\"/>\n                <Item ID=\"0x0C06\"/>\n                <Item ID=\"0x0C07\"/>\n                <Item ID=\"0x0C08\"/>\n                <Item ID=\"0x0C09\"/>\n                <Item ID=\"0x0C0A\"/>\n                <Item ID=\"0x0C0B\"/>\n                <Item ID=\"0x0C0C\"/>\n                <Item ID=\"0x0C0D\"/>\n                <Item ID=\"0x0C0E\"/>\n                <Item ID=\"0x0C43\"/>\n                <Item ID=\"0x0C44\"/>\n                <Item ID=\"0x1514\"/>\n                <Item ID=\"0x1F28\"/>\n                <Item ID=\"0x1F29\"/>\n            </Group>\n        </Group>\n        <Group name=\"Display\">\n            <Group name=\"Bounty\">\n                <Item ID=\"0x1E60\"/>\n                <Item ID=\"0x1E61\"/>\n                <Item ID=\"0x1E62\"/>\n                <Item ID=\"0x1E63\"/>\n                <Item ID=\"0x1E64\"/>\n                <Item ID=\"0x1E65\"/>\n                <Item ID=\"0x1E66\"/>\n                <Item ID=\"0x1E67\"/>\n                <Item ID=\"0x1E68\"/>\n                <Item ID=\"0x1E69\"/>\n                <Item ID=\"0x1E6A\"/>\n                <Item ID=\"0x1E6B\"/>\n                <Item ID=\"0x1E6C\"/>\n                <Item ID=\"0x1E6D\"/>\n                <Item ID=\"0x2234\"/>\n                <Item ID=\"0x2235\"/>\n                <Item ID=\"0x224E\"/>\n                <Item ID=\"0x224F\"/>\n                <Item ID=\"0x2250\"/>\n                <Item ID=\"0x2251\"/>\n                <Item ID=\"0x2F58\"/>\n                <Item ID=\"0x2F59\"/>\n                <Item ID=\"0x2F5A\"/>\n                <Item ID=\"0x2F5B\"/>\n                <Item ID=\"0x2F5C\"/>\n                <Item ID=\"0x2F5D\"/>\n                <Item ID=\"0x2F5E\"/>\n                <Item ID=\"0x2F5F\"/>\n                <Item ID=\"0x2F60\"/>\n                <Item ID=\"0x2F61\"/>\n                <Item ID=\"0x2FB7\"/>\n                <Item ID=\"0x2FB8\"/>\n                <Item ID=\"0x312D\"/>\n                <Item ID=\"0x312E\"/>\n                <Item ID=\"0x312F\"/>\n                <Item ID=\"0x3130\"/>\n                <Item ID=\"0x3155\"/>\n                <Item ID=\"0x3156\"/>\n                <Item ID=\"0x3157\"/>\n                <Item ID=\"0x3158\"/>\n                <Item ID=\"0x3159\"/>\n                <Item ID=\"0x315A\"/>\n                <Item ID=\"0x315B\"/>\n                <Item ID=\"0x315C\"/>\n                <Item ID=\"0x315D\"/>\n                <Item ID=\"0x3172\"/>\n                <Item ID=\"0x3FFE\"/>\n            </Group>\n            <Group name=\"Display Cases\">\n                <Item ID=\"0x0A9F\"/>\n                <Item ID=\"0x0AA0\"/>\n                <Item ID=\"0x0AA1\"/>\n                <Item ID=\"0x0AA2\"/>\n                <Item ID=\"0x0AA3\"/>\n                <Item ID=\"0x0AA4\"/>\n                <Item ID=\"0x0AA5\"/>\n                <Item ID=\"0x0AFD\"/>\n                <Item ID=\"0x0AFE\"/>\n                <Item ID=\"0x0AFF\"/>\n                <Item ID=\"0x0B00\"/>\n                <Item ID=\"0x0B01\"/>\n                <Item ID=\"0x0B02\"/>\n                <Item ID=\"0x0B03\"/>\n                <Item ID=\"0x0B04\"/>\n                <Item ID=\"0x0B05\"/>\n                <Item ID=\"0x0B06\"/>\n                <Item ID=\"0x0B07\"/>\n                <Item ID=\"0x0B08\"/>\n                <Item ID=\"0x0B09\"/>\n                <Item ID=\"0x0B0A\"/>\n                <Item ID=\"0x0B0B\"/>\n                <Item ID=\"0x0B0C\"/>\n                <Item ID=\"0x0B0D\"/>\n                <Item ID=\"0x0B0E\"/>\n                <Item ID=\"0x0B0F\"/>\n                <Item ID=\"0x0B10\"/>\n                <Item ID=\"0x0B11\"/>\n                <Item ID=\"0x0B12\"/>\n                <Item ID=\"0x0B13\"/>\n                <Item ID=\"0x0B14\"/>\n                <Item ID=\"0x0B15\"/>\n                <Item ID=\"0x0B16\"/>\n                <Item ID=\"0x0B17\"/>\n                <Item ID=\"0x0B18\"/>\n                <Item ID=\"0x2FEA\"/>\n                <Item ID=\"0x2FEB\"/>\n            </Group>\n            <Group name=\"Pots + Potting\">\n                <Item ID=\"0x0B45\"/>\n                <Item ID=\"0x0B46\"/>\n                <Item ID=\"0x0B47\"/>\n                <Item ID=\"0x0B48\"/>\n                <Item ID=\"0x0EB0\"/>\n                <Item ID=\"0x11C6\"/>\n                <Item ID=\"0x11C7\"/>\n                <Item ID=\"0x11C8\"/>\n                <Item ID=\"0x11C9\"/>\n                <Item ID=\"0x11CA\"/>\n                <Item ID=\"0x11CB\"/>\n                <Item ID=\"0x11CC\"/>\n                <Item ID=\"0x1E0F\"/>\n                <Item ID=\"0x1E10\"/>\n                <Item ID=\"0x1E11\"/>\n                <Item ID=\"0x1E12\"/>\n                <Item ID=\"0x1E13\"/>\n                <Item ID=\"0x1E14\"/>\n                <Item ID=\"0x284A\"/>\n                <Item ID=\"0x28DC\"/>\n                <Item ID=\"0x28DD\"/>\n                <Item ID=\"0x28DE\"/>\n                <Item ID=\"0x28DF\"/>\n                <Item ID=\"0x28E0\"/>\n                <Item ID=\"0x28E1\"/>\n                <Item ID=\"0x28E2\"/>\n                <Item ID=\"0x28E3\"/>\n            </Group>\n            <Group name=\"Sculptures\">\n                <Item ID=\"0x1223\"/>\n                <Item ID=\"0x1224\"/>\n                <Item ID=\"0x1225\"/>\n                <Item ID=\"0x1226\"/>\n                <Item ID=\"0x1227\"/>\n                <Item ID=\"0x1228\"/>\n                <Item ID=\"0x129F\"/>\n                <Item ID=\"0x12A0\"/>\n                <Item ID=\"0x12A1\"/>\n                <Item ID=\"0x12A2\"/>\n                <Item ID=\"0x12A3\"/>\n                <Item ID=\"0x12A4\"/>\n                <Item ID=\"0x12AE\"/>\n                <Item ID=\"0x12AF\"/>\n                <Item ID=\"0x12B0\"/>\n                <Item ID=\"0x12CA\"/>\n                <Item ID=\"0x12CB\"/>\n                <Item ID=\"0x12D5\"/>\n                <Item ID=\"0x12D6\"/>\n                <Item ID=\"0x12D7\"/>\n                <Item ID=\"0x12D8\"/>\n                <Item ID=\"0x12D9\"/>\n                <Item ID=\"0x139A\"/>\n                <Item ID=\"0x139B\"/>\n                <Item ID=\"0x139C\"/>\n                <Item ID=\"0x139D\"/>\n                <Item ID=\"0x139E\"/>\n                <Item ID=\"0x139F\"/>\n                <Item ID=\"0x13A0\"/>\n                <Item ID=\"0x13A1\"/>\n                <Item ID=\"0x13A2\"/>\n                <Item ID=\"0x13A3\"/>\n                <Item ID=\"0x1f2a\"/>\n                <Item ID=\"0x207c\"/>\n                <Item ID=\"0x241A\"/>\n                <Item ID=\"0x241B\"/>\n                <Item ID=\"0x2846\"/>\n                <Item ID=\"0x2847\"/>\n                <Item ID=\"0x2848\"/>\n                <Item ID=\"0x2849\"/>\n                <Item ID=\"0x2A9e\"/>\n                <Item ID=\"0x2A9f\"/>\n                <Item ID=\"0x2Aa0\"/>\n                <Item ID=\"0x2D0E\"/>\n                <Item ID=\"0x2D0F\"/>\n                <Item ID=\"0x2D10\"/>\n                <Item ID=\"0x2D11\"/>\n                <Item ID=\"0x2D12\"/>\n                <Item ID=\"0x2D13\"/>\n                <Item ID=\"0x2D4A\"/>\n                <Item ID=\"0x2FF6\"/>\n                <Item ID=\"0x305A\"/>\n                <Item ID=\"0x305B\"/>\n                <Item ID=\"0x305C\"/>\n                <Item ID=\"0x305D\"/>\n                <Item ID=\"0x305E\"/>\n                <Item ID=\"0x305F\"/>\n                <Item ID=\"0x3066\"/>\n                <Item ID=\"0x3067\"/>\n                <Item ID=\"0x3068\"/>\n                <Item ID=\"0x3069\"/>\n                <Item ID=\"0x306A\"/>\n                <Item ID=\"0x306B\"/>\n                <Item ID=\"0x306C\"/>\n                <Item ID=\"0x306D\"/>\n                <Item ID=\"0x306E\"/>\n                <Item ID=\"0x306F\"/>\n                <Item ID=\"0x3070\"/>\n                <Item ID=\"0x3071\"/>\n                <Item ID=\"0x3072\"/>\n                <Item ID=\"0x3073\"/>\n                <Item ID=\"0x3074\"/>\n                <Item ID=\"0x3075\"/>\n                <Item ID=\"0x3076\"/>\n                <Item ID=\"0x35F8\"/>\n                <Item ID=\"0x35F9\"/>\n                <Item ID=\"0x35FA\"/>\n                <Item ID=\"0x35FB\"/>\n                <Item ID=\"0x35FC\"/>\n                <Item ID=\"0x35FD\"/>\n                <Item ID=\"0x35FE\"/>\n                <Item ID=\"0x35FF\"/>\n                <Item ID=\"0x3600\"/>\n                <Item ID=\"0x3601\"/>\n                <Item ID=\"0x364B\"/>\n                <Item ID=\"0x3657\"/>\n                <Item ID=\"0x3658\"/>\n                <Item ID=\"0x3659\"/>\n                <Item ID=\"0x3660\"/>\n                <Item ID=\"0x369B\"/>\n                <Item ID=\"0x3BB3\"/>\n                <Item ID=\"0x3BB4\"/>\n                <Item ID=\"0x3da2\"/>\n            </Group>\n            <Group name=\"Shield + Weapon Display\">\n                <Item ID=\"0x155C\"/>\n                <Item ID=\"0x155D\"/>\n                <Item ID=\"0x155E\"/>\n                <Item ID=\"0x155F\"/>\n                <Item ID=\"0x1560\"/>\n                <Item ID=\"0x1561\"/>\n                <Item ID=\"0x1562\"/>\n                <Item ID=\"0x1563\"/>\n                <Item ID=\"0x1564\"/>\n                <Item ID=\"0x1565\"/>\n                <Item ID=\"0x1568\"/>\n                <Item ID=\"0x1569\"/>\n                <Item ID=\"0x156A\"/>\n                <Item ID=\"0x156B\"/>\n                <Item ID=\"0x156C\"/>\n                <Item ID=\"0x156D\"/>\n                <Item ID=\"0x156E\"/>\n                <Item ID=\"0x156F\"/>\n                <Item ID=\"0x1570\"/>\n                <Item ID=\"0x1571\"/>\n                <Item ID=\"0x1572\"/>\n                <Item ID=\"0x1573\"/>\n                <Item ID=\"0x1574\"/>\n                <Item ID=\"0x1575\"/>\n                <Item ID=\"0x1576\"/>\n                <Item ID=\"0x1577\"/>\n                <Item ID=\"0x1578\"/>\n                <Item ID=\"0x1579\"/>\n                <Item ID=\"0x157A\"/>\n                <Item ID=\"0x157B\"/>\n                <Item ID=\"0x157C\"/>\n                <Item ID=\"0x157D\"/>\n                <Item ID=\"0x157E\"/>\n                <Item ID=\"0x157F\"/>\n                <Item ID=\"0x1580\"/>\n                <Item ID=\"0x1581\"/>\n                <Item ID=\"0x1582\"/>\n                <Item ID=\"0x1583\"/>\n                <Item ID=\"0x1584\"/>\n                <Item ID=\"0x1585\"/>\n                <Item ID=\"0x1634\"/>\n                <Item ID=\"0x1635\"/>\n                <Item ID=\"0x1636\"/>\n                <Item ID=\"0x1637\"/>\n                <Item ID=\"0x2236\"/>\n                <Item ID=\"0x2237\"/>\n                <Item ID=\"0x2238\"/>\n                <Item ID=\"0x2239\"/>\n                <Item ID=\"0x2842\"/>\n                <Item ID=\"0x2843\"/>\n                <Item ID=\"0x2844\"/>\n                <Item ID=\"0x2845\"/>\n                <Item ID=\"0x2851\"/>\n                <Item ID=\"0x2852\"/>\n                <Item ID=\"0x2853\"/>\n                <Item ID=\"0x2854\"/>\n                <Item ID=\"0x2855\"/>\n                <Item ID=\"0x2856\"/>\n                <Item ID=\"0x291C\"/>\n                <Item ID=\"0x291D\"/>\n                <Item ID=\"0x291E\"/>\n                <Item ID=\"0x291F\"/>\n                <Item ID=\"0x2A2a\"/>\n                <Item ID=\"0x2A45\"/>\n                <Item ID=\"0x2A46\"/>\n                <Item ID=\"0x2A47\"/>\n                <Item ID=\"0x2A48\"/>\n                <Item ID=\"0x2A49\"/>\n                <Item ID=\"0x2A4A\"/>\n                <Item ID=\"0x2A4B\"/>\n                <Item ID=\"0x2A4C\"/>\n            </Group>\n            <Group name=\"Wall Decor\">\n                <Group name=\"Banner\">\n                    <Item ID=\"0x0426\"/>\n                    <Item ID=\"0x0427\"/>\n                    <Item ID=\"0x042A\"/>\n                    <Item ID=\"0x042B\"/>\n                    <Item ID=\"0x042C\"/>\n                    <Item ID=\"0x042D\"/>\n                    <Item ID=\"0x042E\"/>\n                    <Item ID=\"0x042F\"/>\n                    <Item ID=\"0x1586\"/>\n                    <Item ID=\"0x1587\"/>\n                    <Item ID=\"0x1588\"/>\n                    <Item ID=\"0x1589\"/>\n                    <Item ID=\"0x158a\"/>\n                    <Item ID=\"0x158b\"/>\n                    <Item ID=\"0x158c\"/>\n                    <Item ID=\"0x158d\"/>\n                    <Item ID=\"0x158e\"/>\n                    <Item ID=\"0x158f\"/>\n                    <Item ID=\"0x1590\"/>\n                    <Item ID=\"0x1591\"/>\n                    <Item ID=\"0x1592\"/>\n                    <Item ID=\"0x1593\"/>\n                    <Item ID=\"0x1594\"/>\n                    <Item ID=\"0x1595\"/>\n                    <Item ID=\"0x1596\"/>\n                    <Item ID=\"0x1597\"/>\n                    <Item ID=\"0x1598\"/>\n                    <Item ID=\"0x1599\"/>\n                    <Item ID=\"0x159a\"/>\n                    <Item ID=\"0x159b\"/>\n                    <Item ID=\"0x159c\"/>\n                    <Item ID=\"0x159d\"/>\n                    <Item ID=\"0x159e\"/>\n                    <Item ID=\"0x159f\"/>\n                    <Item ID=\"0x15AE\"/>\n                    <Item ID=\"0x15AF\"/>\n                    <Item ID=\"0x15B0\"/>\n                    <Item ID=\"0x15B1\"/>\n                    <Item ID=\"0x15B2\"/>\n                    <Item ID=\"0x15B3\"/>\n                    <Item ID=\"0x15B4\"/>\n                    <Item ID=\"0x15B5\"/>\n                    <Item ID=\"0x15B6\"/>\n                    <Item ID=\"0x15B7\"/>\n                    <Item ID=\"0x15B8\"/>\n                    <Item ID=\"0x15B9\"/>\n                    <Item ID=\"0x15BA\"/>\n                    <Item ID=\"0x15BB\"/>\n                    <Item ID=\"0x15BC\"/>\n                    <Item ID=\"0x15BD\"/>\n                    <Item ID=\"0x15BE\"/>\n                    <Item ID=\"0x15BF\"/>\n                    <Item ID=\"0x15C0\"/>\n                    <Item ID=\"0x15C1\"/>\n                    <Item ID=\"0x15C2\"/>\n                    <Item ID=\"0x15C3\"/>\n                    <Item ID=\"0x15C4\"/>\n                    <Item ID=\"0x15C5\"/>\n                    <Item ID=\"0x15C6\"/>\n                    <Item ID=\"0x15C7\"/>\n                    <Item ID=\"0x15C8\"/>\n                    <Item ID=\"0x15C9\"/>\n                    <Item ID=\"0x15CA\"/>\n                    <Item ID=\"0x15CB\"/>\n                    <Item ID=\"0x15CC\"/>\n                    <Item ID=\"0x15CD\"/>\n                    <Item ID=\"0x15CE\"/>\n                    <Item ID=\"0x15CF\"/>\n                    <Item ID=\"0x15D0\"/>\n                    <Item ID=\"0x15D1\"/>\n                    <Item ID=\"0x15D2\"/>\n                    <Item ID=\"0x15D3\"/>\n                    <Item ID=\"0x15D4\"/>\n                    <Item ID=\"0x15D5\"/>\n                    <Item ID=\"0x15D6\"/>\n                    <Item ID=\"0x15D7\"/>\n                    <Item ID=\"0x15D8\"/>\n                    <Item ID=\"0x15D9\"/>\n                    <Item ID=\"0x15DA\"/>\n                    <Item ID=\"0x15DB\"/>\n                    <Item ID=\"0x15DC\"/>\n                    <Item ID=\"0x15DD\"/>\n                    <Item ID=\"0x15DE\"/>\n                    <Item ID=\"0x15DF\"/>\n                    <Item ID=\"0x15E0\"/>\n                    <Item ID=\"0x15E1\"/>\n                    <Item ID=\"0x15E2\"/>\n                    <Item ID=\"0x15E3\"/>\n                    <Item ID=\"0x15E4\"/>\n                    <Item ID=\"0x15E5\"/>\n                    <Item ID=\"0x15E6\"/>\n                    <Item ID=\"0x15E7\"/>\n                    <Item ID=\"0x15E8\"/>\n                    <Item ID=\"0x15E9\"/>\n                    <Item ID=\"0x15EA\"/>\n                    <Item ID=\"0x15EB\"/>\n                    <Item ID=\"0x15EC\"/>\n                    <Item ID=\"0x15ED\"/>\n                    <Item ID=\"0x15EE\"/>\n                    <Item ID=\"0x15EF\"/>\n                    <Item ID=\"0x15F0\"/>\n                    <Item ID=\"0x15F1\"/>\n                    <Item ID=\"0x15F2\"/>\n                    <Item ID=\"0x15F3\"/>\n                    <Item ID=\"0x15F4\"/>\n                    <Item ID=\"0x15F5\"/>\n                    <Item ID=\"0x15a0\"/>\n                    <Item ID=\"0x15a1\"/>\n                    <Item ID=\"0x15a2\"/>\n                    <Item ID=\"0x15a3\"/>\n                    <Item ID=\"0x15a4\"/>\n                    <Item ID=\"0x15a5\"/>\n                    <Item ID=\"0x15a6\"/>\n                    <Item ID=\"0x15a7\"/>\n                    <Item ID=\"0x15a8\"/>\n                    <Item ID=\"0x15a9\"/>\n                    <Item ID=\"0x15aa\"/>\n                    <Item ID=\"0x15ab\"/>\n                    <Item ID=\"0x15ac\"/>\n                    <Item ID=\"0x15ad\"/>\n                    <Item ID=\"0x15ae\"/>\n                    <Item ID=\"0x15af\"/>\n                    <Item ID=\"0x15b0\"/>\n                    <Item ID=\"0x15b1\"/>\n                    <Item ID=\"0x15b2\"/>\n                    <Item ID=\"0x15b3\"/>\n                    <Item ID=\"0x15b4\"/>\n                    <Item ID=\"0x15b5\"/>\n                    <Item ID=\"0x15b6\"/>\n                    <Item ID=\"0x15b7\"/>\n                    <Item ID=\"0x15b8\"/>\n                    <Item ID=\"0x15b9\"/>\n                    <Item ID=\"0x15ba\"/>\n                    <Item ID=\"0x15bb\"/>\n                    <Item ID=\"0x15bc\"/>\n                    <Item ID=\"0x15bd\"/>\n                    <Item ID=\"0x15be\"/>\n                    <Item ID=\"0x15bf\"/>\n                    <Item ID=\"0x15c0\"/>\n                    <Item ID=\"0x15c1\"/>\n                    <Item ID=\"0x15c2\"/>\n                    <Item ID=\"0x15c3\"/>\n                    <Item ID=\"0x15c4\"/>\n                    <Item ID=\"0x15c5\"/>\n                    <Item ID=\"0x15c6\"/>\n                    <Item ID=\"0x15c7\"/>\n                    <Item ID=\"0x15c8\"/>\n                    <Item ID=\"0x15c9\"/>\n                    <Item ID=\"0x15ca\"/>\n                    <Item ID=\"0x15cb\"/>\n                    <Item ID=\"0x15cc\"/>\n                    <Item ID=\"0x15cd\"/>\n                    <Item ID=\"0x15ce\"/>\n                    <Item ID=\"0x15cf\"/>\n                    <Item ID=\"0x15d0\"/>\n                    <Item ID=\"0x15d1\"/>\n                    <Item ID=\"0x15d2\"/>\n                    <Item ID=\"0x15d3\"/>\n                    <Item ID=\"0x15d4\"/>\n                    <Item ID=\"0x15d5\"/>\n                    <Item ID=\"0x15d6\"/>\n                    <Item ID=\"0x15d7\"/>\n                    <Item ID=\"0x15d8\"/>\n                    <Item ID=\"0x15d9\"/>\n                    <Item ID=\"0x15da\"/>\n                    <Item ID=\"0x15db\"/>\n                    <Item ID=\"0x15dc\"/>\n                    <Item ID=\"0x15dd\"/>\n                    <Item ID=\"0x15de\"/>\n                    <Item ID=\"0x15df\"/>\n                    <Item ID=\"0x15e0\"/>\n                    <Item ID=\"0x15e1\"/>\n                    <Item ID=\"0x15e2\"/>\n                    <Item ID=\"0x15e3\"/>\n                    <Item ID=\"0x15e4\"/>\n                    <Item ID=\"0x15e5\"/>\n                    <Item ID=\"0x15e6\"/>\n                    <Item ID=\"0x15e7\"/>\n                    <Item ID=\"0x15e8\"/>\n                    <Item ID=\"0x15e9\"/>\n                    <Item ID=\"0x15ea\"/>\n                    <Item ID=\"0x15eb\"/>\n                    <Item ID=\"0x15ec\"/>\n                    <Item ID=\"0x15ed\"/>\n                    <Item ID=\"0x15ee\"/>\n                    <Item ID=\"0x15ef\"/>\n                    <Item ID=\"0x15f0\"/>\n                    <Item ID=\"0x15f1\"/>\n                    <Item ID=\"0x15f2\"/>\n                    <Item ID=\"0x15f3\"/>\n                    <Item ID=\"0x15f4\"/>\n                    <Item ID=\"0x15f5\"/>\n                    <Item ID=\"0x160F\"/>\n                    <Item ID=\"0x1610\"/>\n                    <Item ID=\"0x1611\"/>\n                    <Item ID=\"0x1612\"/>\n                    <Item ID=\"0x1613\"/>\n                    <Item ID=\"0x1614\"/>\n                    <Item ID=\"0x1615\"/>\n                    <Item ID=\"0x1616\"/>\n                    <Item ID=\"0x1617\"/>\n                    <Item ID=\"0x1618\"/>\n                    <Item ID=\"0x1619\"/>\n                    <Item ID=\"0x161A\"/>\n                    <Item ID=\"0x161B\"/>\n                    <Item ID=\"0x161C\"/>\n                    <Item ID=\"0x161D\"/>\n                    <Item ID=\"0x161E\"/>\n                    <Item ID=\"0x161F\"/>\n                    <Item ID=\"0x1620\"/>\n                    <Item ID=\"0x1621\"/>\n                    <Item ID=\"0x1622\"/>\n                    <Item ID=\"0x1623\"/>\n                    <Item ID=\"0x1624\"/>\n                    <Item ID=\"0x1625\"/>\n                    <Item ID=\"0x1626\"/>\n                    <Item ID=\"0x1627\"/>\n                    <Item ID=\"0x1628\"/>\n                    <Item ID=\"0x1629\"/>\n                    <Item ID=\"0x162A\"/>\n                    <Item ID=\"0x162B\"/>\n                    <Item ID=\"0x162C\"/>\n                    <Item ID=\"0x162D\"/>\n                    <Item ID=\"0x162E\"/>\n                    <Item ID=\"0x162F\"/>\n                    <Item ID=\"0x1630\"/>\n                    <Item ID=\"0x1631\"/>\n                    <Item ID=\"0x1632\"/>\n                    <Item ID=\"0x1633\"/>\n                    <Item ID=\"0x2FFf\"/>\n                    <Item ID=\"0x3000\"/>\n                </Group>\n                <Group name=\"Curtains\">\n                    <Item ID=\"0x0980\"/>\n                    <Item ID=\"0x0981\"/>\n                    <Item ID=\"0x0982\"/>\n                    <Item ID=\"0x0983\"/>\n                    <Item ID=\"0x0984\"/>\n                    <Item ID=\"0x0985\"/>\n                    <Item ID=\"0x0986\"/>\n                    <Item ID=\"0x0987\"/>\n                    <Item ID=\"0x0988\"/>\n                    <Item ID=\"0x0989\"/>\n                    <Item ID=\"0x098A\"/>\n                    <Item ID=\"0x098B\"/>\n                    <Item ID=\"0x12DA\"/>\n                    <Item ID=\"0x12DB\"/>\n                    <Item ID=\"0x12DC\"/>\n                    <Item ID=\"0x12DD\"/>\n                    <Item ID=\"0x12DE\"/>\n                    <Item ID=\"0x12DF\"/>\n                    <Item ID=\"0x12E0\"/>\n                    <Item ID=\"0x12E1\"/>\n                    <Item ID=\"0x12E2\"/>\n                    <Item ID=\"0x12E3\"/>\n                    <Item ID=\"0x12E4\"/>\n                    <Item ID=\"0x12E5\"/>\n                    <Item ID=\"0x12E6\"/>\n                    <Item ID=\"0x12E7\"/>\n                    <Item ID=\"0x12E8\"/>\n                    <Item ID=\"0x12E9\"/>\n                    <Item ID=\"0x12EA\"/>\n                    <Item ID=\"0x12EB\"/>\n                    <Item ID=\"0x12EC\"/>\n                    <Item ID=\"0x12ED\"/>\n                    <Item ID=\"0x154E\"/>\n                    <Item ID=\"0x154F\"/>\n                    <Item ID=\"0x1557\"/>\n                    <Item ID=\"0x15f6\"/>\n                    <Item ID=\"0x15f7\"/>\n                    <Item ID=\"0x160D\"/>\n                    <Item ID=\"0x160E\"/>\n                    <Item ID=\"0x1638\"/>\n                    <Item ID=\"0x1639\"/>\n                    <Item ID=\"0x3d9c\"/>\n                    <Item ID=\"0x3d9d\"/>\n                    <Item ID=\"0x3d9e\"/>\n                    <Item ID=\"0x3d9f\"/>\n                    <Item ID=\"0x3da0\"/>\n                    <Item ID=\"0x3da1\"/>\n                    <Item ID=\"0x3da1\"/>\n                    <Item ID=\"0x3da3\"/>\n                    <Item ID=\"0x3da4\"/>\n                    <Item ID=\"0x3da5\"/>\n                    <Item ID=\"0x3da6\"/>\n                    <Item ID=\"0x3da7\"/>\n                    <Item ID=\"0x3da8\"/>\n                    <Item ID=\"0x3dab\"/>\n                    <Item ID=\"0x3dac\"/>\n                    <Item ID=\"0x3dad\"/>\n                    <Item ID=\"0x3dae\"/>\n                </Group>\n                <Group name=\"Painting\">\n                    <Item ID=\"0x0C2C\"/>\n                    <Item ID=\"0x0E9F\"/>\n                    <Item ID=\"0x0EA0\"/>\n                    <Item ID=\"0x0EA1\"/>\n                    <Item ID=\"0x0EA2\"/>\n                    <Item ID=\"0x0EA5\"/>\n                    <Item ID=\"0x0EA6\"/>\n                    <Item ID=\"0x0EA7\"/>\n                    <Item ID=\"0x0EA8\"/>\n                    <Item ID=\"0x0EC8\"/>\n                    <Item ID=\"0x0EC9\"/>\n                    <Item ID=\"0x0EE7\"/>\n                    <Item ID=\"0x240D\"/>\n                    <Item ID=\"0x240E\"/>\n                    <Item ID=\"0x240F\"/>\n                    <Item ID=\"0x2410\"/>\n                    <Item ID=\"0x2411\"/>\n                    <Item ID=\"0x2412\"/>\n                    <Item ID=\"0x2413\"/>\n                    <Item ID=\"0x2414\"/>\n                    <Item ID=\"0x2415\"/>\n                    <Item ID=\"0x2416\"/>\n                    <Item ID=\"0x2417\"/>\n                    <Item ID=\"0x2418\"/>\n                    <Item ID=\"0x2886\"/>\n                    <Item ID=\"0x2887\"/>\n                    <Item ID=\"0x2887\"/>\n                    <Item ID=\"0x2A5D\"/>\n                    <Item ID=\"0x2A5E\"/>\n                    <Item ID=\"0x2A5F\"/>\n                    <Item ID=\"0x2A60\"/>\n                    <Item ID=\"0x2A61\"/>\n                    <Item ID=\"0x2A62\"/>\n                    <Item ID=\"0x2A63\"/>\n                    <Item ID=\"0x2A64\"/>\n                    <Item ID=\"0x2A65\"/>\n                    <Item ID=\"0x2A66\"/>\n                    <Item ID=\"0x2A67\"/>\n                    <Item ID=\"0x2A68\"/>\n                    <Item ID=\"0x2A69\"/>\n                    <Item ID=\"0x2A6A\"/>\n                    <Item ID=\"0x2A6B\"/>\n                    <Item ID=\"0x2A6C\"/>\n                    <Item ID=\"0x2A6D\"/>\n                    <Item ID=\"0x2A6E\"/>\n                    <Item ID=\"0x2A6F\"/>\n                    <Item ID=\"0x2A70\"/>\n                    <Item ID=\"0x3BB6\"/>\n                    <Item ID=\"0x3BB7\"/>\n                </Group>\n                <Group name=\"Tapestry\">\n                    <Item ID=\"0x0FD5\"/>\n                    <Item ID=\"0x0FD6\"/>\n                    <Item ID=\"0x0FD7\"/>\n                    <Item ID=\"0x0FD8\"/>\n                    <Item ID=\"0x0FD9\"/>\n                    <Item ID=\"0x0FDA\"/>\n                    <Item ID=\"0x0FDB\"/>\n                    <Item ID=\"0x0FDC\"/>\n                    <Item ID=\"0x0FDD\"/>\n                    <Item ID=\"0x0FDE\"/>\n                    <Item ID=\"0x0FDF\"/>\n                    <Item ID=\"0x0FE0\"/>\n                    <Item ID=\"0x0FE1\"/>\n                    <Item ID=\"0x0FE2\"/>\n                    <Item ID=\"0x0FE3\"/>\n                    <Item ID=\"0x0FE4\"/>\n                    <Item ID=\"0x234E\"/>\n                    <Item ID=\"0x234F\"/>\n                    <Item ID=\"0x2D6F\"/>\n                    <Item ID=\"0x2D70\"/>\n                    <Item ID=\"0x2D71\"/>\n                    <Item ID=\"0x2D72\"/>\n                    <Item ID=\"0x2FF2\"/>\n                    <Item ID=\"0x2FF3\"/>\n                </Group>\n                <Group name=\"Wall Carving\">\n                    <Item ID=\"0x121d\"/>\n                    <Item ID=\"0x121e\"/>\n                    <Item ID=\"0x121f\"/>\n                    <Item ID=\"0x1220\"/>\n                    <Item ID=\"0x1221\"/>\n                    <Item ID=\"0x1222\"/>\n                    <Item ID=\"0x1231\"/>\n                    <Item ID=\"0x1232\"/>\n                    <Item ID=\"0x1233\"/>\n                    <Item ID=\"0x1234\"/>\n                    <Item ID=\"0x1235\"/>\n                    <Item ID=\"0x1237\"/>\n                    <Item ID=\"0x1238\"/>\n                    <Item ID=\"0x1239\"/>\n                    <Item ID=\"0x123A\"/>\n                    <Item ID=\"0x123B\"/>\n                    <Item ID=\"0x123C\"/>\n                    <Item ID=\"0x123D\"/>\n                    <Item ID=\"0x123E\"/>\n                    <Item ID=\"0x1240\"/>\n                    <Item ID=\"0x1241\"/>\n                    <Item ID=\"0x1242\"/>\n                    <Item ID=\"0x1243\"/>\n                    <Item ID=\"0x1244\"/>\n                    <Item ID=\"0x1265\"/>\n                    <Item ID=\"0x1266\"/>\n                    <Item ID=\"0x1267\"/>\n                    <Item ID=\"0x12CC\"/>\n                    <Item ID=\"0x12CD\"/>\n                    <Item ID=\"0x12CE\"/>\n                    <Item ID=\"0x12CF\"/>\n                    <Item ID=\"0x12D0\"/>\n                    <Item ID=\"0x12D2\"/>\n                    <Item ID=\"0x12D3\"/>\n                    <Item ID=\"0x12D4\"/>\n                    <Item ID=\"0x3647\"/>\n                    <Item ID=\"0x3648\"/>\n                    <Item ID=\"0x3649\"/>\n                    <Item ID=\"0x364a\"/>\n                </Group>\n                <Item ID=\"0x0F65\"/>\n                <Item ID=\"0x0F66\"/>\n                <Item ID=\"0x0F67\"/>\n                <Item ID=\"0x0F68\"/>\n                <Item ID=\"0x0F69\"/>\n                <Item ID=\"0x0F6A\"/>\n                <Item ID=\"0x0F71\"/>\n                <Item ID=\"0x0F72\"/>\n                <Item ID=\"0x0F73\"/>\n                <Item ID=\"0x0F74\"/>\n                <Item ID=\"0x0F75\"/>\n                <Item ID=\"0x0F76\"/>\n                <Item ID=\"0x2409\"/>\n                <Item ID=\"0x240A\"/>\n                <Item ID=\"0x240B\"/>\n                <Item ID=\"0x240C\"/>\n                <Item ID=\"0x2D73\"/>\n                <Item ID=\"0x2D74\"/>\n            </Group>\n            <Item ID=\"0x24E3\"/>\n            <Item ID=\"0x24E4\"/>\n            <Item ID=\"0x24E5\"/>\n            <Item ID=\"0x2FF4\"/>\n            <Item ID=\"0x2FF5\"/>\n            <Item ID=\"0x2Fb6\"/>\n            <Item ID=\"0x2Fd4\"/>\n            <Item ID=\"0x2Fd5\"/>\n            <Item ID=\"0x3d86\"/>\n            <Item ID=\"0x3d87\"/>\n            <Item ID=\"0x3da9\"/>\n            <Item ID=\"0x3daa\"/>\n        </Group>\n        <Group name=\"Docks\">\n            <Item ID=\"0x01CB\"/>\n            <Item ID=\"0x01CC\"/>\n            <Item ID=\"0x01CD\"/>\n            <Item ID=\"0x01CE\"/>\n            <Item ID=\"0x03A5\"/>\n            <Item ID=\"0x03A6\"/>\n            <Item ID=\"0x03A7\"/>\n            <Item ID=\"0x03A8\"/>\n            <Item ID=\"0x03A9\"/>\n            <Item ID=\"0x03AA\"/>\n            <Item ID=\"0x03AB\"/>\n            <Item ID=\"0x03AC\"/>\n            <Item ID=\"0x03AD\"/>\n            <Item ID=\"0x03AE\"/>\n            <Item ID=\"0x03AF\"/>\n            <Item ID=\"0x03B0\"/>\n            <Item ID=\"0x14F7\"/>\n            <Item ID=\"0x14F8\"/>\n            <Item ID=\"0x14F9\"/>\n            <Item ID=\"0x14FA\"/>\n        </Group>\n        <Group name=\"Fountain\">\n            <Item ID=\"0x090D\"/>\n            <Item ID=\"0x1731\"/>\n            <Item ID=\"0x1732\"/>\n            <Item ID=\"0x1733\"/>\n            <Item ID=\"0x1735\"/>\n            <Item ID=\"0x1736\"/>\n            <Item ID=\"0x1737\"/>\n            <Item ID=\"0x1738\"/>\n            <Item ID=\"0x1739\"/>\n            <Item ID=\"0x173A\"/>\n            <Item ID=\"0x173B\"/>\n            <Item ID=\"0x173C\"/>\n            <Item ID=\"0x173D\"/>\n            <Item ID=\"0x173E\"/>\n            <Item ID=\"0x173F\"/>\n            <Item ID=\"0x1740\"/>\n            <Item ID=\"0x19C3\"/>\n            <Item ID=\"0x19C4\"/>\n            <Item ID=\"0x19C5\"/>\n            <Item ID=\"0x19C7\"/>\n            <Item ID=\"0x19C8\"/>\n            <Item ID=\"0x19C9\"/>\n            <Item ID=\"0x19CA\"/>\n            <Item ID=\"0x19CB\"/>\n            <Item ID=\"0x19CC\"/>\n            <Item ID=\"0x19CD\"/>\n            <Item ID=\"0x19CE\"/>\n            <Item ID=\"0x19CF\"/>\n            <Item ID=\"0x19D0\"/>\n            <Item ID=\"0x19D1\"/>\n            <Item ID=\"0x19D2\"/>\n            <Item ID=\"0x2AC0\"/>\n            <Item ID=\"0x2AC3\"/>\n            <Item ID=\"0x2AC6\"/>\n            <Item ID=\"0x35E9\"/>\n        </Group>\n        <Group name=\"Furniture\">\n            <Group name=\"Bedding\">\n                <Item ID=\"0x0A55\"/>\n                <Item ID=\"0x0A56\"/>\n                <Item ID=\"0x0A57\"/>\n                <Item ID=\"0x0A58\"/>\n                <Item ID=\"0x0A59\"/>\n                <Item ID=\"0x0A6C\"/>\n                <Item ID=\"0x0A6D\"/>\n                <Item ID=\"0x0A6E\"/>\n                <Item ID=\"0x0A6F\"/>\n                <Item ID=\"0x0A92\"/>\n                <Item ID=\"0x0A93\"/>\n                <Item ID=\"0x0A94\"/>\n                <Item ID=\"0x0A95\"/>\n                <Item ID=\"0x11E2\"/>\n                <Item ID=\"0x11E3\"/>\n                <Item ID=\"0x11E4\"/>\n                <Item ID=\"0x11E5\"/>\n                <Item ID=\"0x11E6\"/>\n                <Item ID=\"0x11E7\"/>\n                <Item ID=\"0x11E8\"/>\n                <Item ID=\"0x11E9\"/>\n                <Item ID=\"0x11EA\"/>\n                <Item ID=\"0x11EB\"/>\n                <Item ID=\"0x1397\"/>\n                <Item ID=\"0x13A4\"/>\n                <Item ID=\"0x13A5\"/>\n                <Item ID=\"0x13A6\"/>\n                <Item ID=\"0x13A7\"/>\n                <Item ID=\"0x13A8\"/>\n                <Item ID=\"0x13A9\"/>\n                <Item ID=\"0x13AA\"/>\n                <Item ID=\"0x13AB\"/>\n                <Item ID=\"0x13AC\"/>\n                <Item ID=\"0x13AD\"/>\n                <Item ID=\"0x13AE\"/>\n                <Item ID=\"0x163a\"/>\n                <Item ID=\"0x163b\"/>\n                <Item ID=\"0x163c\"/>\n                <Item ID=\"0x1f24\"/>\n                <Item ID=\"0x1f25\"/>\n                <Item ID=\"0x1f26\"/>\n                <Item ID=\"0x1f27\"/>\n                <Item ID=\"0x1f73\"/>\n                <Item ID=\"0x1f74\"/>\n                <Item ID=\"0x1f75\"/>\n                <Item ID=\"0x1f76\"/>\n                <Item ID=\"0x1f77\"/>\n                <Item ID=\"0x1f78\"/>\n                <Item ID=\"0x1f79\"/>\n                <Item ID=\"0x1f7a\"/>\n                <Item ID=\"0x28a4\"/>\n                <Item ID=\"0x28a5\"/>\n                <Item ID=\"0x28a6\"/>\n                <Item ID=\"0x28a7\"/>\n                <Item ID=\"0x28a8\"/>\n                <Item ID=\"0x28a9\"/>\n                <Item ID=\"0x28aa\"/>\n                <Item ID=\"0x28ab\"/>\n                <Item ID=\"0x28ac\"/>\n                <Item ID=\"0x28ad\"/>\n                <Item ID=\"0x28ae\"/>\n                <Item ID=\"0x28af\"/>\n            </Group>\n            <Group name=\"Curtained Furniture\">\n                <Item ID=\"0x0C17\"/>\n                <Item ID=\"0x0C18\"/>\n                <Item ID=\"0x0C31\"/>\n                <Item ID=\"0x0C32\"/>\n                <Item ID=\"0x0C33\"/>\n                <Item ID=\"0x0C34\"/>\n                <Item ID=\"0x0C35\"/>\n                <Item ID=\"0x0C36\"/>\n            </Group>\n            <Group name=\"Damage\">\n                <Item ID=\"0x0C10\"/>\n                <Item ID=\"0x0C11\"/>\n                <Item ID=\"0x0C12\"/>\n                <Item ID=\"0x0C13\"/>\n                <Item ID=\"0x0C14\"/>\n                <Item ID=\"0x0C15\"/>\n                <Item ID=\"0x0C19\"/>\n                <Item ID=\"0x0C1A\"/>\n                <Item ID=\"0x0C1B\"/>\n                <Item ID=\"0x0C1C\"/>\n                <Item ID=\"0x0C1D\"/>\n                <Item ID=\"0x0C1E\"/>\n                <Item ID=\"0x0C1F\"/>\n                <Item ID=\"0x0C20\"/>\n                <Item ID=\"0x0C21\"/>\n                <Item ID=\"0x0C22\"/>\n                <Item ID=\"0x0C23\"/>\n                <Item ID=\"0x0C24\"/>\n                <Item ID=\"0x0C25\"/>\n                <Item ID=\"0x0C26\"/>\n                <Item ID=\"0x0C27\"/>\n                <Item ID=\"0x0C28\"/>\n                <Item ID=\"0x0C29\"/>\n                <Item ID=\"0x0C2A\"/>\n                <Item ID=\"0x0C2B\"/>\n                <Item ID=\"0x1894\"/>\n                <Item ID=\"0x1895\"/>\n                <Item ID=\"0x1896\"/>\n                <Item ID=\"0x1897\"/>\n                <Item ID=\"0x1898\"/>\n                <Item ID=\"0x1899\"/>\n                <Item ID=\"0x189a\"/>\n                <Item ID=\"0x189b\"/>\n                <Item ID=\"0x398c\"/>\n                <Item ID=\"0x3996\"/>\n                <Item ID=\"0x3d8a\"/>\n                <Item ID=\"0x3d8b\"/>\n                <Item ID=\"0x3d8c\"/>\n                <Item ID=\"0x3d8d\"/>\n                <Item ID=\"0x3d90\"/>\n                <Item ID=\"0x3d91\"/>\n                <Item ID=\"0x3d92\"/>\n                <Item ID=\"0x3d93\"/>\n                <Item ID=\"0x3e27\"/>\n                <Item ID=\"0x3e31\"/>\n            </Group>\n            <Group name=\"Elfish Furniture\">\n                <Item ID=\"0x2D05\"/>\n                <Item ID=\"0x2D06\"/>\n                <Item ID=\"0x2D07\"/>\n                <Item ID=\"0x2D08\"/>\n                <Item ID=\"0x2D09\"/>\n                <Item ID=\"0x2D0A\"/>\n                <Item ID=\"0x2D0B\"/>\n                <Item ID=\"0x2D0C\"/>\n                <Item ID=\"0x2DD5\"/>\n                <Item ID=\"0x2DD6\"/>\n                <Item ID=\"0x2DD7\"/>\n                <Item ID=\"0x2DD8\"/>\n                <Item ID=\"0x2DD9\"/>\n                <Item ID=\"0x2DDA\"/>\n                <Item ID=\"0x2DDB\"/>\n                <Item ID=\"0x2DDC\"/>\n                <Item ID=\"0x2DDD\"/>\n                <Item ID=\"0x2DDE\"/>\n                <Item ID=\"0x2DDF\"/>\n                <Item ID=\"0x2DE0\"/>\n                <Item ID=\"0x2DE1\"/>\n                <Item ID=\"0x2DE2\"/>\n                <Item ID=\"0x2DE3\"/>\n                <Item ID=\"0x2DE4\"/>\n                <Item ID=\"0x2DE5\"/>\n                <Item ID=\"0x2DE6\"/>\n                <Item ID=\"0x2DE7\"/>\n                <Item ID=\"0x2DE8\"/>\n                <Item ID=\"0x2DE9\"/>\n                <Item ID=\"0x2DEA\"/>\n                <Item ID=\"0x2DEB\"/>\n                <Item ID=\"0x2DEC\"/>\n                <Item ID=\"0x2DED\"/>\n                <Item ID=\"0x2DEE\"/>\n                <Item ID=\"0x2DEF\"/>\n                <Item ID=\"0x2DF0\"/>\n                <Item ID=\"0x2DF1\"/>\n                <Item ID=\"0x2DF2\"/>\n                <Item ID=\"0x2DF3\"/>\n                <Item ID=\"0x2DF4\"/>\n                <Item ID=\"0x2DF5\"/>\n                <Item ID=\"0x2DF6\"/>\n                <Item ID=\"0x30df\"/>\n                <Item ID=\"0x30e0\"/>\n                <Item ID=\"0x30e1\"/>\n                <Item ID=\"0x30e2\"/>\n                <Item ID=\"0x30e3\"/>\n                <Item ID=\"0x30e4\"/>\n                <Item ID=\"0x30e5\"/>\n                <Item ID=\"0x30e6\"/>\n            </Group>\n            <Group name=\"Large Beds\">\n                <Item ID=\"0x0A70\"/>\n                <Item ID=\"0x0A71\"/>\n                <Item ID=\"0x0A72\"/>\n                <Item ID=\"0x0A73\"/>\n                <Item ID=\"0x0A74\"/>\n                <Item ID=\"0x0A75\"/>\n                <Item ID=\"0x0A76\"/>\n                <Item ID=\"0x0A77\"/>\n                <Item ID=\"0x0A78\"/>\n                <Item ID=\"0x0A79\"/>\n                <Item ID=\"0x0A79\"/>\n                <Item ID=\"0x0A7A\"/>\n                <Item ID=\"0x0A7B\"/>\n                <Item ID=\"0x0A7C\"/>\n                <Item ID=\"0x0A7D\"/>\n                <Item ID=\"0x0A7E\"/>\n                <Item ID=\"0x0A7E\"/>\n                <Item ID=\"0x0A7E\"/>\n                <Item ID=\"0x0A7F\"/>\n                <Item ID=\"0x0A7F\"/>\n                <Item ID=\"0x0A80\"/>\n                <Item ID=\"0x0A81\"/>\n                <Item ID=\"0x0A82\"/>\n                <Item ID=\"0x0A83\"/>\n                <Item ID=\"0x0A84\"/>\n                <Item ID=\"0x0A85\"/>\n                <Item ID=\"0x0A86\"/>\n                <Item ID=\"0x0A87\"/>\n                <Item ID=\"0x0A88\"/>\n                <Item ID=\"0x0A89\"/>\n                <Item ID=\"0x0A8A\"/>\n                <Item ID=\"0x0A8B\"/>\n                <Item ID=\"0x0A8C\"/>\n                <Item ID=\"0x0A8C\"/>\n                <Item ID=\"0x0A8D\"/>\n                <Item ID=\"0x0A8D\"/>\n                <Item ID=\"0x0A8E\"/>\n                <Item ID=\"0x0A8F\"/>\n                <Item ID=\"0x0A90\"/>\n                <Item ID=\"0x0A91\"/>\n                <Item ID=\"0x0db0\"/>\n                <Item ID=\"0x0db1\"/>\n                <Item ID=\"0x0db2\"/>\n                <Item ID=\"0x0db3\"/>\n                <Item ID=\"0x0db4\"/>\n                <Item ID=\"0x0db5\"/>\n                <Item ID=\"0x11ce\"/>\n                <Item ID=\"0x11cf\"/>\n                <Item ID=\"0x11d0\"/>\n                <Item ID=\"0x11d1\"/>\n                <Item ID=\"0x11d2\"/>\n                <Item ID=\"0x11d3\"/>\n                <Item ID=\"0x11d4\"/>\n                <Item ID=\"0x11d5\"/>\n                <Item ID=\"0x3052\"/>\n                <Item ID=\"0x3053\"/>\n                <Item ID=\"0x3054\"/>\n                <Item ID=\"0x3055\"/>\n                <Item ID=\"0x3056\"/>\n                <Item ID=\"0x3057\"/>\n                <Item ID=\"0x3058\"/>\n                <Item ID=\"0x3059\"/>\n            </Group>\n            <Group name=\"Shelf etc.\">\n                <Item ID=\"0x0A2C\"/>\n                <Item ID=\"0x0A30\"/>\n                <Item ID=\"0x0A34\"/>\n                <Item ID=\"0x0A38\"/>\n                <Item ID=\"0x0A3C\"/>\n                <Item ID=\"0x0A3D\"/>\n                <Item ID=\"0x0A44\"/>\n                <Item ID=\"0x0A45\"/>\n                <Item ID=\"0x0A4D\"/>\n                <Item ID=\"0x0A4F\"/>\n                <Item ID=\"0x0A51\"/>\n                <Item ID=\"0x0A53\"/>\n                <Item ID=\"0x0A97\"/>\n                <Item ID=\"0x0A98\"/>\n                <Item ID=\"0x0A99\"/>\n                <Item ID=\"0x0A9A\"/>\n                <Item ID=\"0x0A9B\"/>\n                <Item ID=\"0x0A9C\"/>\n                <Item ID=\"0x0A9D\"/>\n                <Item ID=\"0x0A9E\"/>\n                <Item ID=\"0x2DE9\"/>\n                <Item ID=\"0x2DEA\"/>\n                <Item ID=\"0x2DEF\"/>\n                <Item ID=\"0x2DF0\"/>\n                <Item ID=\"0x2DF1\"/>\n                <Item ID=\"0x2DF2\"/>\n                <Item ID=\"0x2DF3\"/>\n                <Item ID=\"0x2DF4\"/>\n                <Item ID=\"0x2bd7\"/>\n                <Item ID=\"0x2bd8\"/>\n                <Item ID=\"0x3084\"/>\n                <Item ID=\"0x3085\"/>\n                <Item ID=\"0x3086\"/>\n                <Item ID=\"0x3087\"/>\n                <Item ID=\"0x3098\"/>\n                <Item ID=\"0x3099\"/>\n                <Item ID=\"0x309a\"/>\n                <Item ID=\"0x309b\"/>\n                <Item ID=\"0x3605\"/>\n                <Item ID=\"0x3606\"/>\n                <Item ID=\"0x3607\"/>\n                <Item ID=\"0x3608\"/>\n            </Group>\n            <Group name=\"Single Beds\">\n                <Item ID=\"0x0A5A\"/>\n                <Item ID=\"0x0A5B\"/>\n                <Item ID=\"0x0A5C\"/>\n                <Item ID=\"0x0A5D\"/>\n                <Item ID=\"0x0A5E\"/>\n                <Item ID=\"0x0A5F\"/>\n                <Item ID=\"0x0A60\"/>\n                <Item ID=\"0x0A61\"/>\n                <Item ID=\"0x0A62\"/>\n                <Item ID=\"0x0A63\"/>\n                <Item ID=\"0x0A66\"/>\n                <Item ID=\"0x0A67\"/>\n                <Item ID=\"0x0A68\"/>\n                <Item ID=\"0x0A68\"/>\n                <Item ID=\"0x0A69\"/>\n                <Item ID=\"0x0A6A\"/>\n                <Item ID=\"0x0A6B\"/>\n                <Item ID=\"0x0A6B\"/>\n                <Item ID=\"0x11F0\"/>\n                <Item ID=\"0x11F1\"/>\n                <Item ID=\"0x11F2\"/>\n                <Item ID=\"0x11F3\"/>\n                <Item ID=\"0x11F4\"/>\n                <Item ID=\"0x11F6\"/>\n                <Item ID=\"0x11F8\"/>\n                <Item ID=\"0x11FD\"/>\n                <Item ID=\"0x11FE\"/>\n                <Item ID=\"0x11FF\"/>\n                <Item ID=\"0x11Fa\"/>\n                <Item ID=\"0x1200\"/>\n                <Item ID=\"0x295C\"/>\n                <Item ID=\"0x295D\"/>\n                <Item ID=\"0x295E\"/>\n                <Item ID=\"0x295F\"/>\n                <Item ID=\"0x304C\"/>\n                <Item ID=\"0x304D\"/>\n                <Item ID=\"0x3050\"/>\n                <Item ID=\"0x3051\"/>\n            </Group>\n            <Group name=\"Sitting\">\n                <Item ID=\"0x0459\"/>\n                <Item ID=\"0x045A\"/>\n                <Item ID=\"0x045B\"/>\n                <Item ID=\"0x045C\"/>\n                <Item ID=\"0x0A2A\"/>\n                <Item ID=\"0x0A2B\"/>\n                <Item ID=\"0x0B2C\"/>\n                <Item ID=\"0x0B2D\"/>\n                <Item ID=\"0x0B2E\"/>\n                <Item ID=\"0x0B2F\"/>\n                <Item ID=\"0x0B30\"/>\n                <Item ID=\"0x0B31\"/>\n                <Item ID=\"0x0B32\"/>\n                <Item ID=\"0x0B33\"/>\n                <Item ID=\"0x0B4E\"/>\n                <Item ID=\"0x0B4F\"/>\n                <Item ID=\"0x0B50\"/>\n                <Item ID=\"0x0B51\"/>\n                <Item ID=\"0x0B52\"/>\n                <Item ID=\"0x0B53\"/>\n                <Item ID=\"0x0B54\"/>\n                <Item ID=\"0x0B55\"/>\n                <Item ID=\"0x0B56\"/>\n                <Item ID=\"0x0B57\"/>\n                <Item ID=\"0x0B58\"/>\n                <Item ID=\"0x0B59\"/>\n                <Item ID=\"0x0B5A\"/>\n                <Item ID=\"0x0B5B\"/>\n                <Item ID=\"0x0B5C\"/>\n                <Item ID=\"0x0B5D\"/>\n                <Item ID=\"0x0B5E\"/>\n                <Item ID=\"0x0B5F\"/>\n                <Item ID=\"0x0B60\"/>\n                <Item ID=\"0x0B61\"/>\n                <Item ID=\"0x0B62\"/>\n                <Item ID=\"0x0B63\"/>\n                <Item ID=\"0x0B64\"/>\n                <Item ID=\"0x0B65\"/>\n                <Item ID=\"0x0B66\"/>\n                <Item ID=\"0x0B67\"/>\n                <Item ID=\"0x0B68\"/>\n                <Item ID=\"0x0B69\"/>\n                <Item ID=\"0x0B6A\"/>\n                <Item ID=\"0x0B91\"/>\n                <Item ID=\"0x0B92\"/>\n                <Item ID=\"0x0B93\"/>\n                <Item ID=\"0x0B94\"/>\n                <Item ID=\"0x0E50\"/>\n                <Item ID=\"0x0E51\"/>\n                <Item ID=\"0x0E52\"/>\n                <Item ID=\"0x0E53\"/>\n                <Item ID=\"0x11FC\"/>\n                <Item ID=\"0x1207\"/>\n                <Item ID=\"0x1208\"/>\n                <Item ID=\"0x1209\"/>\n                <Item ID=\"0x120a\"/>\n                <Item ID=\"0x120b\"/>\n                <Item ID=\"0x120c\"/>\n                <Item ID=\"0x1218\"/>\n                <Item ID=\"0x1219\"/>\n                <Item ID=\"0x1220\"/>\n                <Item ID=\"0x1221\"/>\n                <Item ID=\"0x1526\"/>\n                <Item ID=\"0x1527\"/>\n                <Item ID=\"0x1dc7\"/>\n                <Item ID=\"0x1dc8\"/>\n                <Item ID=\"0x1dc9\"/>\n                <Item ID=\"0x1dca\"/>\n                <Item ID=\"0x1dcb\"/>\n                <Item ID=\"0x1dcc\"/>\n                <Item ID=\"0x1dcd\"/>\n                <Item ID=\"0x1dce\"/>\n                <Item ID=\"0x1dcf\"/>\n                <Item ID=\"0x1dd0\"/>\n                <Item ID=\"0x1dd1\"/>\n                <Item ID=\"0x1dd2\"/>\n                <Item ID=\"0x2DE3\"/>\n                <Item ID=\"0x2DE4\"/>\n                <Item ID=\"0x2DE5\"/>\n                <Item ID=\"0x2DE6\"/>\n                <Item ID=\"0x2DEB\"/>\n                <Item ID=\"0x2DEC\"/>\n                <Item ID=\"0x2DED\"/>\n                <Item ID=\"0x2DEE\"/>\n                <Item ID=\"0x3088\"/>\n                <Item ID=\"0x3089\"/>\n                <Item ID=\"0x308a\"/>\n                <Item ID=\"0x308b\"/>\n                <Item ID=\"0x319A\"/>\n                <Item ID=\"0x319b\"/>\n                <Item ID=\"0x35ED\"/>\n                <Item ID=\"0x35EE\"/>\n                <Item ID=\"0x3dff\"/>\n                <Item ID=\"0x3e00\"/>\n            </Group>\n            <Group name=\"Stone Fireplaces + Oven\">\n                <Item ID=\"0x045D\"/>\n                <Item ID=\"0x045E\"/>\n                <Item ID=\"0x045F\"/>\n                <Item ID=\"0x0460\"/>\n                <Item ID=\"0x0461\"/>\n                <Item ID=\"0x0462\"/>\n                <Item ID=\"0x046E\"/>\n                <Item ID=\"0x046F\"/>\n                <Item ID=\"0x0475\"/>\n                <Item ID=\"0x047B\"/>\n                <Item ID=\"0x0482\"/>\n                <Item ID=\"0x0489\"/>\n                <Item ID=\"0x07D6\"/>\n                <Item ID=\"0x07D9\"/>\n                <Item ID=\"0x08CF\"/>\n                <Item ID=\"0x08D0\"/>\n                <Item ID=\"0x08D1\"/>\n                <Item ID=\"0x08D2\"/>\n                <Item ID=\"0x08D3\"/>\n                <Item ID=\"0x08D4\"/>\n                <Item ID=\"0x08D5\"/>\n                <Item ID=\"0x08D6\"/>\n                <Item ID=\"0x08D8\"/>\n                <Item ID=\"0x08D9\"/>\n                <Item ID=\"0x08DA\"/>\n                <Item ID=\"0x08DB\"/>\n                <Item ID=\"0x08DC\"/>\n                <Item ID=\"0x08DD\"/>\n                <Item ID=\"0x08DE\"/>\n                <Item ID=\"0x08DF\"/>\n                <Item ID=\"0x092B\"/>\n                <Item ID=\"0x092C\"/>\n                <Item ID=\"0x0930\"/>\n                <Item ID=\"0x0931\"/>\n                <Item ID=\"0x0935\"/>\n                <Item ID=\"0x0936\"/>\n                <Item ID=\"0x0937\"/>\n                <Item ID=\"0x093D\"/>\n                <Item ID=\"0x0943\"/>\n                <Item ID=\"0x0944\"/>\n                <Item ID=\"0x0945\"/>\n                <Item ID=\"0x094B\"/>\n                <Item ID=\"0x0951\"/>\n                <Item ID=\"0x0952\"/>\n                <Item ID=\"0x0953\"/>\n                <Item ID=\"0x0959\"/>\n                <Item ID=\"0x095F\"/>\n                <Item ID=\"0x0960\"/>\n                <Item ID=\"0x0961\"/>\n                <Item ID=\"0x0967\"/>\n                <Item ID=\"0x11ec\"/>\n                <Item ID=\"0x11ed\"/>\n                <Item ID=\"0x11ee\"/>\n                <Item ID=\"0x11ef\"/>\n                <Item ID=\"0x2350\"/>\n                <Item ID=\"0x2351\"/>\n                <Item ID=\"0x2352\"/>\n                <Item ID=\"0x2358\"/>\n                <Item ID=\"0x235e\"/>\n                <Item ID=\"0x235f\"/>\n                <Item ID=\"0x2360\"/>\n                <Item ID=\"0x2366\"/>\n                <Item ID=\"0x29FD\"/>\n                <Item ID=\"0x2A04\"/>\n                <Item ID=\"0x2DDB\"/>\n                <Item ID=\"0x2DDC\"/>\n                <Item ID=\"0x3728\"/>\n            </Group>\n            <Group name=\"Table\">\n                <Item ID=\"0x0B34\"/>\n                <Item ID=\"0x0B35\"/>\n                <Item ID=\"0x0B37\"/>\n                <Item ID=\"0x0B38\"/>\n                <Item ID=\"0x0B3C\"/>\n                <Item ID=\"0x0B3D\"/>\n                <Item ID=\"0x0B3E\"/>\n                <Item ID=\"0x0B3F\"/>\n                <Item ID=\"0x0B40\"/>\n                <Item ID=\"0x0B49\"/>\n                <Item ID=\"0x0B4A\"/>\n                <Item ID=\"0x0B4B\"/>\n                <Item ID=\"0x0B4C\"/>\n                <Item ID=\"0x0B6B\"/>\n                <Item ID=\"0x0B6C\"/>\n                <Item ID=\"0x0B6D\"/>\n                <Item ID=\"0x0B6E\"/>\n                <Item ID=\"0x0B6F\"/>\n                <Item ID=\"0x0B70\"/>\n                <Item ID=\"0x0B71\"/>\n                <Item ID=\"0x0B72\"/>\n                <Item ID=\"0x0B73\"/>\n                <Item ID=\"0x0B73\"/>\n                <Item ID=\"0x0B74\"/>\n                <Item ID=\"0x0B75\"/>\n                <Item ID=\"0x0B76\"/>\n                <Item ID=\"0x0B77\"/>\n                <Item ID=\"0x0B78\"/>\n                <Item ID=\"0x0B79\"/>\n                <Item ID=\"0x0B7A\"/>\n                <Item ID=\"0x0B7A\"/>\n                <Item ID=\"0x0B7D\"/>\n                <Item ID=\"0x0B7E\"/>\n                <Item ID=\"0x0B7F\"/>\n                <Item ID=\"0x0B80\"/>\n                <Item ID=\"0x0B81\"/>\n                <Item ID=\"0x0B82\"/>\n                <Item ID=\"0x0B83\"/>\n                <Item ID=\"0x0B84\"/>\n                <Item ID=\"0x0B85\"/>\n                <Item ID=\"0x0B86\"/>\n                <Item ID=\"0x0B86\"/>\n                <Item ID=\"0x0B87\"/>\n                <Item ID=\"0x0B88\"/>\n                <Item ID=\"0x0B89\"/>\n                <Item ID=\"0x0B8A\"/>\n                <Item ID=\"0x0B8B\"/>\n                <Item ID=\"0x0B8C\"/>\n                <Item ID=\"0x0B8D\"/>\n                <Item ID=\"0x0B8E\"/>\n                <Item ID=\"0x0B90\"/>\n                <Item ID=\"0x118B\"/>\n                <Item ID=\"0x118C\"/>\n                <Item ID=\"0x118D\"/>\n                <Item ID=\"0x118E\"/>\n                <Item ID=\"0x118F\"/>\n                <Item ID=\"0x1190\"/>\n                <Item ID=\"0x1191\"/>\n                <Item ID=\"0x1192\"/>\n                <Item ID=\"0x11D6\"/>\n                <Item ID=\"0x11D7\"/>\n                <Item ID=\"0x11D8\"/>\n                <Item ID=\"0x11D9\"/>\n                <Item ID=\"0x11DA\"/>\n                <Item ID=\"0x11DB\"/>\n                <Item ID=\"0x11DC\"/>\n                <Item ID=\"0x11DD\"/>\n                <Item ID=\"0x11DE\"/>\n                <Item ID=\"0x11DF\"/>\n                <Item ID=\"0x11E0\"/>\n                <Item ID=\"0x11E1\"/>\n                <Item ID=\"0x1201\"/>\n                <Item ID=\"0x1202\"/>\n                <Item ID=\"0x1203\"/>\n                <Item ID=\"0x1204\"/>\n                <Item ID=\"0x1205\"/>\n                <Item ID=\"0x1206\"/>\n                <Item ID=\"0x1667\"/>\n                <Item ID=\"0x1668\"/>\n                <Item ID=\"0x1669\"/>\n                <Item ID=\"0x166A\"/>\n                <Item ID=\"0x166B\"/>\n                <Item ID=\"0x166C\"/>\n                <Item ID=\"0x1DBB\"/>\n                <Item ID=\"0x1DBC\"/>\n                <Item ID=\"0x1DBD\"/>\n                <Item ID=\"0x1DBE\"/>\n                <Item ID=\"0x1DBF\"/>\n                <Item ID=\"0x1DC0\"/>\n                <Item ID=\"0x1DC1\"/>\n                <Item ID=\"0x1DC2\"/>\n                <Item ID=\"0x1DC3\"/>\n                <Item ID=\"0x1DC4\"/>\n                <Item ID=\"0x1DC5\"/>\n                <Item ID=\"0x1DC6\"/>\n                <Item ID=\"0x1da5\"/>\n                <Item ID=\"0x1da6\"/>\n                <Item ID=\"0x1da7\"/>\n                <Item ID=\"0x1da8\"/>\n                <Item ID=\"0x1da9\"/>\n                <Item ID=\"0x1daa\"/>\n                <Item ID=\"0x1dab\"/>\n                <Item ID=\"0x1dac\"/>\n                <Item ID=\"0x207e\"/>\n                <Item ID=\"0x207f\"/>\n                <Item ID=\"0x2819\"/>\n                <Item ID=\"0x281A\"/>\n                <Item ID=\"0x2D4B\"/>\n                <Item ID=\"0x2D4C\"/>\n                <Item ID=\"0x2D4D\"/>\n                <Item ID=\"0x2D4E\"/>\n                <Item ID=\"0x2DDD\"/>\n                <Item ID=\"0x2DDE\"/>\n                <Item ID=\"0x2DE1\"/>\n                <Item ID=\"0x2DE2\"/>\n                <Item ID=\"0x2DE7\"/>\n                <Item ID=\"0x2DE8\"/>\n                <Item ID=\"0x308c\"/>\n                <Item ID=\"0x308d\"/>\n                <Item ID=\"0x308e\"/>\n                <Item ID=\"0x308f\"/>\n                <Item ID=\"0x3090\"/>\n                <Item ID=\"0x3091\"/>\n                <Item ID=\"0x3092\"/>\n                <Item ID=\"0x3093\"/>\n                <Item ID=\"0x3094\"/>\n                <Item ID=\"0x3095\"/>\n                <Item ID=\"0x3096\"/>\n                <Item ID=\"0x3097\"/>\n            </Group>\n        </Group>\n        <Group name=\"Leaves, Branches, Trash\">\n            <Item ID=\"0x0911\"/>\n            <Item ID=\"0x0912\"/>\n            <Item ID=\"0x0913\"/>\n            <Item ID=\"0x0914\"/>\n            <Item ID=\"0x10Ee\"/>\n            <Item ID=\"0x10Ef\"/>\n            <Item ID=\"0x10f0\"/>\n            <Item ID=\"0x10f1\"/>\n            <Item ID=\"0x10f2\"/>\n            <Item ID=\"0x10f3\"/>\n            <Item ID=\"0x17cD\"/>\n            <Item ID=\"0x17cE\"/>\n            <Item ID=\"0x187e\"/>\n            <Item ID=\"0x187f\"/>\n            <Item ID=\"0x1880\"/>\n            <Item ID=\"0x1881\"/>\n            <Item ID=\"0x1B1F\"/>\n            <Item ID=\"0x1B20\"/>\n            <Item ID=\"0x1B21\"/>\n            <Item ID=\"0x1B22\"/>\n            <Item ID=\"0x1B23\"/>\n            <Item ID=\"0x1B24\"/>\n            <Item ID=\"0x1B25\"/>\n            <Item ID=\"0x1B26\"/>\n            <Item ID=\"0x1B81\"/>\n            <Item ID=\"0x1B82\"/>\n            <Item ID=\"0x1B83\"/>\n            <Item ID=\"0x1B84\"/>\n            <Item ID=\"0x1B85\"/>\n            <Item ID=\"0x1B86\"/>\n            <Item ID=\"0x1B87\"/>\n            <Item ID=\"0x1B88\"/>\n            <Item ID=\"0x1B89\"/>\n            <Item ID=\"0x1B8A\"/>\n            <Item ID=\"0x1B8B\"/>\n            <Item ID=\"0x1B8C\"/>\n            <Item ID=\"0x1B8D\"/>\n            <Item ID=\"0x1B8E\"/>\n            <Item ID=\"0x1B8F\"/>\n            <Item ID=\"0x1B90\"/>\n            <Item ID=\"0x1B91\"/>\n            <Item ID=\"0x1B92\"/>\n            <Item ID=\"0x1B93\"/>\n            <Item ID=\"0x1B97\"/>\n            <Item ID=\"0x1B98\"/>\n            <Item ID=\"0x1B99\"/>\n            <Item ID=\"0x1B9A\"/>\n            <Item ID=\"0x1B9B\"/>\n            <Item ID=\"0x1B9C\"/>\n            <Item ID=\"0x1B9D\"/>\n            <Item ID=\"0x1B9E\"/>\n            <Item ID=\"0x1B9F\"/>\n            <Item ID=\"0x1BA0\"/>\n            <Item ID=\"0x1BA1\"/>\n            <Item ID=\"0x1BA2\"/>\n            <Item ID=\"0x1BA3\"/>\n            <Item ID=\"0x1BA4\"/>\n            <Item ID=\"0x1BA5\"/>\n            <Item ID=\"0x1BA6\"/>\n            <Item ID=\"0x1BA7\"/>\n            <Item ID=\"0x1BA8\"/>\n            <Item ID=\"0x1BA9\"/>\n            <Item ID=\"0x1BAA\"/>\n            <Item ID=\"0x1BAB\"/>\n            <Item ID=\"0x1BAC\"/>\n            <Item ID=\"0x1BAD\"/>\n            <Item ID=\"0x1BAE\"/>\n            <Item ID=\"0x1BAF\"/>\n            <Item ID=\"0x1BB0\"/>\n            <Item ID=\"0x1BB1\"/>\n            <Item ID=\"0x1BB2\"/>\n            <Item ID=\"0x1BB4\"/>\n            <Item ID=\"0x1BB5\"/>\n            <Item ID=\"0x1BB6\"/>\n            <Item ID=\"0x1BB7\"/>\n            <Item ID=\"0x1BB8\"/>\n            <Item ID=\"0x1BB9\"/>\n            <Item ID=\"0x1BBA\"/>\n            <Item ID=\"0x1BBB\"/>\n            <Item ID=\"0x1BBC\"/>\n            <Item ID=\"0x1BBD\"/>\n            <Item ID=\"0x1db3\"/>\n            <Item ID=\"0x1db4\"/>\n            <Item ID=\"0x1db5\"/>\n            <Item ID=\"0x1db6\"/>\n            <Item ID=\"0x223a\"/>\n            <Item ID=\"0x223b\"/>\n            <Item ID=\"0x223c\"/>\n            <Item ID=\"0x223d\"/>\n            <Item ID=\"0x223e\"/>\n            <Item ID=\"0x223f\"/>\n            <Item ID=\"0x2240\"/>\n            <Item ID=\"0x2241\"/>\n            <Item ID=\"0x2242\"/>\n            <Item ID=\"0x2243\"/>\n            <Item ID=\"0x2244\"/>\n            <Item ID=\"0x2245\"/>\n            <Item ID=\"0x2246\"/>\n            <Item ID=\"0x2247\"/>\n            <Item ID=\"0x2248\"/>\n            <Item ID=\"0x2249\"/>\n        </Group>\n        <Group name=\"Light Sources\">\n            <Item ID=\"0x09FB\"/>\n            <Item ID=\"0x09FC\"/>\n            <Item ID=\"0x09FE\"/>\n            <Item ID=\"0x0A00\"/>\n            <Item ID=\"0x0A01\"/>\n            <Item ID=\"0x0A03\"/>\n            <Item ID=\"0x0A05\"/>\n            <Item ID=\"0x0A06\"/>\n            <Item ID=\"0x0A07\"/>\n            <Item ID=\"0x0A0A\"/>\n            <Item ID=\"0x0A0B\"/>\n            <Item ID=\"0x0A0C\"/>\n            <Item ID=\"0x0A0F\"/>\n            <Item ID=\"0x0A13\"/>\n            <Item ID=\"0x0A15\"/>\n            <Item ID=\"0x0A18\"/>\n            <Item ID=\"0x0A1A\"/>\n            <Item ID=\"0x0A1D\"/>\n            <Item ID=\"0x0A1F\"/>\n            <Item ID=\"0x0A20\"/>\n            <Item ID=\"0x0A22\"/>\n            <Item ID=\"0x0A25\"/>\n            <Item ID=\"0x0A26\"/>\n            <Item ID=\"0x0A27\"/>\n            <Item ID=\"0x0A28\"/>\n            <Item ID=\"0x0A29\"/>\n            <Item ID=\"0x0B1A\"/>\n            <Item ID=\"0x0B1D\"/>\n            <Item ID=\"0x0B20\"/>\n            <Item ID=\"0x0B21\"/>\n            <Item ID=\"0x0B22\"/>\n            <Item ID=\"0x0B23\"/>\n            <Item ID=\"0x0B24\"/>\n            <Item ID=\"0x0B25\"/>\n            <Item ID=\"0x0B26\"/>\n            <Item ID=\"0x0DE1\"/>\n            <Item ID=\"0x0DE3\"/>\n            <Item ID=\"0x0DEa\"/>\n            <Item ID=\"0x0FAC\"/>\n            <Item ID=\"0x142C\"/>\n            <Item ID=\"0x142F\"/>\n            <Item ID=\"0x1430\"/>\n            <Item ID=\"0x1433\"/>\n            <Item ID=\"0x1434\"/>\n            <Item ID=\"0x1437\"/>\n            <Item ID=\"0x1646\"/>\n            <Item ID=\"0x1647\"/>\n            <Item ID=\"0x1849\"/>\n            <Item ID=\"0x184d\"/>\n            <Item ID=\"0x184e\"/>\n            <Item ID=\"0x1850\"/>\n            <Item ID=\"0x1853\"/>\n            <Item ID=\"0x1854\"/>\n            <Item ID=\"0x1857\"/>\n            <Item ID=\"0x1858\"/>\n            <Item ID=\"0x19AA\"/>\n            <Item ID=\"0x19Ab\"/>\n            <Item ID=\"0x19bb\"/>\n            <Item ID=\"0x1f2b\"/>\n            <Item ID=\"0x2419\"/>\n            <Item ID=\"0x24BB\"/>\n            <Item ID=\"0x24BC\"/>\n            <Item ID=\"0x24BD\"/>\n            <Item ID=\"0x24BE\"/>\n            <Item ID=\"0x24BF\"/>\n            <Item ID=\"0x24C0\"/>\n            <Item ID=\"0x24C1\"/>\n            <Item ID=\"0x24C2\"/>\n            <Item ID=\"0x24C3\"/>\n            <Item ID=\"0x24C4\"/>\n            <Item ID=\"0x24C5\"/>\n            <Item ID=\"0x24C6\"/>\n            <Item ID=\"0x24C7\"/>\n            <Item ID=\"0x24C8\"/>\n            <Item ID=\"0x24C9\"/>\n            <Item ID=\"0x24CA\"/>\n            <Item ID=\"0x29FD\"/>\n            <Item ID=\"0x2A04\"/>\n            <Item ID=\"0x35EF\"/>\n            <Item ID=\"0x3d94\"/>\n            <Item ID=\"0x3d97\"/>\n            <Item ID=\"0x3d98\"/>\n            <Item ID=\"0x3d9b\"/>\n        </Group>\n        <Group name=\"Misc\">\n            <Item ID=\"0x241C\"/>\n            <Item ID=\"0x241D\"/>\n            <Item ID=\"0x241E\"/>\n            <Item ID=\"0x24CB\"/>\n            <Item ID=\"0x24CC\"/>\n            <Item ID=\"0x24CD\"/>\n            <Item ID=\"0x24CE\"/>\n            <Item ID=\"0x24CF\"/>\n            <Item ID=\"0x24D0\"/>\n            <Item ID=\"0x24D1\"/>\n            <Item ID=\"0x24D2\"/>\n            <Item ID=\"0x24D3\"/>\n            <Item ID=\"0x24D4\"/>\n        </Group>\n        <Group name=\"Professions\">\n            <Group name=\"Animal Handling\">\n                <Item ID=\"0x091A\"/>\n                <Item ID=\"0x091B\"/>\n                <Item ID=\"0x0B41\"/>\n                <Item ID=\"0x0B42\"/>\n                <Item ID=\"0x0B43\"/>\n                <Item ID=\"0x0B44\"/>\n                <Item ID=\"0x0F34\"/>\n                <Item ID=\"0x0F35\"/>\n                <Item ID=\"0x0F36\"/>\n                <Item ID=\"0x0F37\"/>\n                <Item ID=\"0x0F38\"/>\n                <Item ID=\"0x0F3B\"/>\n                <Item ID=\"0x0F3C\"/>\n                <Item ID=\"0x0FB6\"/>\n                <Item ID=\"0x0FFA\"/>\n                <Item ID=\"0x1036\"/>\n                <Item ID=\"0x1037\"/>\n                <Item ID=\"0x1038\"/>\n                <Item ID=\"0x1370\"/>\n                <Item ID=\"0x1371\"/>\n                <Item ID=\"0x1372\"/>\n                <Item ID=\"0x1373\"/>\n                <Item ID=\"0x1374\"/>\n                <Item ID=\"0x1375\"/>\n                <Item ID=\"0x1376\"/>\n                <Item ID=\"0x1377\"/>\n                <Item ID=\"0x1378\"/>\n                <Item ID=\"0x1379\"/>\n                <Item ID=\"0x1420\"/>\n                <Item ID=\"0x1421\"/>\n                <Item ID=\"0x1422\"/>\n                <Item ID=\"0x1423\"/>\n                <Item ID=\"0x1424\"/>\n                <Item ID=\"0x1425\"/>\n                <Item ID=\"0x1426\"/>\n                <Item ID=\"0x1427\"/>\n                <Item ID=\"0x1428\"/>\n                <Item ID=\"0x1429\"/>\n                <Item ID=\"0x142A\"/>\n                <Item ID=\"0x142B\"/>\n                <Item ID=\"0x14E0\"/>\n                <Item ID=\"0x14E7\"/>\n                <Item ID=\"0x14E8\"/>\n                <Item ID=\"0x172e\"/>\n                <Item ID=\"0x1Ad4\"/>\n                <Item ID=\"0x1Ad5\"/>\n                <Item ID=\"0x2004\"/>\n                <Item ID=\"0x26b1\"/>\n                <Item ID=\"0x26b2\"/>\n                <Item ID=\"0x26b3\"/>\n                <Item ID=\"0x26b4\"/>\n                <Item ID=\"0x26b5\"/>\n                <Item ID=\"0x26b6\"/>\n                <Item ID=\"0x312D\"/>\n                <Item ID=\"0x312E\"/>\n                <Item ID=\"0x312F\"/>\n                <Item ID=\"0x3130\"/>\n                <Item ID=\"0x3BB8\"/>\n                <Item ID=\"0x3BB9\"/>\n                <Item ID=\"0x3BBa\"/>\n            </Group>\n            <Group name=\"Arcana\">\n                <Group name=\"Alchemic Vials etc.\">\n                    <Item ID=\"0x0E24\"/>\n                    <Item ID=\"0x0E25\"/>\n                    <Item ID=\"0x0E26\"/>\n                    <Item ID=\"0x0E27\"/>\n                    <Item ID=\"0x0E28\"/>\n                    <Item ID=\"0x0E29\"/>\n                    <Item ID=\"0x0E2A\"/>\n                    <Item ID=\"0x0E2B\"/>\n                    <Item ID=\"0x0E2C\"/>\n                    <Item ID=\"0x0E9B\"/>\n                    <Item ID=\"0x0EFB\"/>\n                    <Item ID=\"0x0EFC\"/>\n                    <Item ID=\"0x0EFD\"/>\n                    <Item ID=\"0x0EFE\"/>\n                    <Item ID=\"0x0EFF\"/>\n                    <Item ID=\"0x0F00\"/>\n                    <Item ID=\"0x0F01\"/>\n                    <Item ID=\"0x0F02\"/>\n                    <Item ID=\"0x0F03\"/>\n                    <Item ID=\"0x0F04\"/>\n                    <Item ID=\"0x0F06\"/>\n                    <Item ID=\"0x0F07\"/>\n                    <Item ID=\"0x0F08\"/>\n                    <Item ID=\"0x0F09\"/>\n                    <Item ID=\"0x0F0A\"/>\n                    <Item ID=\"0x0F0B\"/>\n                    <Item ID=\"0x0F0C\"/>\n                    <Item ID=\"0x0F0D\"/>\n                    <Item ID=\"0x0F0E\"/>\n                    <Item ID=\"0x0f53\"/>\n                    <Item ID=\"0x1084\"/>\n                    <Item ID=\"0x1829\"/>\n                    <Item ID=\"0x182A\"/>\n                    <Item ID=\"0x182B\"/>\n                    <Item ID=\"0x182C\"/>\n                    <Item ID=\"0x182D\"/>\n                    <Item ID=\"0x182E\"/>\n                    <Item ID=\"0x182F\"/>\n                    <Item ID=\"0x1830\"/>\n                    <Item ID=\"0x1831\"/>\n                    <Item ID=\"0x1832\"/>\n                    <Item ID=\"0x1833\"/>\n                    <Item ID=\"0x1834\"/>\n                    <Item ID=\"0x1835\"/>\n                    <Item ID=\"0x1836\"/>\n                    <Item ID=\"0x1837\"/>\n                    <Item ID=\"0x1838\"/>\n                    <Item ID=\"0x1839\"/>\n                    <Item ID=\"0x183A\"/>\n                    <Item ID=\"0x183B\"/>\n                    <Item ID=\"0x183C\"/>\n                    <Item ID=\"0x183D\"/>\n                    <Item ID=\"0x183E\"/>\n                    <Item ID=\"0x1841\"/>\n                    <Item ID=\"0x1844\"/>\n                    <Item ID=\"0x1847\"/>\n                    <Item ID=\"0x1848\"/>\n                    <Item ID=\"0x185B\"/>\n                    <Item ID=\"0x185C\"/>\n                    <Item ID=\"0x185D\"/>\n                    <Item ID=\"0x185E\"/>\n                    <Item ID=\"0x21fe\"/>\n                </Group>\n                <Group name=\"Decoration\">\n                    <Item ID=\"0x0E44\"/>\n                    <Item ID=\"0x0E45\"/>\n                    <Item ID=\"0x0E46\"/>\n                    <Item ID=\"0x0E47\"/>\n                    <Item ID=\"0x0E48\"/>\n                    <Item ID=\"0x0E49\"/>\n                    <Item ID=\"0x0E4A\"/>\n                    <Item ID=\"0x0E4B\"/>\n                    <Item ID=\"0x0E4C\"/>\n                    <Item ID=\"0x0E4D\"/>\n                    <Item ID=\"0x0E4E\"/>\n                    <Item ID=\"0x0E4F\"/>\n                    <Item ID=\"0x1005\"/>\n                    <Item ID=\"0x1006\"/>\n                    <Item ID=\"0x1007\"/>\n                    <Item ID=\"0x10FC\"/>\n                    <Item ID=\"0x110F\"/>\n                    <Item ID=\"0x1AD6\"/>\n                    <Item ID=\"0x1AD7\"/>\n                    <Item ID=\"0x1F18\"/>\n                    <Item ID=\"0x1F19\"/>\n                    <Item ID=\"0x1F1C\"/>\n                    <Item ID=\"0x1F1F\"/>\n                    <Item ID=\"0x1F20\"/>\n                    <Item ID=\"0x1F21\"/>\n                    <Item ID=\"0x1F22\"/>\n                    <Item ID=\"0x2A93\"/>\n                    <Item ID=\"0x2A94\"/>\n                    <Item ID=\"0x2AA1\"/>\n                    <Item ID=\"0x2AA2\"/>\n                    <Item ID=\"0x2AA3\"/>\n                    <Item ID=\"0x2AA4\"/>\n                    <Item ID=\"0x2AA5\"/>\n                    <Item ID=\"0x2AA6\"/>\n                    <Item ID=\"0x2AA7\"/>\n                    <Item ID=\"0x2AA8\"/>\n                    <Item ID=\"0x2AA9\"/>\n                    <Item ID=\"0x2ADC\"/>\n                    <Item ID=\"0x2ADd\"/>\n                    <Item ID=\"0x2AEC\"/>\n                    <Item ID=\"0x2AEd\"/>\n                    <Item ID=\"0x307B\"/>\n                    <Item ID=\"0x307C\"/>\n                    <Item ID=\"0x307D\"/>\n                    <Item ID=\"0x307E\"/>\n                    <Item ID=\"0x307F\"/>\n                    <Item ID=\"0x3080\"/>\n                    <Item ID=\"0x3081\"/>\n                    <Item ID=\"0x3082\"/>\n                    <Item ID=\"0x3083\"/>\n                    <Item ID=\"0x314c\"/>\n                    <Item ID=\"0x314d\"/>\n                    <Item ID=\"0x314e\"/>\n                    <Item ID=\"0x314f\"/>\n                    <Item ID=\"0x3150\"/>\n                    <Item ID=\"0x3151\"/>\n                    <Item ID=\"0x3152\"/>\n                    <Item ID=\"0x3153\"/>\n                    <Item ID=\"0x3154\"/>\n                    <Item ID=\"0x32F3\"/>\n                    <Item ID=\"0x32F4\"/>\n                    <Item ID=\"0x3660\"/>\n                </Group>\n                <Group name=\"Effects\">\n                    <Item ID=\"0x0dda\"/>\n                    <Item ID=\"0x1153\"/>\n                    <Item ID=\"0x1ed9\"/>\n                    <Item ID=\"0x1ee2\"/>\n                    <Item ID=\"0x1eeb\"/>\n                    <Item ID=\"0x1ef4\"/>\n                    <Item ID=\"0x373a\"/>\n                    <Item ID=\"0x374a\"/>\n                    <Item ID=\"0x375a\"/>\n                    <Item ID=\"0x376a\"/>\n                    <Item ID=\"0x3779\"/>\n                    <Item ID=\"0x37b9\"/>\n                    <Item ID=\"0x37c4\"/>\n                    <Item ID=\"0x3818\"/>\n                </Group>\n                <Group name=\"Ingredients\">\n                    <Item ID=\"0x021B\"/>\n                    <Item ID=\"0x021C\"/>\n                    <Item ID=\"0x023A\"/>\n                    <Item ID=\"0x023B\"/>\n                    <Item ID=\"0x023F\"/>\n                    <Item ID=\"0x024B\"/>\n                    <Item ID=\"0x0C3B\"/>\n                    <Item ID=\"0x0C3C\"/>\n                    <Item ID=\"0x0C3D\"/>\n                    <Item ID=\"0x0C3E\"/>\n                    <Item ID=\"0x0C3F\"/>\n                    <Item ID=\"0x0C40\"/>\n                    <Item ID=\"0x0C41\"/>\n                    <Item ID=\"0x0C42\"/>\n                    <Item ID=\"0x0F0F\"/>\n                    <Item ID=\"0x0F10\"/>\n                    <Item ID=\"0x0F11\"/>\n                    <Item ID=\"0x0F12\"/>\n                    <Item ID=\"0x0F13\"/>\n                    <Item ID=\"0x0F14\"/>\n                    <Item ID=\"0x0F15\"/>\n                    <Item ID=\"0x0F16\"/>\n                    <Item ID=\"0x0F17\"/>\n                    <Item ID=\"0x0F18\"/>\n                    <Item ID=\"0x0F19\"/>\n                    <Item ID=\"0x0F1A\"/>\n                    <Item ID=\"0x0F1B\"/>\n                    <Item ID=\"0x0F1C\"/>\n                    <Item ID=\"0x0F1D\"/>\n                    <Item ID=\"0x0F1E\"/>\n                    <Item ID=\"0x0F1F\"/>\n                    <Item ID=\"0x0F20\"/>\n                    <Item ID=\"0x0F21\"/>\n                    <Item ID=\"0x0F22\"/>\n                    <Item ID=\"0x0F23\"/>\n                    <Item ID=\"0x0F24\"/>\n                    <Item ID=\"0x0F25\"/>\n                    <Item ID=\"0x0F26\"/>\n                    <Item ID=\"0x0F27\"/>\n                    <Item ID=\"0x0F28\"/>\n                    <Item ID=\"0x0F29\"/>\n                    <Item ID=\"0x0F2A\"/>\n                    <Item ID=\"0x0F2B\"/>\n                    <Item ID=\"0x0F2C\"/>\n                    <Item ID=\"0x0F2D\"/>\n                    <Item ID=\"0x0F2E\"/>\n                    <Item ID=\"0x0F2F\"/>\n                    <Item ID=\"0x0F30\"/>\n                    <Item ID=\"0x0F78\"/>\n                    <Item ID=\"0x0F79\"/>\n                    <Item ID=\"0x0F7A\"/>\n                    <Item ID=\"0x0F7B\"/>\n                    <Item ID=\"0x0F7C\"/>\n                    <Item ID=\"0x0F7D\"/>\n                    <Item ID=\"0x0F7E\"/>\n                    <Item ID=\"0x0F7F\"/>\n                    <Item ID=\"0x0F80\"/>\n                    <Item ID=\"0x0F81\"/>\n                    <Item ID=\"0x0F82\"/>\n                    <Item ID=\"0x0F83\"/>\n                    <Item ID=\"0x0F84\"/>\n                    <Item ID=\"0x0F85\"/>\n                    <Item ID=\"0x0F86\"/>\n                    <Item ID=\"0x0F87\"/>\n                    <Item ID=\"0x0F88\"/>\n                    <Item ID=\"0x0F89\"/>\n                    <Item ID=\"0x0F8A\"/>\n                    <Item ID=\"0x0F8B\"/>\n                    <Item ID=\"0x0F8C\"/>\n                    <Item ID=\"0x0F8D\"/>\n                    <Item ID=\"0x0F8E\"/>\n                    <Item ID=\"0x0F8F\"/>\n                    <Item ID=\"0x0F90\"/>\n                    <Item ID=\"0x0F91\"/>\n                    <Item ID=\"0x18DD\"/>\n                    <Item ID=\"0x18DE\"/>\n                    <Item ID=\"0x18EB\"/>\n                    <Item ID=\"0x18EC\"/>\n                    <Item ID=\"0x1C18\"/>\n                    <Item ID=\"0x1C19\"/>\n                    <Item ID=\"0x1Ea7\"/>\n                    <Item ID=\"0x1f13\"/>\n                    <Item ID=\"0x2003\"/>\n                    <Item ID=\"0x26b1\"/>\n                    <Item ID=\"0x26b2\"/>\n                    <Item ID=\"0x26b3\"/>\n                    <Item ID=\"0x26b4\"/>\n                    <Item ID=\"0x26b5\"/>\n                    <Item ID=\"0x26b6\"/>\n                    <Item ID=\"0x26b7\"/>\n                    <Item ID=\"0x26b8\"/>\n                    <Item ID=\"0x284B\"/>\n                    <Item ID=\"0x284C\"/>\n                    <Item ID=\"0x2AAA\"/>\n                    <Item ID=\"0x2dae\"/>\n                    <Item ID=\"0x2daf\"/>\n                    <Item ID=\"0x2db1\"/>\n                    <Item ID=\"0x2db1\"/>\n                    <Item ID=\"0x2db2\"/>\n                    <Item ID=\"0x2db2\"/>\n                    <Item ID=\"0x2db3\"/>\n                    <Item ID=\"0x2db3\"/>\n                    <Item ID=\"0x2db4\"/>\n                    <Item ID=\"0x2db4\"/>\n                    <Item ID=\"0x2db5\"/>\n                    <Item ID=\"0x2db5\"/>\n                    <Item ID=\"0x2db6\"/>\n                    <Item ID=\"0x2db6\"/>\n                    <Item ID=\"0x2db7\"/>\n                    <Item ID=\"0x2db7\"/>\n                    <Item ID=\"0x2db8\"/>\n                    <Item ID=\"0x2db8\"/>\n                    <Item ID=\"0x2db9\"/>\n                    <Item ID=\"0x2db9\"/>\n                    <Item ID=\"0x2dba\"/>\n                    <Item ID=\"0x2dba\"/>\n                    <Item ID=\"0x2f60\"/>\n                    <Item ID=\"0x3155\"/>\n                    <Item ID=\"0x3183\"/>\n                    <Item ID=\"0x3184\"/>\n                    <Item ID=\"0x3186\"/>\n                    <Item ID=\"0x3188\"/>\n                    <Item ID=\"0x3189\"/>\n                    <Item ID=\"0x318A\"/>\n                    <Item ID=\"0x318B\"/>\n                    <Item ID=\"0x318C\"/>\n                    <Item ID=\"0x318D\"/>\n                    <Item ID=\"0x318E\"/>\n                    <Item ID=\"0x318F\"/>\n                    <Item ID=\"0x3190\"/>\n                    <Item ID=\"0x3191\"/>\n                    <Item ID=\"0x3192\"/>\n                    <Item ID=\"0x3193\"/>\n                    <Item ID=\"0x3194\"/>\n                    <Item ID=\"0x3195\"/>\n                    <Item ID=\"0x3196\"/>\n                    <Item ID=\"0x3197\"/>\n                    <Item ID=\"0x3198\"/>\n                    <Item ID=\"0x3199\"/>\n                    <Item ID=\"0x3678\"/>\n                    <Item ID=\"0x3679\"/>\n                    <Item ID=\"0x367A\"/>\n                    <Item ID=\"0x3db8\"/>\n                    <Item ID=\"0x3db9\"/>\n                    <Item ID=\"0x3dba\"/>\n                    <Item ID=\"0x3dbb\"/>\n                </Group>\n                <Group name=\"Misc\">\n                    <Item ID=\"0x2002\"/>\n                </Group>\n                <Group name=\"Runes + Books\">\n                    <Item ID=\"0x023C\"/>\n                    <Item ID=\"0x023D\"/>\n                    <Item ID=\"0x023E\"/>\n                    <Item ID=\"0x0E5C\"/>\n                    <Item ID=\"0x0E5F\"/>\n                    <Item ID=\"0x0E62\"/>\n                    <Item ID=\"0x0E65\"/>\n                    <Item ID=\"0x0E68\"/>\n                    <Item ID=\"0x181d\"/>\n                    <Item ID=\"0x181e\"/>\n                    <Item ID=\"0x181f\"/>\n                    <Item ID=\"0x1820\"/>\n                    <Item ID=\"0x1821\"/>\n                    <Item ID=\"0x1822\"/>\n                    <Item ID=\"0x1823\"/>\n                    <Item ID=\"0x1824\"/>\n                    <Item ID=\"0x1825\"/>\n                    <Item ID=\"0x1826\"/>\n                    <Item ID=\"0x1827\"/>\n                    <Item ID=\"0x1828\"/>\n                    <Item ID=\"0x1C11\"/>\n                    <Item ID=\"0x1F14\"/>\n                    <Item ID=\"0x1F15\"/>\n                    <Item ID=\"0x1F16\"/>\n                    <Item ID=\"0x1F17\"/>\n                    <Item ID=\"0x2d5e\"/>\n                </Group>\n                <Group name=\"Scrolls\">\n                    <Item ID=\"0x1F2D\"/>\n                    <Item ID=\"0x1F2E\"/>\n                    <Item ID=\"0x1F2F\"/>\n                    <Item ID=\"0x1F30\"/>\n                    <Item ID=\"0x1F31\"/>\n                    <Item ID=\"0x1F32\"/>\n                    <Item ID=\"0x1F33\"/>\n                    <Item ID=\"0x1F34\"/>\n                    <Item ID=\"0x1F35\"/>\n                    <Item ID=\"0x1F36\"/>\n                    <Item ID=\"0x1F37\"/>\n                    <Item ID=\"0x1F38\"/>\n                    <Item ID=\"0x1F39\"/>\n                    <Item ID=\"0x1F3A\"/>\n                    <Item ID=\"0x1F3B\"/>\n                    <Item ID=\"0x1F3C\"/>\n                    <Item ID=\"0x1F3D\"/>\n                    <Item ID=\"0x1F3E\"/>\n                    <Item ID=\"0x1F3F\"/>\n                    <Item ID=\"0x1F40\"/>\n                    <Item ID=\"0x1F41\"/>\n                    <Item ID=\"0x1F42\"/>\n                    <Item ID=\"0x1F43\"/>\n                    <Item ID=\"0x1F44\"/>\n                    <Item ID=\"0x1F45\"/>\n                    <Item ID=\"0x1F46\"/>\n                    <Item ID=\"0x1F47\"/>\n                    <Item ID=\"0x1F48\"/>\n                    <Item ID=\"0x1F49\"/>\n                    <Item ID=\"0x1F4A\"/>\n                    <Item ID=\"0x1F4B\"/>\n                    <Item ID=\"0x1F4C\"/>\n                    <Item ID=\"0x1F4D\"/>\n                    <Item ID=\"0x1F4E\"/>\n                    <Item ID=\"0x1F4F\"/>\n                    <Item ID=\"0x1F50\"/>\n                    <Item ID=\"0x1F51\"/>\n                    <Item ID=\"0x1F52\"/>\n                    <Item ID=\"0x1F53\"/>\n                    <Item ID=\"0x1F54\"/>\n                    <Item ID=\"0x1F55\"/>\n                    <Item ID=\"0x1F56\"/>\n                    <Item ID=\"0x1F57\"/>\n                    <Item ID=\"0x1F58\"/>\n                    <Item ID=\"0x1F59\"/>\n                    <Item ID=\"0x1F5A\"/>\n                    <Item ID=\"0x1F5B\"/>\n                    <Item ID=\"0x1F5C\"/>\n                    <Item ID=\"0x1F5D\"/>\n                    <Item ID=\"0x1F5E\"/>\n                    <Item ID=\"0x1F5F\"/>\n                    <Item ID=\"0x1F60\"/>\n                    <Item ID=\"0x1F61\"/>\n                    <Item ID=\"0x1F62\"/>\n                    <Item ID=\"0x1F63\"/>\n                    <Item ID=\"0x1F64\"/>\n                    <Item ID=\"0x1F65\"/>\n                    <Item ID=\"0x1F66\"/>\n                    <Item ID=\"0x1F67\"/>\n                    <Item ID=\"0x1F68\"/>\n                    <Item ID=\"0x1F69\"/>\n                    <Item ID=\"0x1F6A\"/>\n                    <Item ID=\"0x1F6B\"/>\n                    <Item ID=\"0x1F6C\"/>\n                    <Item ID=\"0x1F6D\"/>\n                    <Item ID=\"0x1F6E\"/>\n                    <Item ID=\"0x1F6F\"/>\n                    <Item ID=\"0x1F70\"/>\n                    <Item ID=\"0x1F71\"/>\n                    <Item ID=\"0x1F72\"/>\n                    <Item ID=\"0x1f23\"/>\n                    <Item ID=\"0x2258\"/>\n                    <Item ID=\"0x2260\"/>\n                    <Item ID=\"0x2261\"/>\n                    <Item ID=\"0x2262\"/>\n                    <Item ID=\"0x2263\"/>\n                    <Item ID=\"0x2264\"/>\n                    <Item ID=\"0x2265\"/>\n                    <Item ID=\"0x2266\"/>\n                    <Item ID=\"0x2267\"/>\n                    <Item ID=\"0x2268\"/>\n                    <Item ID=\"0x2269\"/>\n                    <Item ID=\"0x226A\"/>\n                    <Item ID=\"0x226B\"/>\n                    <Item ID=\"0x226C\"/>\n                    <Item ID=\"0x226D\"/>\n                    <Item ID=\"0x226E\"/>\n                    <Item ID=\"0x226F\"/>\n                    <Item ID=\"0x2270\"/>\n                    <Item ID=\"0x2271\"/>\n                    <Item ID=\"0x2272\"/>\n                    <Item ID=\"0x2273\"/>\n                    <Item ID=\"0x2274\"/>\n                    <Item ID=\"0x2275\"/>\n                    <Item ID=\"0x2276\"/>\n                    <Item ID=\"0x2277\"/>\n                    <Item ID=\"0x2278\"/>\n                    <Item ID=\"0x2279\"/>\n                    <Item ID=\"0x227A\"/>\n                    <Item ID=\"0x227B\"/>\n                    <Item ID=\"0x227C\"/>\n                    <Item ID=\"0x2D51\"/>\n                    <Item ID=\"0x2D52\"/>\n                    <Item ID=\"0x2D53\"/>\n                    <Item ID=\"0x2D54\"/>\n                    <Item ID=\"0x2D55\"/>\n                    <Item ID=\"0x2D56\"/>\n                    <Item ID=\"0x2D57\"/>\n                    <Item ID=\"0x2D58\"/>\n                    <Item ID=\"0x2D59\"/>\n                    <Item ID=\"0x2D5a\"/>\n                    <Item ID=\"0x2D5b\"/>\n                    <Item ID=\"0x2D5c\"/>\n                    <Item ID=\"0x2D5d\"/>\n                    <Item ID=\"0x2D5e\"/>\n                    <Item ID=\"0x2D5f\"/>\n                    <Item ID=\"0x2D60\"/>\n                    <Item ID=\"0x2D61\"/>\n                    <Item ID=\"0x2D62\"/>\n                    <Item ID=\"0x2d9e\"/>\n                    <Item ID=\"0x2d9f\"/>\n                    <Item ID=\"0x2da0\"/>\n                    <Item ID=\"0x2da1\"/>\n                    <Item ID=\"0x2da2\"/>\n                    <Item ID=\"0x2da3\"/>\n                    <Item ID=\"0x2da4\"/>\n                    <Item ID=\"0x2da5\"/>\n                    <Item ID=\"0x2da6\"/>\n                    <Item ID=\"0x2da7\"/>\n                    <Item ID=\"0x2da8\"/>\n                    <Item ID=\"0x2da9\"/>\n                    <Item ID=\"0x2daa\"/>\n                    <Item ID=\"0x2dab\"/>\n                    <Item ID=\"0x2dac\"/>\n                    <Item ID=\"0x2dad\"/>\n                </Group>\n                <Group name=\"Tools\">\n                    <Item ID=\"0x0DF2\"/>\n                    <Item ID=\"0x0DF3\"/>\n                    <Item ID=\"0x0DF4\"/>\n                    <Item ID=\"0x0DF5\"/>\n                    <Item ID=\"0x0E2d\"/>\n                    <Item ID=\"0x0E30\"/>\n                    <Item ID=\"0x0E31\"/>\n                    <Item ID=\"0x0FE6\"/>\n                    <Item ID=\"0x0FE7\"/>\n                    <Item ID=\"0x0FE8\"/>\n                    <Item ID=\"0x0FE9\"/>\n                    <Item ID=\"0x0FEA\"/>\n                    <Item ID=\"0x0FEB\"/>\n                    <Item ID=\"0x0FEC\"/>\n                    <Item ID=\"0x0FED\"/>\n                    <Item ID=\"0x0FEE\"/>\n                    <Item ID=\"0x10AC\"/>\n                    <Item ID=\"0x10AD\"/>\n                    <Item ID=\"0x10AE\"/>\n                    <Item ID=\"0x10AF\"/>\n                    <Item ID=\"0x10B0\"/>\n                    <Item ID=\"0x10B1\"/>\n                    <Item ID=\"0x120E\"/>\n                    <Item ID=\"0x120F\"/>\n                    <Item ID=\"0x1210\"/>\n                    <Item ID=\"0x1211\"/>\n                    <Item ID=\"0x1212\"/>\n                    <Item ID=\"0x1213\"/>\n                    <Item ID=\"0x1214\"/>\n                    <Item ID=\"0x1215\"/>\n                    <Item ID=\"0x1216\"/>\n                    <Item ID=\"0x1810\"/>\n                    <Item ID=\"0x1811\"/>\n                    <Item ID=\"0x1851\"/>\n                    <Item ID=\"0x1852\"/>\n                    <Item ID=\"0x1865\"/>\n                    <Item ID=\"0x1866\"/>\n                    <Item ID=\"0x19BB\"/>\n                    <Item ID=\"0x1C12\"/>\n                    <Item ID=\"0x1C14\"/>\n                    <Item ID=\"0x1C16\"/>\n                    <Item ID=\"0x1E5c\"/>\n                    <Item ID=\"0x1E5d\"/>\n                    <Item ID=\"0x1d97\"/>\n                    <Item ID=\"0x1d98\"/>\n                    <Item ID=\"0x1ecd\"/>\n                    <Item ID=\"0x1ed0\"/>\n                    <Item ID=\"0x2A7B\"/>\n                    <Item ID=\"0x2A7C\"/>\n                    <Item ID=\"0x2A7D\"/>\n                    <Item ID=\"0x2A7E\"/>\n                    <Item ID=\"0x2A9A\"/>\n                    <Item ID=\"0x2A9C\"/>\n                    <Item ID=\"0x2A9D\"/>\n                    <Item ID=\"0x2A9b\"/>\n                    <Item ID=\"0x2AB8\"/>\n                    <Item ID=\"0x2DD3\"/>\n                    <Item ID=\"0x2DD4\"/>\n                    <Item ID=\"0x2db0\"/>\n                    <Item ID=\"0x2db0\"/>\n                    <Item ID=\"0x2f57\"/>\n                    <Item ID=\"0x2f5c\"/>\n                    <Item ID=\"0x2f5d\"/>\n                    <Item ID=\"0x2f5f\"/>\n                    <Item ID=\"0x2f61\"/>\n                    <Item ID=\"0x3077\"/>\n                    <Item ID=\"0x3078\"/>\n                    <Item ID=\"0x3079\"/>\n                    <Item ID=\"0x307a\"/>\n                </Group>\n            </Group>\n            <Group name=\"Baking\">\n                <Item ID=\"0x09E9\"/>\n                <Item ID=\"0x09EA\"/>\n                <Item ID=\"0x09EB\"/>\n                <Item ID=\"0x09FA\"/>\n                <Item ID=\"0x0A1E\"/>\n                <Item ID=\"0x1039\"/>\n                <Item ID=\"0x103D\"/>\n                <Item ID=\"0x103E\"/>\n                <Item ID=\"0x103F\"/>\n                <Item ID=\"0x103a\"/>\n                <Item ID=\"0x1040\"/>\n                <Item ID=\"0x1041\"/>\n                <Item ID=\"0x1042\"/>\n                <Item ID=\"0x1043\"/>\n                <Item ID=\"0x1045\"/>\n                <Item ID=\"0x1046\"/>\n                <Item ID=\"0x1083\"/>\n                <Item ID=\"0x1449\"/>\n                <Item ID=\"0x14E9\"/>\n                <Item ID=\"0x14EA\"/>\n                <Item ID=\"0x14ff\"/>\n                <Item ID=\"0x187e\"/>\n                <Item ID=\"0x187f\"/>\n                <Item ID=\"0x1880\"/>\n                <Item ID=\"0x1881\"/>\n                <Item ID=\"0x1882\"/>\n                <Item ID=\"0x1883\"/>\n                <Item ID=\"0x1884\"/>\n                <Item ID=\"0x1885\"/>\n                <Item ID=\"0x1886\"/>\n                <Item ID=\"0x1887\"/>\n                <Item ID=\"0x1888\"/>\n                <Item ID=\"0x1889\"/>\n                <Item ID=\"0x188a\"/>\n                <Item ID=\"0x188b\"/>\n                <Item ID=\"0x1893\"/>\n                <Item ID=\"0x1920\"/>\n                <Item ID=\"0x1921\"/>\n                <Item ID=\"0x1922\"/>\n                <Item ID=\"0x1923\"/>\n                <Item ID=\"0x1924\"/>\n                <Item ID=\"0x192C\"/>\n                <Item ID=\"0x192D\"/>\n                <Item ID=\"0x192E\"/>\n                <Item ID=\"0x192F\"/>\n                <Item ID=\"0x1930\"/>\n            </Group>\n            <Group name=\"Carpenter\">\n                <Item ID=\"0x0C39\"/>\n                <Item ID=\"0x0C3A\"/>\n                <Item ID=\"0x1028\"/>\n                <Item ID=\"0x1029\"/>\n                <Item ID=\"0x102A\"/>\n                <Item ID=\"0x102B\"/>\n                <Item ID=\"0x102C\"/>\n                <Item ID=\"0x102D\"/>\n                <Item ID=\"0x102E\"/>\n                <Item ID=\"0x102F\"/>\n                <Item ID=\"0x1030\"/>\n                <Item ID=\"0x1031\"/>\n                <Item ID=\"0x1032\"/>\n                <Item ID=\"0x1033\"/>\n                <Item ID=\"0x1034\"/>\n                <Item ID=\"0x1035\"/>\n                <Item ID=\"0x1038\"/>\n                <Item ID=\"0x10E1\"/>\n                <Item ID=\"0x10E2\"/>\n                <Item ID=\"0x10E4\"/>\n                <Item ID=\"0x10E5\"/>\n                <Item ID=\"0x10E6\"/>\n                <Item ID=\"0x10E7\"/>\n                <Item ID=\"0x10E8\"/>\n                <Item ID=\"0x10E9\"/>\n                <Item ID=\"0x12B3\"/>\n                <Item ID=\"0x19F1\"/>\n                <Item ID=\"0x19F2\"/>\n                <Item ID=\"0x19F3\"/>\n                <Item ID=\"0x19F4\"/>\n                <Item ID=\"0x19F5\"/>\n                <Item ID=\"0x19F6\"/>\n                <Item ID=\"0x19F7\"/>\n                <Item ID=\"0x19F8\"/>\n                <Item ID=\"0x19F9\"/>\n                <Item ID=\"0x19FA\"/>\n                <Item ID=\"0x19FB\"/>\n                <Item ID=\"0x19FC\"/>\n                <Item ID=\"0x1BD8\"/>\n                <Item ID=\"0x1BD9\"/>\n                <Item ID=\"0x1BDB\"/>\n                <Item ID=\"0x1BDC\"/>\n                <Item ID=\"0x1BDE\"/>\n                <Item ID=\"0x1BDF\"/>\n                <Item ID=\"0x1BE1\"/>\n                <Item ID=\"0x1BE2\"/>\n                <Item ID=\"0x1E6E\"/>\n                <Item ID=\"0x1E6F\"/>\n                <Item ID=\"0x1E70\"/>\n                <Item ID=\"0x1E71\"/>\n                <Item ID=\"0x1E72\"/>\n                <Item ID=\"0x1E73\"/>\n                <Item ID=\"0x1E74\"/>\n                <Item ID=\"0x1E75\"/>\n                <Item ID=\"0x1E76\"/>\n                <Item ID=\"0x1E77\"/>\n                <Item ID=\"0x1E78\"/>\n                <Item ID=\"0x1E79\"/>\n                <Item ID=\"0x1E7A\"/>\n                <Item ID=\"0x1E7B\"/>\n                <Item ID=\"0x1E7C\"/>\n                <Item ID=\"0x1E7D\"/>\n                <Item ID=\"0x1E7E\"/>\n                <Item ID=\"0x1E7F\"/>\n                <Item ID=\"0x1E80\"/>\n                <Item ID=\"0x1E81\"/>\n                <Item ID=\"0x1E82\"/>\n                <Item ID=\"0x1EB1\"/>\n                <Item ID=\"0x1EB2\"/>\n                <Item ID=\"0x1EB3\"/>\n                <Item ID=\"0x1EB4\"/>\n                <Item ID=\"0x1EB5\"/>\n                <Item ID=\"0x1EB6\"/>\n                <Item ID=\"0x1EB7\"/>\n                <Item ID=\"0x1EB8\"/>\n                <Item ID=\"0x1EB9\"/>\n                <Item ID=\"0x1EBA\"/>\n                <Item ID=\"0x1EBB\"/>\n                <Item ID=\"0x1EBC\"/>\n                <Item ID=\"0x1db3\"/>\n                <Item ID=\"0x1db4\"/>\n                <Item ID=\"0x1db5\"/>\n                <Item ID=\"0x1db6\"/>\n                <Item ID=\"0x1db7\"/>\n                <Item ID=\"0x1db8\"/>\n            </Group>\n            <Group name=\"Cooking\">\n                <Item ID=\"0x0970\"/>\n                <Item ID=\"0x0974\"/>\n                <Item ID=\"0x0975\"/>\n                <Item ID=\"0x097F\"/>\n                <Item ID=\"0x0991\"/>\n                <Item ID=\"0x0992\"/>\n                <Item ID=\"0x09DC\"/>\n                <Item ID=\"0x09DD\"/>\n                <Item ID=\"0x09DE\"/>\n                <Item ID=\"0x09DF\"/>\n                <Item ID=\"0x09E0\"/>\n                <Item ID=\"0x09E1\"/>\n                <Item ID=\"0x09E2\"/>\n                <Item ID=\"0x09E3\"/>\n                <Item ID=\"0x09E4\"/>\n                <Item ID=\"0x09E5\"/>\n                <Item ID=\"0x09E6\"/>\n                <Item ID=\"0x09E7\"/>\n                <Item ID=\"0x09E8\"/>\n                <Item ID=\"0x09ED\"/>\n                <Item ID=\"0x09F3\"/>\n                <Item ID=\"0x1039\"/>\n                <Item ID=\"0x103D\"/>\n                <Item ID=\"0x103E\"/>\n                <Item ID=\"0x103F\"/>\n                <Item ID=\"0x103a\"/>\n                <Item ID=\"0x1040\"/>\n                <Item ID=\"0x1041\"/>\n                <Item ID=\"0x1042\"/>\n                <Item ID=\"0x1043\"/>\n                <Item ID=\"0x1045\"/>\n                <Item ID=\"0x1046\"/>\n                <Item ID=\"0x1083\"/>\n                <Item ID=\"0x10E7\"/>\n                <Item ID=\"0x10E8\"/>\n                <Item ID=\"0x10E9\"/>\n                <Item ID=\"0x10Ee\"/>\n                <Item ID=\"0x10Ef\"/>\n                <Item ID=\"0x10f0\"/>\n                <Item ID=\"0x10f1\"/>\n                <Item ID=\"0x10f2\"/>\n                <Item ID=\"0x10f3\"/>\n                <Item ID=\"0x1449\"/>\n                <Item ID=\"0x14ff\"/>\n                <Item ID=\"0x1865\"/>\n                <Item ID=\"0x1866\"/>\n                <Item ID=\"0x1871\"/>\n                <Item ID=\"0x1872\"/>\n                <Item ID=\"0x1873\"/>\n                <Item ID=\"0x1874\"/>\n                <Item ID=\"0x18E3\"/>\n                <Item ID=\"0x18E4\"/>\n                <Item ID=\"0x1AA2\"/>\n                <Item ID=\"0x1E15\"/>\n                <Item ID=\"0x1E16\"/>\n                <Item ID=\"0x1E17\"/>\n                <Item ID=\"0x1E18\"/>\n                <Item ID=\"0x1E19\"/>\n                <Item ID=\"0x1E1A\"/>\n                <Item ID=\"0x1E1B\"/>\n                <Item ID=\"0x1E1C\"/>\n                <Item ID=\"0x1E1D\"/>\n                <Item ID=\"0x1E1E\"/>\n                <Item ID=\"0x1E1F\"/>\n                <Item ID=\"0x1E83\"/>\n                <Item ID=\"0x1E84\"/>\n                <Item ID=\"0x1E85\"/>\n                <Item ID=\"0x1E86\"/>\n                <Item ID=\"0x1E87\"/>\n                <Item ID=\"0x1E88\"/>\n                <Item ID=\"0x1E89\"/>\n                <Item ID=\"0x1E8A\"/>\n                <Item ID=\"0x1E8B\"/>\n                <Item ID=\"0x1E8C\"/>\n                <Item ID=\"0x1E8D\"/>\n                <Item ID=\"0x1E8E\"/>\n                <Item ID=\"0x1E8F\"/>\n                <Item ID=\"0x1E90\"/>\n                <Item ID=\"0x1E91\"/>\n                <Item ID=\"0x1E92\"/>\n                <Item ID=\"0x1E93\"/>\n                <Item ID=\"0x1E94\"/>\n                <Item ID=\"0x1E95\"/>\n                <Item ID=\"0x1E96\"/>\n                <Item ID=\"0x1E97\"/>\n                <Item ID=\"0x1E98\"/>\n                <Item ID=\"0x1E99\"/>\n                <Item ID=\"0x1Eb0\"/>\n                <Item ID=\"0x207a\"/>\n                <Item ID=\"0x207b\"/>\n                <Item ID=\"0x3daf\"/>\n                <Item ID=\"0x3db0\"/>\n                <Item ID=\"0x3db1\"/>\n                <Item ID=\"0x3db8\"/>\n                <Item ID=\"0x3db9\"/>\n                <Item ID=\"0x3dba\"/>\n                <Item ID=\"0x3dbb\"/>\n            </Group>\n            <Group name=\"Farming\">\n                <Group name=\"Plants\">\n                    <Item ID=\"0x02DB\"/>\n                    <Item ID=\"0x0C4f\"/>\n                    <Item ID=\"0x0C50\"/>\n                    <Item ID=\"0x0C51\"/>\n                    <Item ID=\"0x0C52\"/>\n                    <Item ID=\"0x0C53\"/>\n                    <Item ID=\"0x0C54\"/>\n                    <Item ID=\"0x0C55\"/>\n                    <Item ID=\"0x0C56\"/>\n                    <Item ID=\"0x0C57\"/>\n                    <Item ID=\"0x0C58\"/>\n                    <Item ID=\"0x0C59\"/>\n                    <Item ID=\"0x0C5C\"/>\n                    <Item ID=\"0x0C5a\"/>\n                    <Item ID=\"0x0C5b\"/>\n                    <Item ID=\"0x0C5d\"/>\n                    <Item ID=\"0x0C5e\"/>\n                    <Item ID=\"0x0C5f\"/>\n                    <Item ID=\"0x0C60\"/>\n                    <Item ID=\"0x0C61\"/>\n                    <Item ID=\"0x0C62\"/>\n                    <Item ID=\"0x0C63\"/>\n                    <Item ID=\"0x0C64\"/>\n                    <Item ID=\"0x0C65\"/>\n                    <Item ID=\"0x0C66\"/>\n                    <Item ID=\"0x0C67\"/>\n                    <Item ID=\"0x0C68\"/>\n                    <Item ID=\"0x0C69\"/>\n                    <Item ID=\"0x0C6a\"/>\n                    <Item ID=\"0x0C6b\"/>\n                    <Item ID=\"0x0C6c\"/>\n                    <Item ID=\"0x0C6f\"/>\n                    <Item ID=\"0x0C70\"/>\n                    <Item ID=\"0x0C71\"/>\n                    <Item ID=\"0x0C72\"/>\n                    <Item ID=\"0x0C73\"/>\n                    <Item ID=\"0x0C74\"/>\n                    <Item ID=\"0x0C75\"/>\n                    <Item ID=\"0x0C76\"/>\n                    <Item ID=\"0x0C79\"/>\n                    <Item ID=\"0x0C7a\"/>\n                    <Item ID=\"0x0C7b\"/>\n                    <Item ID=\"0x0C7c\"/>\n                    <Item ID=\"0x0C7d\"/>\n                    <Item ID=\"0x0C7e\"/>\n                    <Item ID=\"0x0D1A\"/>\n                    <Item ID=\"0x0D1B\"/>\n                    <Item ID=\"0x0D1C\"/>\n                    <Item ID=\"0x0D1D\"/>\n                    <Item ID=\"0x0D1E\"/>\n                    <Item ID=\"0x0D1F\"/>\n                    <Item ID=\"0x0D20\"/>\n                    <Item ID=\"0x0D21\"/>\n                    <Item ID=\"0x0D22\"/>\n                    <Item ID=\"0x0D23\"/>\n                    <Item ID=\"0x0D24\"/>\n                    <Item ID=\"0x0DAE\"/>\n                    <Item ID=\"0x0DAF\"/>\n                    <Item ID=\"0x0DEb\"/>\n                    <Item ID=\"0x0DEc\"/>\n                    <Item ID=\"0x0DEd\"/>\n                    <Item ID=\"0x0DEe\"/>\n                    <Item ID=\"0x1449\"/>\n                    <Item ID=\"0x1A99\"/>\n                    <Item ID=\"0x1A9A\"/>\n                    <Item ID=\"0x1A9B\"/>\n                    <Item ID=\"0x1A9E\"/>\n                    <Item ID=\"0x1A9F\"/>\n                    <Item ID=\"0x1AA0\"/>\n                    <Item ID=\"0x1AA1\"/>\n                    <Item ID=\"0x1AA2\"/>\n                    <Item ID=\"0x1Ebd\"/>\n                    <Item ID=\"0x1Ebe\"/>\n                    <Item ID=\"0x1Ebf\"/>\n                    <Item ID=\"0x3d12\"/>\n                    <Item ID=\"0x3d17\"/>\n                    <Item ID=\"0x3d18\"/>\n                    <Item ID=\"0x3d19\"/>\n                    <Item ID=\"0x3d1a\"/>\n                    <Item ID=\"0x3d1b\"/>\n                    <Item ID=\"0x3d1c\"/>\n                </Group>\n                <Group name=\"Tools\">\n                    <Item ID=\"0x1500\"/>\n                    <Item ID=\"0x1501\"/>\n                    <Item ID=\"0x1502\"/>\n                    <Item ID=\"0x1503\"/>\n                    <Item ID=\"0x1504\"/>\n                    <Item ID=\"0x1505\"/>\n                    <Item ID=\"0x1506\"/>\n                    <Item ID=\"0x1507\"/>\n                    <Item ID=\"0x1E34\"/>\n                    <Item ID=\"0x1E35\"/>\n                </Group>\n            </Group>\n            <Group name=\"Fisher + Sailor\">\n                <Item ID=\"0x020D\"/>\n                <Item ID=\"0x0DBF\"/>\n                <Item ID=\"0x0DC0\"/>\n                <Item ID=\"0x0DC8\"/>\n                <Item ID=\"0x0DC9\"/>\n                <Item ID=\"0x0DCA\"/>\n                <Item ID=\"0x0DCA\"/>\n                <Item ID=\"0x0DCB\"/>\n                <Item ID=\"0x0DCC\"/>\n                <Item ID=\"0x0DCD\"/>\n                <Item ID=\"0x0DCE\"/>\n                <Item ID=\"0x0DCF\"/>\n                <Item ID=\"0x0DD0\"/>\n                <Item ID=\"0x0DD1\"/>\n                <Item ID=\"0x0DD2\"/>\n                <Item ID=\"0x0DD3\"/>\n                <Item ID=\"0x0DD4\"/>\n                <Item ID=\"0x0DD5\"/>\n                <Item ID=\"0x0DD6\"/>\n                <Item ID=\"0x0DD6\"/>\n                <Item ID=\"0x0DD7\"/>\n                <Item ID=\"0x0DD7\"/>\n                <Item ID=\"0x0DD8\"/>\n                <Item ID=\"0x0DD8\"/>\n                <Item ID=\"0x0DD9\"/>\n                <Item ID=\"0x0DD9\"/>\n                <Item ID=\"0x0FC4\"/>\n                <Item ID=\"0x0FC5\"/>\n                <Item ID=\"0x0FC6\"/>\n                <Item ID=\"0x0FC7\"/>\n                <Item ID=\"0x0FC8\"/>\n                <Item ID=\"0x0FC9\"/>\n                <Item ID=\"0x0FCA\"/>\n                <Item ID=\"0x0FCB\"/>\n                <Item ID=\"0x0FCC\"/>\n                <Item ID=\"0x0FCD\"/>\n                <Item ID=\"0x0FCE\"/>\n                <Item ID=\"0x0FCF\"/>\n                <Item ID=\"0x0FD0\"/>\n                <Item ID=\"0x0FD1\"/>\n                <Item ID=\"0x0FD2\"/>\n                <Item ID=\"0x0FD3\"/>\n                <Item ID=\"0x0FD4\"/>\n                <Item ID=\"0x1047\"/>\n                <Item ID=\"0x1048\"/>\n                <Item ID=\"0x14EB\"/>\n                <Item ID=\"0x14EC\"/>\n                <Item ID=\"0x14ED\"/>\n                <Item ID=\"0x14EE\"/>\n                <Item ID=\"0x14F1\"/>\n                <Item ID=\"0x14F2\"/>\n                <Item ID=\"0x14F3\"/>\n                <Item ID=\"0x14F4\"/>\n                <Item ID=\"0x14F5\"/>\n                <Item ID=\"0x14F6\"/>\n                <Item ID=\"0x1E26\"/>\n                <Item ID=\"0x1E27\"/>\n                <Item ID=\"0x1E28\"/>\n                <Item ID=\"0x1E29\"/>\n                <Item ID=\"0x1E2A\"/>\n                <Item ID=\"0x1E2B\"/>\n                <Item ID=\"0x1E9A\"/>\n                <Item ID=\"0x1E9B\"/>\n                <Item ID=\"0x1E9C\"/>\n                <Item ID=\"0x1E9D\"/>\n                <Item ID=\"0x1E9E\"/>\n                <Item ID=\"0x1E9F\"/>\n                <Item ID=\"0x1EA0\"/>\n                <Item ID=\"0x1EA1\"/>\n                <Item ID=\"0x1EA2\"/>\n                <Item ID=\"0x1EA3\"/>\n                <Item ID=\"0x1EA4\"/>\n                <Item ID=\"0x1EA5\"/>\n                <Item ID=\"0x1EA6\"/>\n                <Item ID=\"0x2003\"/>\n                <Item ID=\"0x2710\"/>\n                <Item ID=\"0x2711\"/>\n                <Item ID=\"0x3d8e\"/>\n                <Item ID=\"0x3d8f\"/>\n            </Group>\n            <Group name=\"Fletcher\">\n                <Item ID=\"0x0DFA\"/>\n                <Item ID=\"0x0DFB\"/>\n                <Item ID=\"0x0fc2\"/>\n                <Item ID=\"0x1020\"/>\n                <Item ID=\"0x1021\"/>\n                <Item ID=\"0x1022\"/>\n                <Item ID=\"0x1023\"/>\n                <Item ID=\"0x1024\"/>\n                <Item ID=\"0x1025\"/>\n                <Item ID=\"0x1BD1\"/>\n                <Item ID=\"0x1BD2\"/>\n                <Item ID=\"0x1BD3\"/>\n                <Item ID=\"0x1BD4\"/>\n                <Item ID=\"0x1BD5\"/>\n                <Item ID=\"0x1BD6\"/>\n                <Item ID=\"0x1BD8\"/>\n                <Item ID=\"0x1BD9\"/>\n                <Item ID=\"0x1BDB\"/>\n                <Item ID=\"0x1BDC\"/>\n                <Item ID=\"0x1BDE\"/>\n                <Item ID=\"0x1BDF\"/>\n                <Item ID=\"0x1BE1\"/>\n                <Item ID=\"0x1BE2\"/>\n                <Item ID=\"0x1BFB\"/>\n                <Item ID=\"0x1BFC\"/>\n                <Item ID=\"0x1BFD\"/>\n                <Item ID=\"0x1BFE\"/>\n                <Item ID=\"0x2DD7\"/>\n            </Group>\n            <Group name=\"Hairdressing\">\n                <Item ID=\"0x0DFC\"/>\n                <Item ID=\"0x0DFD\"/>\n                <Item ID=\"0x0DFE\"/>\n                <Item ID=\"0x0DFF\"/>\n                <Item ID=\"0x0E00\"/>\n                <Item ID=\"0x0E01\"/>\n                <Item ID=\"0x0E02\"/>\n                <Item ID=\"0x0E03\"/>\n                <Item ID=\"0x0E04\"/>\n                <Item ID=\"0x0E05\"/>\n                <Item ID=\"0x0E06\"/>\n                <Item ID=\"0x0E07\"/>\n                <Item ID=\"0x0E08\"/>\n                <Item ID=\"0x0E09\"/>\n                <Item ID=\"0x0E0A\"/>\n                <Item ID=\"0x0E0B\"/>\n                <Item ID=\"0x0E0C\"/>\n                <Item ID=\"0x0E0D\"/>\n                <Item ID=\"0x0E0E\"/>\n            </Group>\n            <Group name=\"Healer\">\n                <Item ID=\"0x0002\"/>\n                <Item ID=\"0x0003\"/>\n                <Item ID=\"0x0004\"/>\n                <Item ID=\"0x0005\"/>\n                <Item ID=\"0x0C3B\"/>\n                <Item ID=\"0x0C3C\"/>\n                <Item ID=\"0x0C3D\"/>\n                <Item ID=\"0x0C3E\"/>\n                <Item ID=\"0x0C3F\"/>\n                <Item ID=\"0x0C40\"/>\n                <Item ID=\"0x0C41\"/>\n                <Item ID=\"0x0C42\"/>\n                <Item ID=\"0x0E20\"/>\n                <Item ID=\"0x0E21\"/>\n                <Item ID=\"0x0E22\"/>\n                <Item ID=\"0x0E23\"/>\n                <Item ID=\"0x0E30\"/>\n                <Item ID=\"0x0E31\"/>\n                <Item ID=\"0x0Ee9\"/>\n                <Item ID=\"0x1008\"/>\n                <Item ID=\"0x1009\"/>\n                <Item ID=\"0x10AC\"/>\n                <Item ID=\"0x10AD\"/>\n                <Item ID=\"0x10AE\"/>\n                <Item ID=\"0x10AF\"/>\n                <Item ID=\"0x10B0\"/>\n                <Item ID=\"0x10B1\"/>\n                <Item ID=\"0x19BB\"/>\n                <Item ID=\"0x312D\"/>\n                <Item ID=\"0x312E\"/>\n                <Item ID=\"0x312F\"/>\n                <Item ID=\"0x3130\"/>\n            </Group>\n            <Group name=\"Jeweler\">\n                <Group name=\"Resources\">\n                    <Item ID=\"0x0F0F\"/>\n                    <Item ID=\"0x0F10\"/>\n                    <Item ID=\"0x0F11\"/>\n                    <Item ID=\"0x0F12\"/>\n                    <Item ID=\"0x0F13\"/>\n                    <Item ID=\"0x0F14\"/>\n                    <Item ID=\"0x0F15\"/>\n                    <Item ID=\"0x0F16\"/>\n                    <Item ID=\"0x0F17\"/>\n                    <Item ID=\"0x0F18\"/>\n                    <Item ID=\"0x0F19\"/>\n                    <Item ID=\"0x0F1A\"/>\n                    <Item ID=\"0x0F1B\"/>\n                    <Item ID=\"0x0F1C\"/>\n                    <Item ID=\"0x0F1D\"/>\n                    <Item ID=\"0x0F1E\"/>\n                    <Item ID=\"0x0F1F\"/>\n                    <Item ID=\"0x0F20\"/>\n                    <Item ID=\"0x0F21\"/>\n                    <Item ID=\"0x0F22\"/>\n                    <Item ID=\"0x0F23\"/>\n                    <Item ID=\"0x0F24\"/>\n                    <Item ID=\"0x0F25\"/>\n                    <Item ID=\"0x0F26\"/>\n                    <Item ID=\"0x0F27\"/>\n                    <Item ID=\"0x0F28\"/>\n                    <Item ID=\"0x0F29\"/>\n                    <Item ID=\"0x0F2A\"/>\n                    <Item ID=\"0x0F2B\"/>\n                    <Item ID=\"0x0F2C\"/>\n                    <Item ID=\"0x0F2D\"/>\n                    <Item ID=\"0x0F2E\"/>\n                    <Item ID=\"0x0F2F\"/>\n                    <Item ID=\"0x0F30\"/>\n                    <Item ID=\"0x1876\"/>\n                    <Item ID=\"0x1877\"/>\n                    <Item ID=\"0x1878\"/>\n                    <Item ID=\"0x1879\"/>\n                    <Item ID=\"0x1BE3\"/>\n                    <Item ID=\"0x1BE4\"/>\n                    <Item ID=\"0x1BE5\"/>\n                    <Item ID=\"0x1BE6\"/>\n                    <Item ID=\"0x1BE7\"/>\n                    <Item ID=\"0x1BE8\"/>\n                    <Item ID=\"0x1BE9\"/>\n                    <Item ID=\"0x1BEA\"/>\n                    <Item ID=\"0x1BEB\"/>\n                    <Item ID=\"0x1BEC\"/>\n                    <Item ID=\"0x1BED\"/>\n                    <Item ID=\"0x1BEE\"/>\n                    <Item ID=\"0x1BEF\"/>\n                    <Item ID=\"0x1BF0\"/>\n                    <Item ID=\"0x1BF1\"/>\n                    <Item ID=\"0x1BF2\"/>\n                    <Item ID=\"0x1BF3\"/>\n                    <Item ID=\"0x1BF4\"/>\n                    <Item ID=\"0x1BF5\"/>\n                    <Item ID=\"0x1BF6\"/>\n                    <Item ID=\"0x1BF7\"/>\n                    <Item ID=\"0x1BF8\"/>\n                    <Item ID=\"0x1BF9\"/>\n                    <Item ID=\"0x1BFA\"/>\n                    <Item ID=\"0x3192\"/>\n                    <Item ID=\"0x3193\"/>\n                    <Item ID=\"0x3194\"/>\n                    <Item ID=\"0x3195\"/>\n                    <Item ID=\"0x3196\"/>\n                    <Item ID=\"0x3197\"/>\n                    <Item ID=\"0x3198\"/>\n                    <Item ID=\"0x3199\"/>\n                </Group>\n                <Item ID=\"0x0FBB\"/>\n                <Item ID=\"0x0FBC\"/>\n                <Item ID=\"0x102A\"/>\n                <Item ID=\"0x102B\"/>\n                <Item ID=\"0x1085\"/>\n                <Item ID=\"0x1086\"/>\n                <Item ID=\"0x1087\"/>\n                <Item ID=\"0x1088\"/>\n                <Item ID=\"0x1089\"/>\n                <Item ID=\"0x108a\"/>\n                <Item ID=\"0x108b\"/>\n                <Item ID=\"0x1f05\"/>\n                <Item ID=\"0x1f06\"/>\n                <Item ID=\"0x1f07\"/>\n                <Item ID=\"0x1f08\"/>\n                <Item ID=\"0x1f09\"/>\n                <Item ID=\"0x1f0a\"/>\n                <Item ID=\"0x3BB5\"/>\n            </Group>\n            <Group name=\"Lock picking + Traps\">\n                <Item ID=\"0x108c\"/>\n                <Item ID=\"0x108f\"/>\n                <Item ID=\"0x1092\"/>\n                <Item ID=\"0x1093\"/>\n                <Item ID=\"0x10F5\"/>\n                <Item ID=\"0x10F6\"/>\n                <Item ID=\"0x10Fc\"/>\n                <Item ID=\"0x10fd\"/>\n                <Item ID=\"0x1103\"/>\n                <Item ID=\"0x1104\"/>\n                <Item ID=\"0x1108\"/>\n                <Item ID=\"0x1109\"/>\n                <Item ID=\"0x110f\"/>\n                <Item ID=\"0x1110\"/>\n                <Item ID=\"0x1116\"/>\n                <Item ID=\"0x1117\"/>\n                <Item ID=\"0x111b\"/>\n                <Item ID=\"0x111c\"/>\n                <Item ID=\"0x1122\"/>\n                <Item ID=\"0x1123\"/>\n                <Item ID=\"0x1125\"/>\n                <Item ID=\"0x1126\"/>\n                <Item ID=\"0x112b\"/>\n                <Item ID=\"0x112c\"/>\n                <Item ID=\"0x112f\"/>\n                <Item ID=\"0x1130\"/>\n                <Item ID=\"0x1133\"/>\n                <Item ID=\"0x1134\"/>\n                <Item ID=\"0x113a\"/>\n                <Item ID=\"0x1140\"/>\n                <Item ID=\"0x1141\"/>\n                <Item ID=\"0x1145\"/>\n                <Item ID=\"0x1146\"/>\n                <Item ID=\"0x114b\"/>\n                <Item ID=\"0x114c\"/>\n                <Item ID=\"0x1193\"/>\n                <Item ID=\"0x1194\"/>\n                <Item ID=\"0x119a\"/>\n                <Item ID=\"0x119b\"/>\n                <Item ID=\"0x11a0\"/>\n                <Item ID=\"0x11a1\"/>\n                <Item ID=\"0x11a6\"/>\n                <Item ID=\"0x11a7\"/>\n                <Item ID=\"0x11ac\"/>\n                <Item ID=\"0x11ad\"/>\n                <Item ID=\"0x11b1\"/>\n                <Item ID=\"0x11b2\"/>\n                <Item ID=\"0x11b6\"/>\n                <Item ID=\"0x11b7\"/>\n                <Item ID=\"0x11c0\"/>\n                <Item ID=\"0x11c1\"/>\n                <Item ID=\"0x14FB\"/>\n                <Item ID=\"0x14FC\"/>\n                <Item ID=\"0x14FD\"/>\n                <Item ID=\"0x14FE\"/>\n                <Item ID=\"0x1508\"/>\n                <Item ID=\"0x1509\"/>\n                <Item ID=\"0x1512\"/>\n                <Item ID=\"0x1513\"/>\n                <Item ID=\"0x151A\"/>\n                <Item ID=\"0x151B\"/>\n                <Item ID=\"0x151C\"/>\n                <Item ID=\"0x151D\"/>\n                <Item ID=\"0x1B8f\"/>\n                <Item ID=\"0x1Bc0\"/>\n                <Item ID=\"0x1Bc1\"/>\n                <Item ID=\"0x1d99\"/>\n                <Item ID=\"0x1d9a\"/>\n                <Item ID=\"0x1ed3\"/>\n                <Item ID=\"0x1ed6\"/>\n                <Item ID=\"0x37a0\"/>\n            </Group>\n            <Group name=\"Massage\">\n                <Item ID=\"0x1914\"/>\n                <Item ID=\"0x1915\"/>\n                <Item ID=\"0x1916\"/>\n                <Item ID=\"0x1917\"/>\n            </Group>\n            <Group name=\"Metalwork\">\n                <Item ID=\"0x0FAF\"/>\n                <Item ID=\"0x0FB0\"/>\n                <Item ID=\"0x0FB1\"/>\n                <Item ID=\"0x0FB4\"/>\n                <Item ID=\"0x0FB5\"/>\n                <Item ID=\"0x0FB7\"/>\n                <Item ID=\"0x0FB8\"/>\n                <Item ID=\"0x0FBB\"/>\n                <Item ID=\"0x0FBC\"/>\n                <Item ID=\"0x100e\"/>\n                <Item ID=\"0x100f\"/>\n                <Item ID=\"0x1010\"/>\n                <Item ID=\"0x1011\"/>\n                <Item ID=\"0x1012\"/>\n                <Item ID=\"0x1013\"/>\n                <Item ID=\"0x10E1\"/>\n                <Item ID=\"0x10E2\"/>\n                <Item ID=\"0x1769\"/>\n                <Item ID=\"0x176a\"/>\n                <Item ID=\"0x176b\"/>\n                <Item ID=\"0x1876\"/>\n                <Item ID=\"0x1877\"/>\n                <Item ID=\"0x1878\"/>\n                <Item ID=\"0x1879\"/>\n                <Item ID=\"0x197A\"/>\n                <Item ID=\"0x197E\"/>\n                <Item ID=\"0x1982\"/>\n                <Item ID=\"0x1986\"/>\n                <Item ID=\"0x198A\"/>\n                <Item ID=\"0x198E\"/>\n                <Item ID=\"0x1992\"/>\n                <Item ID=\"0x1996\"/>\n                <Item ID=\"0x199A\"/>\n                <Item ID=\"0x199E\"/>\n                <Item ID=\"0x19A2\"/>\n                <Item ID=\"0x19A6\"/>\n                <Item ID=\"0x19B7\"/>\n                <Item ID=\"0x19B8\"/>\n                <Item ID=\"0x19B9\"/>\n                <Item ID=\"0x19BA\"/>\n                <Item ID=\"0x1A82\"/>\n                <Item ID=\"0x1A83\"/>\n                <Item ID=\"0x1A86\"/>\n                <Item ID=\"0x1A87\"/>\n                <Item ID=\"0x1A88\"/>\n                <Item ID=\"0x1A8B\"/>\n                <Item ID=\"0x1BE3\"/>\n                <Item ID=\"0x1BE4\"/>\n                <Item ID=\"0x1BE5\"/>\n                <Item ID=\"0x1BE6\"/>\n                <Item ID=\"0x1BE7\"/>\n                <Item ID=\"0x1BE8\"/>\n                <Item ID=\"0x1BE9\"/>\n                <Item ID=\"0x1BEA\"/>\n                <Item ID=\"0x1BEB\"/>\n                <Item ID=\"0x1BEC\"/>\n                <Item ID=\"0x1BED\"/>\n                <Item ID=\"0x1BEE\"/>\n                <Item ID=\"0x1BEF\"/>\n                <Item ID=\"0x1BF0\"/>\n                <Item ID=\"0x1BF1\"/>\n                <Item ID=\"0x1BF2\"/>\n                <Item ID=\"0x1BF3\"/>\n                <Item ID=\"0x1BF4\"/>\n                <Item ID=\"0x1BF5\"/>\n                <Item ID=\"0x1BF6\"/>\n                <Item ID=\"0x1BF7\"/>\n                <Item ID=\"0x1BF8\"/>\n                <Item ID=\"0x1BF9\"/>\n                <Item ID=\"0x1BFA\"/>\n                <Item ID=\"0x1db7\"/>\n                <Item ID=\"0x2DD5\"/>\n                <Item ID=\"0x2DD6\"/>\n                <Item ID=\"0x2DD8\"/>\n            </Group>\n            <Group name=\"Sculptor\">\n                <Item ID=\"0x12B1\"/>\n                <Item ID=\"0x12B2\"/>\n                <Item ID=\"0x12B3\"/>\n                <Item ID=\"0x12C8\"/>\n                <Item ID=\"0x12C9\"/>\n                <Item ID=\"0x12b0\"/>\n                <Item ID=\"0x12b1\"/>\n                <Item ID=\"0x12b2\"/>\n                <Item ID=\"0x12b3\"/>\n                <Item ID=\"0x32F0\"/>\n                <Item ID=\"0x32F2\"/>\n                <Item ID=\"0x32F8\"/>\n            </Group>\n            <Group name=\"Skill Training\">\n                <Item ID=\"0x100A\"/>\n                <Item ID=\"0x100B\"/>\n                <Item ID=\"0x1070\"/>\n                <Item ID=\"0x1074\"/>\n                <Item ID=\"0x1E2C\"/>\n                <Item ID=\"0x1E2D\"/>\n                <Item ID=\"0x1ec0\"/>\n                <Item ID=\"0x1ec3\"/>\n            </Group>\n            <Group name=\"Skinner\">\n                <Item ID=\"0x1067\"/>\n                <Item ID=\"0x1068\"/>\n                <Item ID=\"0x1069\"/>\n                <Item ID=\"0x106B\"/>\n                <Item ID=\"0x1078\"/>\n                <Item ID=\"0x1079\"/>\n                <Item ID=\"0x107A\"/>\n                <Item ID=\"0x107C\"/>\n                <Item ID=\"0x107b\"/>\n                <Item ID=\"0x107d\"/>\n                <Item ID=\"0x107e\"/>\n                <Item ID=\"0x107f\"/>\n                <Item ID=\"0x1080\"/>\n                <Item ID=\"0x1082\"/>\n                <Item ID=\"0x1082\"/>\n                <Item ID=\"0x11F4\"/>\n                <Item ID=\"0x11F5\"/>\n                <Item ID=\"0x11F6\"/>\n                <Item ID=\"0x11F7\"/>\n                <Item ID=\"0x11F8\"/>\n                <Item ID=\"0x11F8\"/>\n                <Item ID=\"0x11F9\"/>\n                <Item ID=\"0x11F9\"/>\n                <Item ID=\"0x11FA\"/>\n                <Item ID=\"0x11FB\"/>\n                <Item ID=\"0x11Fa\"/>\n                <Item ID=\"0x11Fb\"/>\n                <Item ID=\"0x1871\"/>\n                <Item ID=\"0x1872\"/>\n                <Item ID=\"0x1873\"/>\n                <Item ID=\"0x1874\"/>\n                <Item ID=\"0x1875\"/>\n                <Item ID=\"0x3d69\"/>\n                <Item ID=\"0x3d6a\"/>\n                <Item ID=\"0x3d6b\"/>\n            </Group>\n            <Group name=\"Tailoring + Clothwork\">\n                <Item ID=\"0x0DEF\"/>\n                <Item ID=\"0x0DF6\"/>\n                <Item ID=\"0x0DF7\"/>\n                <Item ID=\"0x0DF8\"/>\n                <Item ID=\"0x0DFA\"/>\n                <Item ID=\"0x0DFB\"/>\n                <Item ID=\"0x0EC6\"/>\n                <Item ID=\"0x0EC7\"/>\n                <Item ID=\"0x0F95\"/>\n                <Item ID=\"0x0F96\"/>\n                <Item ID=\"0x0F97\"/>\n                <Item ID=\"0x0F98\"/>\n                <Item ID=\"0x0F99\"/>\n                <Item ID=\"0x0F9A\"/>\n                <Item ID=\"0x0F9B\"/>\n                <Item ID=\"0x0F9C\"/>\n                <Item ID=\"0x0F9D\"/>\n                <Item ID=\"0x0F9E\"/>\n                <Item ID=\"0x0F9F\"/>\n                <Item ID=\"0x0FA0\"/>\n                <Item ID=\"0x0FA1\"/>\n                <Item ID=\"0x0FA9\"/>\n                <Item ID=\"0x0FAB\"/>\n                <Item ID=\"0x0e1d\"/>\n                <Item ID=\"0x0e1e\"/>\n                <Item ID=\"0x0e1f\"/>\n                <Item ID=\"0x1015\"/>\n                <Item ID=\"0x1019\"/>\n                <Item ID=\"0x101c\"/>\n                <Item ID=\"0x101f\"/>\n                <Item ID=\"0x105F\"/>\n                <Item ID=\"0x1060\"/>\n                <Item ID=\"0x1061\"/>\n                <Item ID=\"0x1062\"/>\n                <Item ID=\"0x10a4\"/>\n                <Item ID=\"0x1420\"/>\n                <Item ID=\"0x1421\"/>\n                <Item ID=\"0x175d\"/>\n                <Item ID=\"0x175e\"/>\n                <Item ID=\"0x175f\"/>\n                <Item ID=\"0x1760\"/>\n                <Item ID=\"0x1761\"/>\n                <Item ID=\"0x1762\"/>\n                <Item ID=\"0x1763\"/>\n                <Item ID=\"0x1764\"/>\n                <Item ID=\"0x1765\"/>\n                <Item ID=\"0x1766\"/>\n                <Item ID=\"0x1767\"/>\n                <Item ID=\"0x1768\"/>\n                <Item ID=\"0x1a9c\"/>\n                <Item ID=\"0x1a9d\"/>\n                <Item ID=\"0x2001\"/>\n                <Item ID=\"0x2DD9\"/>\n                <Item ID=\"0x2DD9\"/>\n                <Item ID=\"0x2DD9\"/>\n                <Item ID=\"0x2DDA\"/>\n                <Item ID=\"0x2e3c\"/>\n                <Item ID=\"0x2e3d\"/>\n                <Item ID=\"0x2e3e\"/>\n                <Item ID=\"0x2e3f\"/>\n            </Group>\n            <Group name=\"Tinker/Carver\">\n                <Item ID=\"0x0C39\"/>\n                <Item ID=\"0x0C3A\"/>\n                <Item ID=\"0x1026\"/>\n                <Item ID=\"0x1027\"/>\n                <Item ID=\"0x1028\"/>\n                <Item ID=\"0x1029\"/>\n                <Item ID=\"0x102A\"/>\n                <Item ID=\"0x102B\"/>\n                <Item ID=\"0x102C\"/>\n                <Item ID=\"0x102D\"/>\n                <Item ID=\"0x102E\"/>\n                <Item ID=\"0x102F\"/>\n                <Item ID=\"0x1030\"/>\n                <Item ID=\"0x1031\"/>\n                <Item ID=\"0x1032\"/>\n                <Item ID=\"0x1033\"/>\n                <Item ID=\"0x1034\"/>\n                <Item ID=\"0x1035\"/>\n                <Item ID=\"0x1038\"/>\n                <Item ID=\"0x1043\"/>\n                <Item ID=\"0x104B\"/>\n                <Item ID=\"0x104C\"/>\n                <Item ID=\"0x104D\"/>\n                <Item ID=\"0x104E\"/>\n                <Item ID=\"0x104F\"/>\n                <Item ID=\"0x1050\"/>\n                <Item ID=\"0x1051\"/>\n                <Item ID=\"0x1052\"/>\n                <Item ID=\"0x1053\"/>\n                <Item ID=\"0x1054\"/>\n                <Item ID=\"0x1055\"/>\n                <Item ID=\"0x1056\"/>\n                <Item ID=\"0x1057\"/>\n                <Item ID=\"0x1058\"/>\n                <Item ID=\"0x1059\"/>\n                <Item ID=\"0x105A\"/>\n                <Item ID=\"0x105B\"/>\n                <Item ID=\"0x105C\"/>\n                <Item ID=\"0x105D\"/>\n                <Item ID=\"0x105E\"/>\n                <Item ID=\"0x10AC\"/>\n                <Item ID=\"0x10AD\"/>\n                <Item ID=\"0x10AE\"/>\n                <Item ID=\"0x10AF\"/>\n                <Item ID=\"0x10B0\"/>\n                <Item ID=\"0x10B1\"/>\n                <Item ID=\"0x10E3\"/>\n                <Item ID=\"0x10E4\"/>\n                <Item ID=\"0x10E5\"/>\n                <Item ID=\"0x10E6\"/>\n                <Item ID=\"0x10E7\"/>\n                <Item ID=\"0x10E8\"/>\n                <Item ID=\"0x10E9\"/>\n                <Item ID=\"0x12B3\"/>\n                <Item ID=\"0x19F1\"/>\n                <Item ID=\"0x19F2\"/>\n                <Item ID=\"0x19F3\"/>\n                <Item ID=\"0x19F4\"/>\n                <Item ID=\"0x19F5\"/>\n                <Item ID=\"0x19F6\"/>\n                <Item ID=\"0x19F7\"/>\n                <Item ID=\"0x19F8\"/>\n                <Item ID=\"0x19F9\"/>\n                <Item ID=\"0x19FA\"/>\n                <Item ID=\"0x19FB\"/>\n                <Item ID=\"0x19FC\"/>\n                <Item ID=\"0x1E6E\"/>\n                <Item ID=\"0x1E77\"/>\n                <Item ID=\"0x1EA8\"/>\n                <Item ID=\"0x1EA9\"/>\n                <Item ID=\"0x1EAC\"/>\n                <Item ID=\"0x1EAb\"/>\n                <Item ID=\"0x1EB6\"/>\n                <Item ID=\"0x1EB7\"/>\n                <Item ID=\"0x1EB8\"/>\n                <Item ID=\"0x1EB9\"/>\n                <Item ID=\"0x1EBA\"/>\n                <Item ID=\"0x1EBB\"/>\n                <Item ID=\"0x1EBC\"/>\n            </Group>\n            <Group name=\"Treasure + Trade\">\n                <Item ID=\"0x0F0F\"/>\n                <Item ID=\"0x0F10\"/>\n                <Item ID=\"0x0F11\"/>\n                <Item ID=\"0x0F12\"/>\n                <Item ID=\"0x0F13\"/>\n                <Item ID=\"0x0F14\"/>\n                <Item ID=\"0x0F15\"/>\n                <Item ID=\"0x0F16\"/>\n                <Item ID=\"0x0F17\"/>\n                <Item ID=\"0x0F18\"/>\n                <Item ID=\"0x0F19\"/>\n                <Item ID=\"0x0F1A\"/>\n                <Item ID=\"0x0F1B\"/>\n                <Item ID=\"0x0F1C\"/>\n                <Item ID=\"0x0F1D\"/>\n                <Item ID=\"0x0F1E\"/>\n                <Item ID=\"0x0F1F\"/>\n                <Item ID=\"0x0F20\"/>\n                <Item ID=\"0x0F21\"/>\n                <Item ID=\"0x0F22\"/>\n                <Item ID=\"0x0F23\"/>\n                <Item ID=\"0x0F24\"/>\n                <Item ID=\"0x0F25\"/>\n                <Item ID=\"0x0F26\"/>\n                <Item ID=\"0x0F27\"/>\n                <Item ID=\"0x0F28\"/>\n                <Item ID=\"0x0F29\"/>\n                <Item ID=\"0x0F2A\"/>\n                <Item ID=\"0x0F2B\"/>\n                <Item ID=\"0x0F2C\"/>\n                <Item ID=\"0x0F2D\"/>\n                <Item ID=\"0x0F2E\"/>\n                <Item ID=\"0x0F2F\"/>\n                <Item ID=\"0x0F30\"/>\n                <Item ID=\"0x1851\"/>\n                <Item ID=\"0x1852\"/>\n                <Item ID=\"0x1B3F\"/>\n                <Item ID=\"0x1B40\"/>\n                <Item ID=\"0x1B41\"/>\n                <Item ID=\"0x1B42\"/>\n                <Item ID=\"0x1B43\"/>\n                <Item ID=\"0x1B44\"/>\n                <Item ID=\"0x1B45\"/>\n                <Item ID=\"0x1B46\"/>\n                <Item ID=\"0x1B47\"/>\n                <Item ID=\"0x1B48\"/>\n                <Item ID=\"0x1B4A\"/>\n                <Item ID=\"0x1B4B\"/>\n                <Item ID=\"0x1B4C\"/>\n                <Item ID=\"0x1B4D\"/>\n                <Item ID=\"0x1B4E\"/>\n                <Item ID=\"0x1B4F\"/>\n                <Item ID=\"0x1B50\"/>\n                <Item ID=\"0x1B51\"/>\n                <Item ID=\"0x1B53\"/>\n                <Item ID=\"0x1B54\"/>\n                <Item ID=\"0x1B55\"/>\n                <Item ID=\"0x1B56\"/>\n                <Item ID=\"0x1B57\"/>\n                <Item ID=\"0x1B58\"/>\n                <Item ID=\"0x1B59\"/>\n                <Item ID=\"0x1B5A\"/>\n                <Item ID=\"0x1B5B\"/>\n                <Item ID=\"0x1B5C\"/>\n                <Item ID=\"0x1B5D\"/>\n                <Item ID=\"0x1B5F\"/>\n                <Item ID=\"0x1B60\"/>\n                <Item ID=\"0x1B61\"/>\n                <Item ID=\"0x1B62\"/>\n                <Item ID=\"0x1B63\"/>\n                <Item ID=\"0x1B64\"/>\n                <Item ID=\"0x1B65\"/>\n                <Item ID=\"0x1B66\"/>\n                <Item ID=\"0x1B67\"/>\n                <Item ID=\"0x1B68\"/>\n                <Item ID=\"0x1B69\"/>\n                <Item ID=\"0x1B6A\"/>\n                <Item ID=\"0x1B6B\"/>\n                <Item ID=\"0x1ec6\"/>\n                <Item ID=\"0x1ec7\"/>\n                <Item ID=\"0x1ec8\"/>\n                <Item ID=\"0x1ec9\"/>\n                <Item ID=\"0x2936\"/>\n                <Item ID=\"0x2937\"/>\n                <Item ID=\"0x3192\"/>\n                <Item ID=\"0x3193\"/>\n                <Item ID=\"0x3194\"/>\n                <Item ID=\"0x3195\"/>\n                <Item ID=\"0x3196\"/>\n                <Item ID=\"0x3197\"/>\n                <Item ID=\"0x3198\"/>\n                <Item ID=\"0x3199\"/>\n            </Group>\n        </Group>\n        <Group name=\"Sea Life\">\n            <Item ID=\"0x3060\"/>\n            <Item ID=\"0x3061\"/>\n            <Item ID=\"0x3062\"/>\n            <Item ID=\"0x3063\"/>\n            <Item ID=\"0x3678\"/>\n            <Item ID=\"0x3AF9\"/>\n            <Item ID=\"0x3AFA\"/>\n            <Item ID=\"0x3AFB\"/>\n            <Item ID=\"0x3AFC\"/>\n            <Item ID=\"0x3AFD\"/>\n            <Item ID=\"0x3AFE\"/>\n            <Item ID=\"0x3AFF\"/>\n            <Item ID=\"0x3B00\"/>\n            <Item ID=\"0x3B01\"/>\n            <Item ID=\"0x3B02\"/>\n            <Item ID=\"0x3B03\"/>\n            <Item ID=\"0x3B04\"/>\n            <Item ID=\"0x3B05\"/>\n            <Item ID=\"0x3B06\"/>\n            <Item ID=\"0x3B07\"/>\n            <Item ID=\"0x3B08\"/>\n            <Item ID=\"0x3B09\"/>\n            <Item ID=\"0x3B0A\"/>\n            <Item ID=\"0x3B0B\"/>\n            <Item ID=\"0x3B0C\"/>\n            <Item ID=\"0x3B0D\"/>\n            <Item ID=\"0x3B0E\"/>\n            <Item ID=\"0x3B0F\"/>\n            <Item ID=\"0x3B10\"/>\n            <Item ID=\"0x3B11\"/>\n            <Item ID=\"0x3B12\"/>\n            <Item ID=\"0x3B13\"/>\n            <Item ID=\"0x3B14\"/>\n            <Item ID=\"0x3B15\"/>\n        </Group>\n        <Group name=\"Sweet Life\">\n            <Group name=\"Bar\">\n                <Item ID=\"0x190E\"/>\n                <Item ID=\"0x190F\"/>\n                <Item ID=\"0x1910\"/>\n                <Item ID=\"0x1911\"/>\n                <Item ID=\"0x1912\"/>\n                <Item ID=\"0x1913\"/>\n                <Item ID=\"0x1918\"/>\n                <Item ID=\"0x1919\"/>\n                <Item ID=\"0x191A\"/>\n                <Item ID=\"0x191B\"/>\n                <Item ID=\"0x191C\"/>\n                <Item ID=\"0x191D\"/>\n                <Item ID=\"0x191E\"/>\n                <Item ID=\"0x191F\"/>\n                <Item ID=\"0x1941\"/>\n                <Item ID=\"0x1942\"/>\n                <Item ID=\"0x1943\"/>\n                <Item ID=\"0x1AD6\"/>\n                <Item ID=\"0x1AD7\"/>\n            </Group>\n            <Group name=\"Drinking\">\n                <Item ID=\"0x098D\"/>\n                <Item ID=\"0x098E\"/>\n                <Item ID=\"0x0995\"/>\n                <Item ID=\"0x0996\"/>\n                <Item ID=\"0x0997\"/>\n                <Item ID=\"0x0998\"/>\n                <Item ID=\"0x0999\"/>\n                <Item ID=\"0x099A\"/>\n                <Item ID=\"0x099B\"/>\n                <Item ID=\"0x099C\"/>\n                <Item ID=\"0x099D\"/>\n                <Item ID=\"0x099E\"/>\n                <Item ID=\"0x099F\"/>\n                <Item ID=\"0x09A0\"/>\n                <Item ID=\"0x09A1\"/>\n                <Item ID=\"0x09A2\"/>\n                <Item ID=\"0x09A7\"/>\n                <Item ID=\"0x09AD\"/>\n                <Item ID=\"0x09B3\"/>\n                <Item ID=\"0x09BF\"/>\n                <Item ID=\"0x09C4\"/>\n                <Item ID=\"0x09C5\"/>\n                <Item ID=\"0x09C6\"/>\n                <Item ID=\"0x09C7\"/>\n                <Item ID=\"0x09C8\"/>\n                <Item ID=\"0x09CA\"/>\n                <Item ID=\"0x09CB\"/>\n                <Item ID=\"0x09D6\"/>\n                <Item ID=\"0x09EE\"/>\n                <Item ID=\"0x09EF\"/>\n                <Item ID=\"0x09F0\"/>\n                <Item ID=\"0x0FF6\"/>\n                <Item ID=\"0x0FF7\"/>\n                <Item ID=\"0x0FF8\"/>\n                <Item ID=\"0x0FF9\"/>\n                <Item ID=\"0x0FFB\"/>\n                <Item ID=\"0x0FFC\"/>\n                <Item ID=\"0x0FFD\"/>\n                <Item ID=\"0x0FFE\"/>\n                <Item ID=\"0x0FFF\"/>\n                <Item ID=\"0x1000\"/>\n                <Item ID=\"0x1001\"/>\n                <Item ID=\"0x1002\"/>\n                <Item ID=\"0x1f7d\"/>\n                <Item ID=\"0x1f7e\"/>\n                <Item ID=\"0x1f7f\"/>\n                <Item ID=\"0x1f80\"/>\n                <Item ID=\"0x1f81\"/>\n                <Item ID=\"0x1f82\"/>\n                <Item ID=\"0x1f83\"/>\n                <Item ID=\"0x1f84\"/>\n                <Item ID=\"0x1f85\"/>\n                <Item ID=\"0x1f86\"/>\n                <Item ID=\"0x1f87\"/>\n                <Item ID=\"0x1f88\"/>\n                <Item ID=\"0x1f89\"/>\n                <Item ID=\"0x1f8a\"/>\n                <Item ID=\"0x1f8b\"/>\n                <Item ID=\"0x1f8c\"/>\n                <Item ID=\"0x1f8d\"/>\n                <Item ID=\"0x1f8e\"/>\n                <Item ID=\"0x1f8f\"/>\n                <Item ID=\"0x1f90\"/>\n                <Item ID=\"0x1f91\"/>\n                <Item ID=\"0x1f92\"/>\n                <Item ID=\"0x1f93\"/>\n                <Item ID=\"0x1f94\"/>\n                <Item ID=\"0x1f95\"/>\n                <Item ID=\"0x1f96\"/>\n                <Item ID=\"0x1f97\"/>\n                <Item ID=\"0x1f98\"/>\n                <Item ID=\"0x1f99\"/>\n                <Item ID=\"0x1f9a\"/>\n                <Item ID=\"0x1f9b\"/>\n                <Item ID=\"0x1f9c\"/>\n                <Item ID=\"0x1f9d\"/>\n                <Item ID=\"0x1f9e\"/>\n                <Item ID=\"0x24E1\"/>\n                <Item ID=\"0x24E2\"/>\n                <Item ID=\"0x24E6\"/>\n                <Item ID=\"0x24E7\"/>\n                <Item ID=\"0x284B\"/>\n                <Item ID=\"0x284C\"/>\n            </Group>\n            <Group name=\"Eating\">\n                <Item ID=\"0x0976\"/>\n                <Item ID=\"0x0977\"/>\n                <Item ID=\"0x0978\"/>\n                <Item ID=\"0x0979\"/>\n                <Item ID=\"0x097A\"/>\n                <Item ID=\"0x097B\"/>\n                <Item ID=\"0x097C\"/>\n                <Item ID=\"0x097D\"/>\n                <Item ID=\"0x097E\"/>\n                <Item ID=\"0x098C\"/>\n                <Item ID=\"0x0993\"/>\n                <Item ID=\"0x0994\"/>\n                <Item ID=\"0x09A3\"/>\n                <Item ID=\"0x09A4\"/>\n                <Item ID=\"0x09A5\"/>\n                <Item ID=\"0x09A6\"/>\n                <Item ID=\"0x09AE\"/>\n                <Item ID=\"0x09AF\"/>\n                <Item ID=\"0x09B4\"/>\n                <Item ID=\"0x09B5\"/>\n                <Item ID=\"0x09B6\"/>\n                <Item ID=\"0x09B7\"/>\n                <Item ID=\"0x09B8\"/>\n                <Item ID=\"0x09B9\"/>\n                <Item ID=\"0x09BA\"/>\n                <Item ID=\"0x09BB\"/>\n                <Item ID=\"0x09BC\"/>\n                <Item ID=\"0x09BD\"/>\n                <Item ID=\"0x09BE\"/>\n                <Item ID=\"0x09C0\"/>\n                <Item ID=\"0x09C1\"/>\n                <Item ID=\"0x09C2\"/>\n                <Item ID=\"0x09C3\"/>\n                <Item ID=\"0x09C9\"/>\n                <Item ID=\"0x09CC\"/>\n                <Item ID=\"0x09CD\"/>\n                <Item ID=\"0x09CE\"/>\n                <Item ID=\"0x09CF\"/>\n                <Item ID=\"0x09D0\"/>\n                <Item ID=\"0x09D1\"/>\n                <Item ID=\"0x09D2\"/>\n                <Item ID=\"0x09D3\"/>\n                <Item ID=\"0x09D4\"/>\n                <Item ID=\"0x09D5\"/>\n                <Item ID=\"0x09D7\"/>\n                <Item ID=\"0x09D8\"/>\n                <Item ID=\"0x09D9\"/>\n                <Item ID=\"0x09DA\"/>\n                <Item ID=\"0x09E9\"/>\n                <Item ID=\"0x09EA\"/>\n                <Item ID=\"0x09EB\"/>\n                <Item ID=\"0x09EC\"/>\n                <Item ID=\"0x09F1\"/>\n                <Item ID=\"0x09F2\"/>\n                <Item ID=\"0x09F4\"/>\n                <Item ID=\"0x09F5\"/>\n                <Item ID=\"0x09F6\"/>\n                <Item ID=\"0x09F7\"/>\n                <Item ID=\"0x09F8\"/>\n                <Item ID=\"0x09F9\"/>\n                <Item ID=\"0x09FA\"/>\n                <Item ID=\"0x0C5C\"/>\n                <Item ID=\"0x0C5D\"/>\n                <Item ID=\"0x0C6A\"/>\n                <Item ID=\"0x0C6B\"/>\n                <Item ID=\"0x0C6C\"/>\n                <Item ID=\"0x0C6D\"/>\n                <Item ID=\"0x0C6E\"/>\n                <Item ID=\"0x0C70\"/>\n                <Item ID=\"0x0C71\"/>\n                <Item ID=\"0x0C72\"/>\n                <Item ID=\"0x0C73\"/>\n                <Item ID=\"0x0C74\"/>\n                <Item ID=\"0x0C75\"/>\n                <Item ID=\"0x0C77\"/>\n                <Item ID=\"0x0C78\"/>\n                <Item ID=\"0x0C79\"/>\n                <Item ID=\"0x0C7A\"/>\n                <Item ID=\"0x0C7B\"/>\n                <Item ID=\"0x0C7C\"/>\n                <Item ID=\"0x0C7F\"/>\n                <Item ID=\"0x0C80\"/>\n                <Item ID=\"0x0C81\"/>\n                <Item ID=\"0x0C82\"/>\n                <Item ID=\"0x103B\"/>\n                <Item ID=\"0x103C\"/>\n                <Item ID=\"0x1040\"/>\n                <Item ID=\"0x1041\"/>\n                <Item ID=\"0x1042\"/>\n                <Item ID=\"0x15F9\"/>\n                <Item ID=\"0x15FA\"/>\n                <Item ID=\"0x15FB\"/>\n                <Item ID=\"0x15FC\"/>\n                <Item ID=\"0x15FD\"/>\n                <Item ID=\"0x15FE\"/>\n                <Item ID=\"0x15FF\"/>\n                <Item ID=\"0x1600\"/>\n                <Item ID=\"0x1601\"/>\n                <Item ID=\"0x1602\"/>\n                <Item ID=\"0x1604\"/>\n                <Item ID=\"0x1605\"/>\n                <Item ID=\"0x1606\"/>\n                <Item ID=\"0x1607\"/>\n                <Item ID=\"0x1608\"/>\n                <Item ID=\"0x1609\"/>\n                <Item ID=\"0x160A\"/>\n                <Item ID=\"0x160B\"/>\n                <Item ID=\"0x160C\"/>\n                <Item ID=\"0x171D\"/>\n                <Item ID=\"0x171E\"/>\n                <Item ID=\"0x171F\"/>\n                <Item ID=\"0x1720\"/>\n                <Item ID=\"0x1721\"/>\n                <Item ID=\"0x1722\"/>\n                <Item ID=\"0x1723\"/>\n                <Item ID=\"0x1724\"/>\n                <Item ID=\"0x1725\"/>\n                <Item ID=\"0x1726\"/>\n                <Item ID=\"0x1727\"/>\n                <Item ID=\"0x1728\"/>\n                <Item ID=\"0x1729\"/>\n                <Item ID=\"0x172A\"/>\n                <Item ID=\"0x172B\"/>\n                <Item ID=\"0x172C\"/>\n                <Item ID=\"0x172D\"/>\n                <Item ID=\"0x1E15\"/>\n                <Item ID=\"0x1E16\"/>\n                <Item ID=\"0x1E17\"/>\n                <Item ID=\"0x1E18\"/>\n                <Item ID=\"0x1E19\"/>\n                <Item ID=\"0x1E1A\"/>\n                <Item ID=\"0x1E1B\"/>\n                <Item ID=\"0x1E1C\"/>\n                <Item ID=\"0x1E1D\"/>\n                <Item ID=\"0x1E1E\"/>\n                <Item ID=\"0x1E1F\"/>\n                <Item ID=\"0x1ad3\"/>\n                <Item ID=\"0x24DE\"/>\n                <Item ID=\"0x24DF\"/>\n                <Item ID=\"0x24E0\"/>\n                <Item ID=\"0x24E8\"/>\n                <Item ID=\"0x24E9\"/>\n                <Item ID=\"0x24EB\"/>\n                <Item ID=\"0x2834\"/>\n                <Item ID=\"0x2835\"/>\n                <Item ID=\"0x2836\"/>\n                <Item ID=\"0x2837\"/>\n                <Item ID=\"0x283E\"/>\n                <Item ID=\"0x283F\"/>\n                <Item ID=\"0x2840\"/>\n                <Item ID=\"0x2841\"/>\n                <Item ID=\"0x284D\"/>\n                <Item ID=\"0x284E\"/>\n                <Item ID=\"0x284F\"/>\n                <Item ID=\"0x2850\"/>\n                <Item ID=\"0x2D4F\"/>\n                <Item ID=\"0x2Fd6\"/>\n                <Item ID=\"0x2Fd7\"/>\n                <Item ID=\"0x2Fd8\"/>\n            </Group>\n            <Group name=\"Games\">\n                <Item ID=\"0x0E12\"/>\n                <Item ID=\"0x0E13\"/>\n                <Item ID=\"0x0E14\"/>\n                <Item ID=\"0x0E15\"/>\n                <Item ID=\"0x0E16\"/>\n                <Item ID=\"0x0E17\"/>\n                <Item ID=\"0x0E18\"/>\n                <Item ID=\"0x0E19\"/>\n                <Item ID=\"0x0E1A\"/>\n                <Item ID=\"0x0E1B\"/>\n                <Item ID=\"0x0E1C\"/>\n                <Item ID=\"0x0FA2\"/>\n                <Item ID=\"0x0FA3\"/>\n                <Item ID=\"0x0FA4\"/>\n                <Item ID=\"0x0FA5\"/>\n                <Item ID=\"0x0FA6\"/>\n                <Item ID=\"0x0FA7\"/>\n                <Item ID=\"0x0FA8\"/>\n                <Item ID=\"0x0FAA\"/>\n                <Item ID=\"0x0FAD\"/>\n                <Item ID=\"0x12A5\"/>\n                <Item ID=\"0x12A6\"/>\n                <Item ID=\"0x12A7\"/>\n                <Item ID=\"0x12A8\"/>\n                <Item ID=\"0x12A9\"/>\n                <Item ID=\"0x12AA\"/>\n                <Item ID=\"0x12AB\"/>\n                <Item ID=\"0x12AC\"/>\n                <Item ID=\"0x1E2e\"/>\n                <Item ID=\"0x1E2f\"/>\n                <Item ID=\"0x1E30\"/>\n                <Item ID=\"0x1E31\"/>\n                <Item ID=\"0x1E32\"/>\n                <Item ID=\"0x1E33\"/>\n                <Item ID=\"0x2256\"/>\n                <Item ID=\"0x2257\"/>\n                <Item ID=\"0x2830\"/>\n                <Item ID=\"0x2831\"/>\n                <Item ID=\"0x2838\"/>\n                <Item ID=\"0x2839\"/>\n                <Item ID=\"0x283A\"/>\n                <Item ID=\"0x283B\"/>\n                <Item ID=\"0x283C\"/>\n                <Item ID=\"0x283D\"/>\n            </Group>\n            <Group name=\"Music\">\n                <Item ID=\"0x0E9C\"/>\n                <Item ID=\"0x0E9D\"/>\n                <Item ID=\"0x0E9E\"/>\n                <Item ID=\"0x0EB1\"/>\n                <Item ID=\"0x0EB2\"/>\n                <Item ID=\"0x0EB3\"/>\n                <Item ID=\"0x0EB4\"/>\n                <Item ID=\"0x0EB5\"/>\n                <Item ID=\"0x0EB6\"/>\n                <Item ID=\"0x0EB7\"/>\n                <Item ID=\"0x0EB8\"/>\n                <Item ID=\"0x0EB9\"/>\n                <Item ID=\"0x0EBA\"/>\n                <Item ID=\"0x0EBB\"/>\n                <Item ID=\"0x0EBC\"/>\n                <Item ID=\"0x0EBD\"/>\n                <Item ID=\"0x0EBE\"/>\n                <Item ID=\"0x0EBF\"/>\n                <Item ID=\"0x0EC0\"/>\n                <Item ID=\"0x2805\"/>\n                <Item ID=\"0x2807\"/>\n                <Item ID=\"0x2832\"/>\n                <Item ID=\"0x2833\"/>\n                <Item ID=\"0x2AF9\"/>\n                <Item ID=\"0x2AFD\"/>\n                <Item ID=\"0x2AFa\"/>\n                <Item ID=\"0x2AFe\"/>\n            </Group>\n        </Group>\n    </Group>\n    <Group name=\"Equipment\">\n        <Group name=\"Amazon\">\n            <Item ID=\"0x2659\"/>\n            <Item ID=\"0x265A\"/>\n            <Item ID=\"0x265B\"/>\n            <Item ID=\"0x265C\"/>\n            <Item ID=\"0x265D\"/>\n            <Item ID=\"0x265E\"/>\n        </Group>\n        <Group name=\"Arcana Clothes\">\n            <Item ID=\"0x26AD\"/>\n            <Item ID=\"0x26AE\"/>\n            <Item ID=\"0x26AF\"/>\n            <Item ID=\"0x26B0\"/>\n        </Group>\n        <Group name=\"Armor Female\">\n            <Item ID=\"0x1C00\"/>\n            <Item ID=\"0x1C01\"/>\n            <Item ID=\"0x1C02\"/>\n            <Item ID=\"0x1C03\"/>\n            <Item ID=\"0x1C04\"/>\n            <Item ID=\"0x1C05\"/>\n            <Item ID=\"0x1C06\"/>\n            <Item ID=\"0x1C07\"/>\n            <Item ID=\"0x1C08\"/>\n            <Item ID=\"0x1C09\"/>\n            <Item ID=\"0x1C0A\"/>\n            <Item ID=\"0x1C0B\"/>\n            <Item ID=\"0x1C0C\"/>\n            <Item ID=\"0x1C0D\"/>\n        </Group>\n        <Group name=\"Bone\">\n            <Item ID=\"0x144E\"/>\n            <Item ID=\"0x144F\"/>\n            <Item ID=\"0x1450\"/>\n            <Item ID=\"0x1451\"/>\n            <Item ID=\"0x1452\"/>\n            <Item ID=\"0x1453\"/>\n            <Item ID=\"0x1454\"/>\n            <Item ID=\"0x1455\"/>\n            <Item ID=\"0x1456\"/>\n            <Item ID=\"0x1457\"/>\n        </Group>\n        <Group name=\"Chainmail\">\n            <Item ID=\"0x13BB\"/>\n            <Item ID=\"0x13BE\"/>\n            <Item ID=\"0x13BF\"/>\n            <Item ID=\"0x13C0\"/>\n            <Item ID=\"0x13C3\"/>\n            <Item ID=\"0x13C4\"/>\n        </Group>\n        <Group name=\"Dragon Armor\">\n            <Item ID=\"0x2641\"/>\n            <Item ID=\"0x2642\"/>\n            <Item ID=\"0x2643\"/>\n            <Item ID=\"0x2644\"/>\n            <Item ID=\"0x2645\"/>\n            <Item ID=\"0x2646\"/>\n            <Item ID=\"0x2647\"/>\n            <Item ID=\"0x2648\"/>\n        </Group>\n        <Group name=\"Dresses + Skirts\">\n            <Item ID=\"0x1515\"/>\n            <Item ID=\"0x1516\"/>\n            <Item ID=\"0x1531\"/>\n            <Item ID=\"0x1537\"/>\n            <Item ID=\"0x1538\"/>\n            <Item ID=\"0x1EFF\"/>\n            <Item ID=\"0x1F00\"/>\n            <Item ID=\"0x1F01\"/>\n            <Item ID=\"0x1F02\"/>\n            <Item ID=\"0x267B\"/>\n            <Item ID=\"0x267C\"/>\n            <Item ID=\"0x267D\"/>\n            <Item ID=\"0x267E\"/>\n            <Item ID=\"0x267F\"/>\n            <Item ID=\"0x2680\"/>\n            <Item ID=\"0x2681\"/>\n            <Item ID=\"0x2682\"/>\n            <Item ID=\"0x2783\"/>\n            <Item ID=\"0x279A\"/>\n            <Item ID=\"0x27CE\"/>\n            <Item ID=\"0x27E5\"/>\n        </Group>\n        <Group name=\"Elven Equipment\">\n            <Item ID=\"0x2B67\"/>\n            <Item ID=\"0x2B68\"/>\n            <Item ID=\"0x2B69\"/>\n            <Item ID=\"0x2B6A\"/>\n            <Item ID=\"0x2B6B\"/>\n            <Item ID=\"0x2B6C\"/>\n            <Item ID=\"0x2B6D\"/>\n            <Item ID=\"0x2B6E\"/>\n            <Item ID=\"0x2B6F\"/>\n            <Item ID=\"0x2B70\"/>\n            <Item ID=\"0x2B71\"/>\n            <Item ID=\"0x2B72\"/>\n            <Item ID=\"0x2B73\"/>\n            <Item ID=\"0x2B74\"/>\n            <Item ID=\"0x2B75\"/>\n            <Item ID=\"0x2B76\"/>\n            <Item ID=\"0x2B77\"/>\n            <Item ID=\"0x2B78\"/>\n            <Item ID=\"0x2B79\"/>\n            <Item ID=\"0x2FB9\"/>\n            <Item ID=\"0x2FBA\"/>\n            <Item ID=\"0x2FC3\"/>\n            <Item ID=\"0x2FC4\"/>\n            <Item ID=\"0x2FC5\"/>\n            <Item ID=\"0x2FC6\"/>\n            <Item ID=\"0x2FC7\"/>\n            <Item ID=\"0x2FC8\"/>\n            <Item ID=\"0x2FC9\"/>\n            <Item ID=\"0x2FCA\"/>\n            <Item ID=\"0x2FCB\"/>\n            <Item ID=\"0x315E\"/>\n            <Item ID=\"0x315F\"/>\n            <Item ID=\"0x3160\"/>\n            <Item ID=\"0x3161\"/>\n            <Item ID=\"0x3162\"/>\n            <Item ID=\"0x3163\"/>\n            <Item ID=\"0x3164\"/>\n            <Item ID=\"0x3165\"/>\n            <Item ID=\"0x3166\"/>\n            <Item ID=\"0x3167\"/>\n            <Item ID=\"0x3168\"/>\n            <Item ID=\"0x3169\"/>\n            <Item ID=\"0x316A\"/>\n            <Item ID=\"0x316B\"/>\n            <Item ID=\"0x316C\"/>\n            <Item ID=\"0x316D\"/>\n            <Item ID=\"0x316E\"/>\n            <Item ID=\"0x316F\"/>\n            <Item ID=\"0x3170\"/>\n            <Item ID=\"0x3173\"/>\n            <Item ID=\"0x3174\"/>\n            <Item ID=\"0x3175\"/>\n            <Item ID=\"0x3176\"/>\n            <Item ID=\"0x3177\"/>\n            <Item ID=\"0x3178\"/>\n            <Item ID=\"0x3179\"/>\n            <Item ID=\"0x317A\"/>\n            <Item ID=\"0x317B\"/>\n            <Item ID=\"0x317C\"/>\n            <Item ID=\"0x317D\"/>\n            <Item ID=\"0x317E\"/>\n            <Item ID=\"0x317F\"/>\n            <Item ID=\"0x3180\"/>\n            <Item ID=\"0x3181\"/>\n        </Group>\n        <Group name=\"Elven Weapon\">\n            <Item ID=\"0x2D1E\"/>\n            <Item ID=\"0x2D1F\"/>\n            <Item ID=\"0x2D20\"/>\n            <Item ID=\"0x2D21\"/>\n            <Item ID=\"0x2D22\"/>\n            <Item ID=\"0x2D23\"/>\n            <Item ID=\"0x2D24\"/>\n            <Item ID=\"0x2D25\"/>\n            <Item ID=\"0x2D26\"/>\n            <Item ID=\"0x2D27\"/>\n            <Item ID=\"0x2D28\"/>\n            <Item ID=\"0x2D29\"/>\n            <Item ID=\"0x2D2A\"/>\n            <Item ID=\"0x2D2B\"/>\n            <Item ID=\"0x2D2C\"/>\n            <Item ID=\"0x2D2D\"/>\n            <Item ID=\"0x2D2E\"/>\n            <Item ID=\"0x2D2F\"/>\n            <Item ID=\"0x2D30\"/>\n            <Item ID=\"0x2D31\"/>\n            <Item ID=\"0x2D32\"/>\n            <Item ID=\"0x2D33\"/>\n            <Item ID=\"0x2D34\"/>\n            <Item ID=\"0x2D35\"/>\n            <Item ID=\"0x3171\"/>\n        </Group>\n        <Group name=\"Footwear + Pants\">\n            <Item ID=\"0x152E\"/>\n            <Item ID=\"0x1539\"/>\n            <Item ID=\"0x153A\"/>\n            <Item ID=\"0x170B\"/>\n            <Item ID=\"0x170C\"/>\n            <Item ID=\"0x170D\"/>\n            <Item ID=\"0x170E\"/>\n            <Item ID=\"0x170F\"/>\n            <Item ID=\"0x1710\"/>\n            <Item ID=\"0x1711\"/>\n            <Item ID=\"0x1712\"/>\n            <Item ID=\"0x264F\"/>\n            <Item ID=\"0x2650\"/>\n            <Item ID=\"0x279B\"/>\n            <Item ID=\"0x27E6\"/>\n        </Group>\n        <Group name=\"Gargoyle\">\n            <Item ID=\"0x0283\"/>\n            <Item ID=\"0x0284\"/>\n            <Item ID=\"0x0285\"/>\n            <Item ID=\"0x0286\"/>\n            <Item ID=\"0x0287\"/>\n            <Item ID=\"0x0288\"/>\n            <Item ID=\"0x0289\"/>\n            <Item ID=\"0x028a\"/>\n            <Item ID=\"0x0301\"/>\n            <Item ID=\"0x0302\"/>\n            <Item ID=\"0x0303\"/>\n            <Item ID=\"0x0304\"/>\n            <Item ID=\"0x0305\"/>\n            <Item ID=\"0x0306\"/>\n            <Item ID=\"0x0307\"/>\n            <Item ID=\"0x0308\"/>\n            <Item ID=\"0x0309\"/>\n            <Item ID=\"0x030a\"/>\n            <Item ID=\"0x030b\"/>\n            <Item ID=\"0x030c\"/>\n            <Item ID=\"0x030d\"/>\n            <Item ID=\"0x030e\"/>\n            <Item ID=\"0x0310\"/>\n            <Item ID=\"0x0311\"/>\n            <Item ID=\"0x0403\"/>\n            <Item ID=\"0x0404\"/>\n            <Item ID=\"0x0405\"/>\n            <Item ID=\"0x0406\"/>\n            <Item ID=\"0x0407\"/>\n            <Item ID=\"0x0408\"/>\n            <Item ID=\"0x0409\"/>\n            <Item ID=\"0x040a\"/>\n        </Group>\n        <Group name=\"Hanging Armor\">\n            <Item ID=\"0x13BC\"/>\n            <Item ID=\"0x13BD\"/>\n            <Item ID=\"0x13C1\"/>\n            <Item ID=\"0x13C2\"/>\n            <Item ID=\"0x13C8\"/>\n            <Item ID=\"0x13C9\"/>\n            <Item ID=\"0x13CA\"/>\n            <Item ID=\"0x13CF\"/>\n            <Item ID=\"0x13D0\"/>\n            <Item ID=\"0x13D1\"/>\n            <Item ID=\"0x13D7\"/>\n            <Item ID=\"0x13D8\"/>\n            <Item ID=\"0x13D9\"/>\n            <Item ID=\"0x13DE\"/>\n            <Item ID=\"0x13DF\"/>\n            <Item ID=\"0x13E0\"/>\n            <Item ID=\"0x13E5\"/>\n            <Item ID=\"0x13E6\"/>\n            <Item ID=\"0x13E7\"/>\n            <Item ID=\"0x13E8\"/>\n            <Item ID=\"0x13E9\"/>\n            <Item ID=\"0x13EA\"/>\n        </Group>\n        <Group name=\"Hats, Masks, Helmets\">\n            <Item ID=\"0x141B\"/>\n            <Item ID=\"0x141C\"/>\n            <Item ID=\"0x153F\"/>\n            <Item ID=\"0x1540\"/>\n            <Item ID=\"0x1543\"/>\n            <Item ID=\"0x1544\"/>\n            <Item ID=\"0x1545\"/>\n            <Item ID=\"0x1546\"/>\n            <Item ID=\"0x1547\"/>\n            <Item ID=\"0x1548\"/>\n            <Item ID=\"0x1549\"/>\n            <Item ID=\"0x154A\"/>\n            <Item ID=\"0x154B\"/>\n            <Item ID=\"0x154C\"/>\n            <Item ID=\"0x1713\"/>\n            <Item ID=\"0x1714\"/>\n            <Item ID=\"0x1715\"/>\n            <Item ID=\"0x1716\"/>\n            <Item ID=\"0x1717\"/>\n            <Item ID=\"0x1718\"/>\n            <Item ID=\"0x1719\"/>\n            <Item ID=\"0x171A\"/>\n            <Item ID=\"0x171B\"/>\n            <Item ID=\"0x19Bc\"/>\n            <Item ID=\"0x19Bd\"/>\n            <Item ID=\"0x1F0B\"/>\n            <Item ID=\"0x1F0C\"/>\n            <Item ID=\"0x236C\"/>\n            <Item ID=\"0x236D\"/>\n            <Item ID=\"0x2689\"/>\n            <Item ID=\"0x268A\"/>\n            <Item ID=\"0x268B\"/>\n            <Item ID=\"0x268C\"/>\n            <Item ID=\"0x268D\"/>\n            <Item ID=\"0x268E\"/>\n            <Item ID=\"0x268F\"/>\n            <Item ID=\"0x2690\"/>\n            <Item ID=\"0x269D\"/>\n            <Item ID=\"0x269E\"/>\n            <Item ID=\"0x26A1\"/>\n            <Item ID=\"0x26A2\"/>\n            <Item ID=\"0x26A3\"/>\n            <Item ID=\"0x26A4\"/>\n            <Item ID=\"0x2776\"/>\n            <Item ID=\"0x2777\"/>\n            <Item ID=\"0x2778\"/>\n            <Item ID=\"0x2784\"/>\n            <Item ID=\"0x2785\"/>\n            <Item ID=\"0x2789\"/>\n            <Item ID=\"0x278E\"/>\n            <Item ID=\"0x278F\"/>\n            <Item ID=\"0x2798\"/>\n            <Item ID=\"0x27C1\"/>\n            <Item ID=\"0x27C2\"/>\n            <Item ID=\"0x27C3\"/>\n            <Item ID=\"0x27CC\"/>\n            <Item ID=\"0x27CF\"/>\n            <Item ID=\"0x27D0\"/>\n            <Item ID=\"0x27D4\"/>\n            <Item ID=\"0x27D9\"/>\n            <Item ID=\"0x27DA\"/>\n            <Item ID=\"0x27E3\"/>\n        </Group>\n        <Group name=\"Jester\">\n            <Item ID=\"0x171C\"/>\n            <Item ID=\"0x1F9F\"/>\n            <Item ID=\"0x1FA0\"/>\n            <Item ID=\"0x2649\"/>\n            <Item ID=\"0x264A\"/>\n            <Item ID=\"0x2655\"/>\n            <Item ID=\"0x2656\"/>\n        </Group>\n        <Group name=\"Leather\">\n            <Item ID=\"0x13C5\"/>\n            <Item ID=\"0x13C6\"/>\n            <Item ID=\"0x13C7\"/>\n            <Item ID=\"0x13CB\"/>\n            <Item ID=\"0x13CC\"/>\n            <Item ID=\"0x13CD\"/>\n            <Item ID=\"0x13CE\"/>\n            <Item ID=\"0x13D2\"/>\n            <Item ID=\"0x13D3\"/>\n            <Item ID=\"0x2691\"/>\n            <Item ID=\"0x2692\"/>\n        </Group>\n        <Group name=\"Misc\">\n            <Item ID=\"0x153B\"/>\n            <Item ID=\"0x153C\"/>\n            <Item ID=\"0x153D\"/>\n            <Item ID=\"0x153E\"/>\n            <Item ID=\"0x1541\"/>\n            <Item ID=\"0x1542\"/>\n            <Item ID=\"0x27A0\"/>\n            <Item ID=\"0x27EB\"/>\n        </Group>\n        <Group name=\"Plate\">\n            <Item ID=\"0x1408\"/>\n            <Item ID=\"0x1409\"/>\n            <Item ID=\"0x140A\"/>\n            <Item ID=\"0x140B\"/>\n            <Item ID=\"0x140C\"/>\n            <Item ID=\"0x140D\"/>\n            <Item ID=\"0x140E\"/>\n            <Item ID=\"0x140F\"/>\n            <Item ID=\"0x1410\"/>\n            <Item ID=\"0x1411\"/>\n            <Item ID=\"0x1412\"/>\n            <Item ID=\"0x1413\"/>\n            <Item ID=\"0x1414\"/>\n            <Item ID=\"0x1415\"/>\n            <Item ID=\"0x1416\"/>\n            <Item ID=\"0x1417\"/>\n            <Item ID=\"0x1418\"/>\n            <Item ID=\"0x1419\"/>\n            <Item ID=\"0x141A\"/>\n            <Item ID=\"0x264B\"/>\n            <Item ID=\"0x264C\"/>\n        </Group>\n        <Group name=\"Ringmail\">\n            <Item ID=\"0x13EB\"/>\n            <Item ID=\"0x13EC\"/>\n            <Item ID=\"0x13ED\"/>\n            <Item ID=\"0x13EE\"/>\n            <Item ID=\"0x13EF\"/>\n            <Item ID=\"0x13F0\"/>\n            <Item ID=\"0x13F1\"/>\n            <Item ID=\"0x13F2\"/>\n        </Group>\n        <Group name=\"Samurai Weapon\">\n            <Item ID=\"0x27A2\"/>\n            <Item ID=\"0x27A3\"/>\n            <Item ID=\"0x27A4\"/>\n            <Item ID=\"0x27A5\"/>\n            <Item ID=\"0x27A6\"/>\n            <Item ID=\"0x27A7\"/>\n            <Item ID=\"0x27A8\"/>\n            <Item ID=\"0x27A9\"/>\n            <Item ID=\"0x27AA\"/>\n            <Item ID=\"0x27AB\"/>\n            <Item ID=\"0x27AC\"/>\n            <Item ID=\"0x27AD\"/>\n            <Item ID=\"0x27AE\"/>\n            <Item ID=\"0x27AF\"/>\n            <Item ID=\"0x27ED\"/>\n            <Item ID=\"0x27EE\"/>\n            <Item ID=\"0x27EF\"/>\n            <Item ID=\"0x27F0\"/>\n            <Item ID=\"0x27F1\"/>\n            <Item ID=\"0x27F2\"/>\n            <Item ID=\"0x27F3\"/>\n            <Item ID=\"0x27F4\"/>\n            <Item ID=\"0x27F5\"/>\n            <Item ID=\"0x27F6\"/>\n            <Item ID=\"0x27F7\"/>\n            <Item ID=\"0x27F8\"/>\n            <Item ID=\"0x27F9\"/>\n            <Item ID=\"0x27FA\"/>\n            <Item ID=\"0x2804\"/>\n            <Item ID=\"0x2806\"/>\n            <Item ID=\"0x2808\"/>\n            <Item ID=\"0x2808\"/>\n        </Group>\n        <Group name=\"Samurai+Ninja\">\n            <Item ID=\"0x264D\"/>\n            <Item ID=\"0x264E\"/>\n            <Item ID=\"0x2651\"/>\n            <Item ID=\"0x2652\"/>\n            <Item ID=\"0x2653\"/>\n            <Item ID=\"0x2654\"/>\n            <Item ID=\"0x2667\"/>\n            <Item ID=\"0x2668\"/>\n            <Item ID=\"0x266B\"/>\n            <Item ID=\"0x266C\"/>\n            <Item ID=\"0x266D\"/>\n            <Item ID=\"0x266E\"/>\n            <Item ID=\"0x2673\"/>\n            <Item ID=\"0x2674\"/>\n            <Item ID=\"0x2677\"/>\n            <Item ID=\"0x2678\"/>\n            <Item ID=\"0x2679\"/>\n            <Item ID=\"0x267A\"/>\n            <Item ID=\"0x2774\"/>\n            <Item ID=\"0x2775\"/>\n            <Item ID=\"0x2779\"/>\n            <Item ID=\"0x277A\"/>\n            <Item ID=\"0x277B\"/>\n            <Item ID=\"0x277C\"/>\n            <Item ID=\"0x277D\"/>\n            <Item ID=\"0x277E\"/>\n            <Item ID=\"0x277F\"/>\n            <Item ID=\"0x2780\"/>\n            <Item ID=\"0x2786\"/>\n            <Item ID=\"0x2787\"/>\n            <Item ID=\"0x2788\"/>\n            <Item ID=\"0x278A\"/>\n            <Item ID=\"0x278B\"/>\n            <Item ID=\"0x278D\"/>\n            <Item ID=\"0x2790\"/>\n            <Item ID=\"0x2791\"/>\n            <Item ID=\"0x2792\"/>\n            <Item ID=\"0x2793\"/>\n            <Item ID=\"0x2794\"/>\n            <Item ID=\"0x2796\"/>\n            <Item ID=\"0x2797\"/>\n            <Item ID=\"0x279D\"/>\n            <Item ID=\"0x27A1\"/>\n            <Item ID=\"0x27BF\"/>\n            <Item ID=\"0x27C0\"/>\n            <Item ID=\"0x27C4\"/>\n            <Item ID=\"0x27C5\"/>\n            <Item ID=\"0x27C6\"/>\n            <Item ID=\"0x27C7\"/>\n            <Item ID=\"0x27C8\"/>\n            <Item ID=\"0x27C9\"/>\n            <Item ID=\"0x27CA\"/>\n            <Item ID=\"0x27CB\"/>\n            <Item ID=\"0x27D1\"/>\n            <Item ID=\"0x27D2\"/>\n            <Item ID=\"0x27D3\"/>\n            <Item ID=\"0x27D5\"/>\n            <Item ID=\"0x27D6\"/>\n            <Item ID=\"0x27D8\"/>\n            <Item ID=\"0x27DB\"/>\n            <Item ID=\"0x27DC\"/>\n            <Item ID=\"0x27DD\"/>\n            <Item ID=\"0x27DE\"/>\n            <Item ID=\"0x27DF\"/>\n            <Item ID=\"0x27E1\"/>\n            <Item ID=\"0x27E2\"/>\n            <Item ID=\"0x27E8\"/>\n            <Item ID=\"0x27EC\"/>\n        </Group>\n        <Group name=\"Shields\">\n            <Item ID=\"0x1B72\"/>\n            <Item ID=\"0x1B73\"/>\n            <Item ID=\"0x1B74\"/>\n            <Item ID=\"0x1B75\"/>\n            <Item ID=\"0x1B76\"/>\n            <Item ID=\"0x1B77\"/>\n            <Item ID=\"0x1B78\"/>\n            <Item ID=\"0x1B79\"/>\n            <Item ID=\"0x1B7A\"/>\n            <Item ID=\"0x1B7B\"/>\n            <Item ID=\"0x1BC3\"/>\n            <Item ID=\"0x1BC4\"/>\n            <Item ID=\"0x1BC5\"/>\n            <Item ID=\"0x1BC6\"/>\n            <Item ID=\"0x1BC7\"/>\n        </Group>\n        <Group name=\"Shirts + Tunics\">\n            <Item ID=\"0x1517\"/>\n            <Item ID=\"0x1518\"/>\n            <Item ID=\"0x1EFD\"/>\n            <Item ID=\"0x1EFE\"/>\n            <Item ID=\"0x1F7B\"/>\n            <Item ID=\"0x1F7C\"/>\n            <Item ID=\"0x1FA1\"/>\n            <Item ID=\"0x1FA2\"/>\n            <Item ID=\"0x1FFD\"/>\n            <Item ID=\"0x1FFE\"/>\n            <Item ID=\"0x265F\"/>\n            <Item ID=\"0x2660\"/>\n            <Item ID=\"0x2661\"/>\n            <Item ID=\"0x2662\"/>\n            <Item ID=\"0x2663\"/>\n            <Item ID=\"0x2664\"/>\n            <Item ID=\"0x2665\"/>\n            <Item ID=\"0x2666\"/>\n            <Item ID=\"0x2671\"/>\n            <Item ID=\"0x2672\"/>\n            <Item ID=\"0x2799\"/>\n            <Item ID=\"0x279C\"/>\n            <Item ID=\"0x27E4\"/>\n            <Item ID=\"0x27E7\"/>\n        </Group>\n        <Group name=\"Shrouds + Cloaks\">\n            <Item ID=\"0x1530\"/>\n            <Item ID=\"0x1F03\"/>\n            <Item ID=\"0x1F04\"/>\n            <Item ID=\"0x2683\"/>\n            <Item ID=\"0x2684\"/>\n            <Item ID=\"0x2685\"/>\n            <Item ID=\"0x2686\"/>\n            <Item ID=\"0x2687\"/>\n            <Item ID=\"0x2782\"/>\n            <Item ID=\"0x27CD\"/>\n        </Group>\n        <Group name=\"Studded\">\n            <Item ID=\"0x13D4\"/>\n            <Item ID=\"0x13D5\"/>\n            <Item ID=\"0x13D6\"/>\n            <Item ID=\"0x13DA\"/>\n            <Item ID=\"0x13DB\"/>\n            <Item ID=\"0x13DC\"/>\n            <Item ID=\"0x13DD\"/>\n            <Item ID=\"0x13E1\"/>\n            <Item ID=\"0x13E2\"/>\n        </Group>\n        <Group name=\"Weapon + Tools\">\n            <Item ID=\"0x0DF0\"/>\n            <Item ID=\"0x0DF1\"/>\n            <Item ID=\"0x0E81\"/>\n            <Item ID=\"0x0E82\"/>\n            <Item ID=\"0x0E85\"/>\n            <Item ID=\"0x0E86\"/>\n            <Item ID=\"0x0E87\"/>\n            <Item ID=\"0x0E88\"/>\n            <Item ID=\"0x0E89\"/>\n            <Item ID=\"0x0E8A\"/>\n            <Item ID=\"0x0F43\"/>\n            <Item ID=\"0x0F44\"/>\n            <Item ID=\"0x0F45\"/>\n            <Item ID=\"0x0F46\"/>\n            <Item ID=\"0x0F47\"/>\n            <Item ID=\"0x0F48\"/>\n            <Item ID=\"0x0F49\"/>\n            <Item ID=\"0x0F4A\"/>\n            <Item ID=\"0x0F4B\"/>\n            <Item ID=\"0x0F4C\"/>\n            <Item ID=\"0x0F4D\"/>\n            <Item ID=\"0x0F4E\"/>\n            <Item ID=\"0x0F4F\"/>\n            <Item ID=\"0x0F50\"/>\n            <Item ID=\"0x0F51\"/>\n            <Item ID=\"0x0F52\"/>\n            <Item ID=\"0x0F5C\"/>\n            <Item ID=\"0x0F5D\"/>\n            <Item ID=\"0x0F5E\"/>\n            <Item ID=\"0x0F5F\"/>\n            <Item ID=\"0x0F60\"/>\n            <Item ID=\"0x0F61\"/>\n            <Item ID=\"0x0F62\"/>\n            <Item ID=\"0x0F63\"/>\n            <Item ID=\"0x13AF\"/>\n            <Item ID=\"0x13B0\"/>\n            <Item ID=\"0x13B1\"/>\n            <Item ID=\"0x13B2\"/>\n            <Item ID=\"0x13B3\"/>\n            <Item ID=\"0x13B4\"/>\n            <Item ID=\"0x13B5\"/>\n            <Item ID=\"0x13B6\"/>\n            <Item ID=\"0x13B7\"/>\n            <Item ID=\"0x13B8\"/>\n            <Item ID=\"0x13B9\"/>\n            <Item ID=\"0x13BA\"/>\n            <Item ID=\"0x13E3\"/>\n            <Item ID=\"0x13E4\"/>\n            <Item ID=\"0x13F4\"/>\n            <Item ID=\"0x13F5\"/>\n            <Item ID=\"0x13F6\"/>\n            <Item ID=\"0x13F7\"/>\n            <Item ID=\"0x13F8\"/>\n            <Item ID=\"0x13F9\"/>\n            <Item ID=\"0x13FA\"/>\n            <Item ID=\"0x13FB\"/>\n            <Item ID=\"0x13FC\"/>\n            <Item ID=\"0x13FD\"/>\n            <Item ID=\"0x13FE\"/>\n            <Item ID=\"0x13FF\"/>\n            <Item ID=\"0x1400\"/>\n            <Item ID=\"0x1401\"/>\n            <Item ID=\"0x1402\"/>\n            <Item ID=\"0x1403\"/>\n            <Item ID=\"0x1404\"/>\n            <Item ID=\"0x1405\"/>\n            <Item ID=\"0x1406\"/>\n            <Item ID=\"0x1407\"/>\n            <Item ID=\"0x1438\"/>\n            <Item ID=\"0x1439\"/>\n            <Item ID=\"0x143A\"/>\n            <Item ID=\"0x143B\"/>\n            <Item ID=\"0x143C\"/>\n            <Item ID=\"0x143D\"/>\n            <Item ID=\"0x143E\"/>\n            <Item ID=\"0x143F\"/>\n            <Item ID=\"0x1440\"/>\n            <Item ID=\"0x1441\"/>\n            <Item ID=\"0x1442\"/>\n            <Item ID=\"0x1443\"/>\n            <Item ID=\"0x26BA\"/>\n            <Item ID=\"0x26BB\"/>\n            <Item ID=\"0x26BC\"/>\n            <Item ID=\"0x26BD\"/>\n            <Item ID=\"0x26BE\"/>\n            <Item ID=\"0x26BF\"/>\n            <Item ID=\"0x26C0\"/>\n            <Item ID=\"0x26C1\"/>\n            <Item ID=\"0x26C2\"/>\n            <Item ID=\"0x26C3\"/>\n            <Item ID=\"0x26C4\"/>\n            <Item ID=\"0x26C5\"/>\n            <Item ID=\"0x26C6\"/>\n            <Item ID=\"0x26C7\"/>\n            <Item ID=\"0x26C8\"/>\n            <Item ID=\"0x26C9\"/>\n            <Item ID=\"0x26CA\"/>\n            <Item ID=\"0x26CB\"/>\n            <Item ID=\"0x26CC\"/>\n            <Item ID=\"0x26CD\"/>\n            <Item ID=\"0x26CE\"/>\n            <Item ID=\"0x26CF\"/>\n            <Item ID=\"0x26ac\"/>\n        </Group>\n    </Group>\n    <Group name=\"Miniatures + Celebrations\">\n        <Group name=\"8th Anniversary Items\">\n            <Item ID=\"0x2B01\"/>\n            <Item ID=\"0x2B02\"/>\n            <Item ID=\"0x2B03\"/>\n            <Item ID=\"0x2B04\"/>\n            <Item ID=\"0x2B05\"/>\n            <Item ID=\"0x2B06\"/>\n            <Item ID=\"0x2B07\"/>\n            <Item ID=\"0x2B08\"/>\n            <Item ID=\"0x2B09\"/>\n            <Item ID=\"0x2B0A\"/>\n            <Item ID=\"0x2B0B\"/>\n            <Item ID=\"0x2B0C\"/>\n            <Item ID=\"0x2B0D\"/>\n            <Item ID=\"0x2B0E\"/>\n            <Item ID=\"0x2B0F\"/>\n            <Item ID=\"0x2B10\"/>\n            <Item ID=\"0x2B11\"/>\n            <Item ID=\"0x2B12\"/>\n            <Item ID=\"0x2B13\"/>\n        </Group>\n        <Group name=\"9th Anniversary Items\">\n            <Item ID=\"0x3DB1\"/>\n            <Item ID=\"0x3F07\"/>\n            <Item ID=\"0x3F08\"/>\n            <Item ID=\"0x3F09\"/>\n            <Item ID=\"0x3F0A\"/>\n            <Item ID=\"0x3F0B\"/>\n            <Item ID=\"0x3F0C\"/>\n            <Item ID=\"0x3F0D\"/>\n            <Item ID=\"0x3F0E\"/>\n            <Item ID=\"0x3F0F\"/>\n            <Item ID=\"0x3F10\"/>\n            <Item ID=\"0x3F11\"/>\n            <Item ID=\"0x3F12\"/>\n            <Item ID=\"0x3F13\"/>\n            <Item ID=\"0x3F14\"/>\n            <Item ID=\"0x3F15\"/>\n            <Item ID=\"0x3F16\"/>\n            <Item ID=\"0x3F17\"/>\n            <Item ID=\"0x3F18\"/>\n            <Item ID=\"0x3F19\"/>\n            <Item ID=\"0x3F1A\"/>\n            <Item ID=\"0x3F1B\"/>\n            <Item ID=\"0x3F1C\"/>\n            <Item ID=\"0x3F1D\"/>\n            <Item ID=\"0x3F1E\"/>\n            <Item ID=\"0x3F1F\"/>\n            <Item ID=\"0x3F20\"/>\n            <Item ID=\"0x3F21\"/>\n            <Item ID=\"0x3F22\"/>\n            <Item ID=\"0x3F23\"/>\n            <Item ID=\"0x3F24\"/>\n            <Item ID=\"0x3F25\"/>\n            <Item ID=\"0x3F26\"/>\n            <Item ID=\"0x3F27\"/>\n        </Group>\n        <Group name=\"Mini House's\">\n            <Item ID=\"0x22C4\"/>\n            <Item ID=\"0x22C9\"/>\n            <Item ID=\"0x22CA\"/>\n            <Item ID=\"0x22CB\"/>\n            <Item ID=\"0x22CC\"/>\n            <Item ID=\"0x22CD\"/>\n            <Item ID=\"0x22CE\"/>\n            <Item ID=\"0x22CF\"/>\n            <Item ID=\"0x22D0\"/>\n            <Item ID=\"0x22D1\"/>\n            <Item ID=\"0x22D2\"/>\n            <Item ID=\"0x22D3\"/>\n            <Item ID=\"0x22D4\"/>\n            <Item ID=\"0x22D5\"/>\n            <Item ID=\"0x22D6\"/>\n            <Item ID=\"0x22D7\"/>\n            <Item ID=\"0x22D8\"/>\n            <Item ID=\"0x22D9\"/>\n            <Item ID=\"0x22DA\"/>\n            <Item ID=\"0x22DB\"/>\n            <Item ID=\"0x22DC\"/>\n            <Item ID=\"0x22DD\"/>\n            <Item ID=\"0x22DE\"/>\n            <Item ID=\"0x22DF\"/>\n            <Item ID=\"0x22E0\"/>\n            <Item ID=\"0x22E1\"/>\n            <Item ID=\"0x22E2\"/>\n            <Item ID=\"0x22E3\"/>\n            <Item ID=\"0x22E4\"/>\n            <Item ID=\"0x22E5\"/>\n            <Item ID=\"0x22E6\"/>\n            <Item ID=\"0x22E7\"/>\n            <Item ID=\"0x22E8\"/>\n            <Item ID=\"0x22E9\"/>\n            <Item ID=\"0x22EA\"/>\n            <Item ID=\"0x22EB\"/>\n            <Item ID=\"0x22EC\"/>\n            <Item ID=\"0x22ED\"/>\n            <Item ID=\"0x22EE\"/>\n            <Item ID=\"0x22EF\"/>\n            <Item ID=\"0x22F0\"/>\n            <Item ID=\"0x22F1\"/>\n            <Item ID=\"0x22F2\"/>\n            <Item ID=\"0x22F3\"/>\n            <Item ID=\"0x22F4\"/>\n            <Item ID=\"0x22F5\"/>\n            <Item ID=\"0x22F6\"/>\n            <Item ID=\"0x22F7\"/>\n            <Item ID=\"0x22F8\"/>\n            <Item ID=\"0x22F9\"/>\n            <Item ID=\"0x22FA\"/>\n            <Item ID=\"0x22FB\"/>\n            <Item ID=\"0x22FC\"/>\n            <Item ID=\"0x22FD\"/>\n            <Item ID=\"0x22FE\"/>\n            <Item ID=\"0x22FF\"/>\n            <Item ID=\"0x2300\"/>\n            <Item ID=\"0x2301\"/>\n            <Item ID=\"0x2302\"/>\n            <Item ID=\"0x2303\"/>\n            <Item ID=\"0x2304\"/>\n            <Item ID=\"0x2313\"/>\n            <Item ID=\"0x2314\"/>\n            <Item ID=\"0x2315\"/>\n            <Item ID=\"0x2316\"/>\n            <Item ID=\"0x2317\"/>\n            <Item ID=\"0x2318\"/>\n            <Item ID=\"0x2319\"/>\n        </Group>\n        <Group name=\"Mini Monster UO:KR/SA\">\n            <Item ID=\"0x3ffd\"/>\n        </Group>\n        <Group name=\"Mini Monsters AOS\">\n            <Item ID=\"0x25F8\"/>\n            <Item ID=\"0x25F9\"/>\n            <Item ID=\"0x25FA\"/>\n            <Item ID=\"0x25FB\"/>\n            <Item ID=\"0x25FC\"/>\n            <Item ID=\"0x2602\"/>\n            <Item ID=\"0x2603\"/>\n            <Item ID=\"0x2604\"/>\n            <Item ID=\"0x2605\"/>\n            <Item ID=\"0x2606\"/>\n            <Item ID=\"0x2607\"/>\n            <Item ID=\"0x2608\"/>\n            <Item ID=\"0x2609\"/>\n            <Item ID=\"0x260A\"/>\n            <Item ID=\"0x260B\"/>\n            <Item ID=\"0x260C\"/>\n            <Item ID=\"0x260D\"/>\n            <Item ID=\"0x260E\"/>\n            <Item ID=\"0x260F\"/>\n            <Item ID=\"0x2610\"/>\n            <Item ID=\"0x2611\"/>\n            <Item ID=\"0x2612\"/>\n            <Item ID=\"0x2613\"/>\n            <Item ID=\"0x2614\"/>\n            <Item ID=\"0x2615\"/>\n            <Item ID=\"0x2616\"/>\n            <Item ID=\"0x2617\"/>\n            <Item ID=\"0x2618\"/>\n            <Item ID=\"0x2619\"/>\n            <Item ID=\"0x261A\"/>\n            <Item ID=\"0x261B\"/>\n            <Item ID=\"0x261C\"/>\n            <Item ID=\"0x261D\"/>\n            <Item ID=\"0x261E\"/>\n            <Item ID=\"0x261F\"/>\n            <Item ID=\"0x2620\"/>\n            <Item ID=\"0x2621\"/>\n            <Item ID=\"0x2622\"/>\n            <Item ID=\"0x2623\"/>\n            <Item ID=\"0x2624\"/>\n            <Item ID=\"0x2625\"/>\n            <Item ID=\"0x2626\"/>\n            <Item ID=\"0x2627\"/>\n            <Item ID=\"0x2628\"/>\n            <Item ID=\"0x2629\"/>\n            <Item ID=\"0x262A\"/>\n            <Item ID=\"0x262B\"/>\n            <Item ID=\"0x262C\"/>\n            <Item ID=\"0x262D\"/>\n            <Item ID=\"0x262E\"/>\n            <Item ID=\"0x262F\"/>\n            <Item ID=\"0x2630\"/>\n            <Item ID=\"0x2631\"/>\n            <Item ID=\"0x2632\"/>\n            <Item ID=\"0x2633\"/>\n        </Group>\n        <Group name=\"Mini Monsters UO\">\n            <Item ID=\"0x20CF\"/>\n            <Item ID=\"0x20D0\"/>\n            <Item ID=\"0x20D1\"/>\n            <Item ID=\"0x20D2\"/>\n            <Item ID=\"0x20D3\"/>\n            <Item ID=\"0x20D4\"/>\n            <Item ID=\"0x20D5\"/>\n            <Item ID=\"0x20D6\"/>\n            <Item ID=\"0x20D7\"/>\n            <Item ID=\"0x20D8\"/>\n            <Item ID=\"0x20D9\"/>\n            <Item ID=\"0x20DA\"/>\n            <Item ID=\"0x20DB\"/>\n            <Item ID=\"0x20DC\"/>\n            <Item ID=\"0x20DD\"/>\n            <Item ID=\"0x20DE\"/>\n            <Item ID=\"0x20DF\"/>\n            <Item ID=\"0x20E0\"/>\n            <Item ID=\"0x20E1\"/>\n            <Item ID=\"0x20E2\"/>\n            <Item ID=\"0x20E3\"/>\n            <Item ID=\"0x20E4\"/>\n            <Item ID=\"0x20E5\"/>\n            <Item ID=\"0x20E6\"/>\n            <Item ID=\"0x20E7\"/>\n            <Item ID=\"0x20E8\"/>\n            <Item ID=\"0x20E9\"/>\n            <Item ID=\"0x20EA\"/>\n            <Item ID=\"0x20EB\"/>\n            <Item ID=\"0x20EC\"/>\n            <Item ID=\"0x20ED\"/>\n            <Item ID=\"0x20EE\"/>\n            <Item ID=\"0x20EF\"/>\n            <Item ID=\"0x20F0\"/>\n            <Item ID=\"0x20F1\"/>\n            <Item ID=\"0x20F2\"/>\n            <Item ID=\"0x20F3\"/>\n            <Item ID=\"0x20F4\"/>\n            <Item ID=\"0x20F5\"/>\n            <Item ID=\"0x20F6\"/>\n            <Item ID=\"0x20F7\"/>\n            <Item ID=\"0x20F8\"/>\n            <Item ID=\"0x20F9\"/>\n            <Item ID=\"0x20FA\"/>\n            <Item ID=\"0x20FB\"/>\n            <Item ID=\"0x20FC\"/>\n            <Item ID=\"0x20FD\"/>\n            <Item ID=\"0x20FE\"/>\n            <Item ID=\"0x20FF\"/>\n            <Item ID=\"0x2100\"/>\n            <Item ID=\"0x2101\"/>\n            <Item ID=\"0x2102\"/>\n            <Item ID=\"0x2103\"/>\n            <Item ID=\"0x2106\"/>\n            <Item ID=\"0x2107\"/>\n            <Item ID=\"0x2108\"/>\n            <Item ID=\"0x2109\"/>\n            <Item ID=\"0x210A\"/>\n            <Item ID=\"0x210B\"/>\n        </Group>\n        <Group name=\"Mini Monsters UO:LBR\">\n            <Item ID=\"0x21F1\"/>\n            <Item ID=\"0x2580\"/>\n            <Item ID=\"0x2581\"/>\n            <Item ID=\"0x2582\"/>\n            <Item ID=\"0x2583\"/>\n            <Item ID=\"0x2584\"/>\n            <Item ID=\"0x2585\"/>\n            <Item ID=\"0x2586\"/>\n            <Item ID=\"0x2587\"/>\n            <Item ID=\"0x2588\"/>\n            <Item ID=\"0x2589\"/>\n            <Item ID=\"0x258B\"/>\n            <Item ID=\"0x258C\"/>\n            <Item ID=\"0x258D\"/>\n            <Item ID=\"0x258E\"/>\n            <Item ID=\"0x258F\"/>\n            <Item ID=\"0x2590\"/>\n            <Item ID=\"0x2591\"/>\n            <Item ID=\"0x2592\"/>\n            <Item ID=\"0x2593\"/>\n            <Item ID=\"0x2594\"/>\n            <Item ID=\"0x2595\"/>\n            <Item ID=\"0x2596\"/>\n            <Item ID=\"0x2597\"/>\n            <Item ID=\"0x2598\"/>\n            <Item ID=\"0x2599\"/>\n            <Item ID=\"0x259A\"/>\n            <Item ID=\"0x259B\"/>\n            <Item ID=\"0x259C\"/>\n            <Item ID=\"0x259D\"/>\n            <Item ID=\"0x259E\"/>\n            <Item ID=\"0x259F\"/>\n            <Item ID=\"0x25A0\"/>\n            <Item ID=\"0x25A1\"/>\n            <Item ID=\"0x25A2\"/>\n            <Item ID=\"0x25A3\"/>\n            <Item ID=\"0x25A4\"/>\n            <Item ID=\"0x25A5\"/>\n            <Item ID=\"0x25A6\"/>\n            <Item ID=\"0x25A7\"/>\n            <Item ID=\"0x25A8\"/>\n            <Item ID=\"0x25A9\"/>\n            <Item ID=\"0x25AA\"/>\n            <Item ID=\"0x25AB\"/>\n            <Item ID=\"0x25AC\"/>\n            <Item ID=\"0x25AD\"/>\n            <Item ID=\"0x25AE\"/>\n            <Item ID=\"0x25AF\"/>\n            <Item ID=\"0x25B0\"/>\n            <Item ID=\"0x25B1\"/>\n            <Item ID=\"0x25B2\"/>\n            <Item ID=\"0x25B3\"/>\n            <Item ID=\"0x25B4\"/>\n            <Item ID=\"0x25B5\"/>\n            <Item ID=\"0x25B6\"/>\n            <Item ID=\"0x25B7\"/>\n            <Item ID=\"0x25B8\"/>\n            <Item ID=\"0x25B9\"/>\n            <Item ID=\"0x25BA\"/>\n            <Item ID=\"0x25BB\"/>\n            <Item ID=\"0x25BC\"/>\n            <Item ID=\"0x25BD\"/>\n            <Item ID=\"0x25BE\"/>\n            <Item ID=\"0x25BF\"/>\n            <Item ID=\"0x25C0\"/>\n            <Item ID=\"0x25C1\"/>\n            <Item ID=\"0x25C2\"/>\n            <Item ID=\"0x25C3\"/>\n            <Item ID=\"0x25C4\"/>\n            <Item ID=\"0x25C5\"/>\n            <Item ID=\"0x25C6\"/>\n            <Item ID=\"0x25C7\"/>\n            <Item ID=\"0x25C8\"/>\n            <Item ID=\"0x25C9\"/>\n            <Item ID=\"0x25CA\"/>\n            <Item ID=\"0x25CB\"/>\n            <Item ID=\"0x25CC\"/>\n            <Item ID=\"0x25CD\"/>\n            <Item ID=\"0x25CE\"/>\n            <Item ID=\"0x25CF\"/>\n            <Item ID=\"0x25D0\"/>\n            <Item ID=\"0x25D1\"/>\n            <Item ID=\"0x25D2\"/>\n            <Item ID=\"0x25D3\"/>\n            <Item ID=\"0x25D4\"/>\n            <Item ID=\"0x25D5\"/>\n            <Item ID=\"0x25D6\"/>\n            <Item ID=\"0x25D7\"/>\n            <Item ID=\"0x25D8\"/>\n            <Item ID=\"0x25D9\"/>\n            <Item ID=\"0x25DA\"/>\n            <Item ID=\"0x25DB\"/>\n            <Item ID=\"0x25DC\"/>\n            <Item ID=\"0x25DD\"/>\n        </Group>\n        <Group name=\"Mini Monsters UO:ML\">\n            <Item ID=\"0x2D82\"/>\n            <Item ID=\"0x2D83\"/>\n            <Item ID=\"0x2D84\"/>\n            <Item ID=\"0x2D85\"/>\n            <Item ID=\"0x2D88\"/>\n            <Item ID=\"0x2D89\"/>\n            <Item ID=\"0x2D8A\"/>\n            <Item ID=\"0x2D8B\"/>\n            <Item ID=\"0x2D8C\"/>\n            <Item ID=\"0x2D8D\"/>\n            <Item ID=\"0x2D90\"/>\n            <Item ID=\"0x2D93\"/>\n            <Item ID=\"0x2D94\"/>\n            <Item ID=\"0x2D95\"/>\n            <Item ID=\"0x2D96\"/>\n            <Item ID=\"0x2D97\"/>\n            <Item ID=\"0x2D98\"/>\n            <Item ID=\"0x2D99\"/>\n            <Item ID=\"0x2D9A\"/>\n            <Item ID=\"0x2D9B\"/>\n            <Item ID=\"0x2D9C\"/>\n        </Group>\n        <Group name=\"Mini Monsters UO:SE\">\n            <Item ID=\"0x2763\"/>\n            <Item ID=\"0x2764\"/>\n            <Item ID=\"0x2765\"/>\n            <Item ID=\"0x2766\"/>\n            <Item ID=\"0x2767\"/>\n            <Item ID=\"0x2768\"/>\n            <Item ID=\"0x2769\"/>\n            <Item ID=\"0x276A\"/>\n            <Item ID=\"0x276B\"/>\n            <Item ID=\"0x276C\"/>\n            <Item ID=\"0x276D\"/>\n            <Item ID=\"0x276E\"/>\n            <Item ID=\"0x276F\"/>\n            <Item ID=\"0x2770\"/>\n            <Item ID=\"0x2771\"/>\n            <Item ID=\"0x2772\"/>\n            <Item ID=\"0x2773\"/>\n            <Item ID=\"0x281B\"/>\n            <Item ID=\"0x281C\"/>\n        </Group>\n        <Group name=\"Spring\">\n            <Item ID=\"0x18d9\"/>\n            <Item ID=\"0x18da\"/>\n            <Item ID=\"0x1944\"/>\n            <Item ID=\"0x1945\"/>\n            <Item ID=\"0x1946\"/>\n            <Item ID=\"0x1947\"/>\n            <Item ID=\"0x1948\"/>\n            <Item ID=\"0x1949\"/>\n            <Item ID=\"0x194A\"/>\n            <Item ID=\"0x194B\"/>\n            <Item ID=\"0x194C\"/>\n            <Item ID=\"0x194D\"/>\n            <Item ID=\"0x194E\"/>\n            <Item ID=\"0x194F\"/>\n            <Item ID=\"0x1950\"/>\n            <Item ID=\"0x1951\"/>\n            <Item ID=\"0x1952\"/>\n            <Item ID=\"0x1953\"/>\n            <Item ID=\"0x1954\"/>\n            <Item ID=\"0x1956\"/>\n        </Group>\n        <Group name=\"Winter\">\n            <Group name=\"Santa Reindeer\">\n                <Item ID=\"0x3A55\"/>\n                <Item ID=\"0x3A56\"/>\n                <Item ID=\"0x3A57\"/>\n                <Item ID=\"0x3A58\"/>\n                <Item ID=\"0x3A59\"/>\n                <Item ID=\"0x3A5A\"/>\n                <Item ID=\"0x3A5B\"/>\n                <Item ID=\"0x3A5C\"/>\n                <Item ID=\"0x3A5D\"/>\n                <Item ID=\"0x3A5E\"/>\n                <Item ID=\"0x3A5F\"/>\n                <Item ID=\"0x3A60\"/>\n                <Item ID=\"0x3A61\"/>\n                <Item ID=\"0x3A62\"/>\n                <Item ID=\"0x3A63\"/>\n                <Item ID=\"0x3A64\"/>\n                <Item ID=\"0x3A65\"/>\n                <Item ID=\"0x3A66\"/>\n                <Item ID=\"0x3A67\"/>\n                <Item ID=\"0x3A68\"/>\n                <Item ID=\"0x3A69\"/>\n                <Item ID=\"0x3A6A\"/>\n                <Item ID=\"0x3A6B\"/>\n                <Item ID=\"0x3A6C\"/>\n            </Group>\n            <Group name=\"Santa Sleigh\">\n                <Item ID=\"0x3A73\"/>\n                <Item ID=\"0x3A74\"/>\n                <Item ID=\"0x3A76\"/>\n                <Item ID=\"0x3A77\"/>\n                <Item ID=\"0x3A7A\"/>\n                <Item ID=\"0x3A7C\"/>\n                <Item ID=\"0x3A7D\"/>\n                <Item ID=\"0x3A7E\"/>\n                <Item ID=\"0x3A80\"/>\n                <Item ID=\"0x3A81\"/>\n                <Item ID=\"0x3A84\"/>\n                <Item ID=\"0x3A86\"/>\n                <Item ID=\"0x3A87\"/>\n                <Item ID=\"0x3A88\"/>\n                <Item ID=\"0x3A8A\"/>\n                <Item ID=\"0x3A8B\"/>\n                <Item ID=\"0x3A8D\"/>\n                <Item ID=\"0x3A8E\"/>\n                <Item ID=\"0x3A90\"/>\n                <Item ID=\"0x3A91\"/>\n            </Group>\n            <Item ID=\"0x2328\"/>\n            <Item ID=\"0x2329\"/>\n            <Item ID=\"0x232A\"/>\n            <Item ID=\"0x232B\"/>\n            <Item ID=\"0x232C\"/>\n            <Item ID=\"0x232D\"/>\n            <Item ID=\"0x232E\"/>\n            <Item ID=\"0x232F\"/>\n            <Item ID=\"0x2332\"/>\n            <Item ID=\"0x2336\"/>\n            <Item ID=\"0x236e\"/>\n            <Item ID=\"0x236f\"/>\n            <Item ID=\"0x2374\"/>\n            <Item ID=\"0x2375\"/>\n            <Item ID=\"0x2376\"/>\n            <Item ID=\"0x2377\"/>\n            <Item ID=\"0x2378\"/>\n            <Item ID=\"0x2BD9\"/>\n            <Item ID=\"0x2BDA\"/>\n            <Item ID=\"0x2BDB\"/>\n            <Item ID=\"0x2BDC\"/>\n            <Item ID=\"0x2BDD\"/>\n            <Item ID=\"0x2BDE\"/>\n            <Item ID=\"0x2BDF\"/>\n            <Item ID=\"0x2BE0\"/>\n            <Item ID=\"0x2BE1\"/>\n            <Item ID=\"0x2BE2\"/>\n            <Item ID=\"0x2BE3\"/>\n            <Item ID=\"0x2BE4\"/>\n            <Item ID=\"0x2BE5\"/>\n            <Item ID=\"0x2BE6\"/>\n            <Item ID=\"0x2BE7\"/>\n            <Item ID=\"0x2b14\"/>\n            <Item ID=\"0x3BBb\"/>\n            <Item ID=\"0x3BBc\"/>\n        </Group>\n    </Group>\n    <Group name=\"Multipart\">\n        <Group name=\"Dolphin Rug East\">\n            <Item ID=\"0x38d9\"/>\n            <Item ID=\"0x38da\"/>\n            <Item ID=\"0x38db\"/>\n            <Item ID=\"0x38dc\"/>\n            <Item ID=\"0x38dd\"/>\n            <Item ID=\"0x38de\"/>\n            <Item ID=\"0x38df\"/>\n            <Item ID=\"0x38e0\"/>\n            <Item ID=\"0x38e1\"/>\n            <Item ID=\"0x38e2\"/>\n            <Item ID=\"0x38e3\"/>\n            <Item ID=\"0x38e4\"/>\n            <Item ID=\"0x38e5\"/>\n            <Item ID=\"0x38e6\"/>\n            <Item ID=\"0x38e7\"/>\n            <Item ID=\"0x38e8\"/>\n            <Item ID=\"0x38e9\"/>\n            <Item ID=\"0x38ea\"/>\n            <Item ID=\"0x38eb\"/>\n            <Item ID=\"0x38ec\"/>\n            <Item ID=\"0x38ed\"/>\n            <Item ID=\"0x38ee\"/>\n            <Item ID=\"0x38ef\"/>\n            <Item ID=\"0x38f0\"/>\n            <Item ID=\"0x38f1\"/>\n            <Item ID=\"0x38f2\"/>\n            <Item ID=\"0x38f3\"/>\n            <Item ID=\"0x38f4\"/>\n        </Group>\n        <Group name=\"Dolphin Rug S\">\n            <Item ID=\"0x38f5\"/>\n            <Item ID=\"0x38f6\"/>\n            <Item ID=\"0x38f7\"/>\n            <Item ID=\"0x38f8\"/>\n            <Item ID=\"0x38f9\"/>\n            <Item ID=\"0x38fa\"/>\n            <Item ID=\"0x38fb\"/>\n            <Item ID=\"0x38fc\"/>\n            <Item ID=\"0x38fd\"/>\n            <Item ID=\"0x38fe\"/>\n            <Item ID=\"0x38ff\"/>\n            <Item ID=\"0x3900\"/>\n            <Item ID=\"0x3901\"/>\n            <Item ID=\"0x3902\"/>\n            <Item ID=\"0x3903\"/>\n            <Item ID=\"0x3904\"/>\n            <Item ID=\"0x3905\"/>\n            <Item ID=\"0x3906\"/>\n            <Item ID=\"0x3907\"/>\n            <Item ID=\"0x3908\"/>\n            <Item ID=\"0x3909\"/>\n            <Item ID=\"0x390a\"/>\n            <Item ID=\"0x390b\"/>\n            <Item ID=\"0x390c\"/>\n            <Item ID=\"0x390d\"/>\n            <Item ID=\"0x390e\"/>\n            <Item ID=\"0x390f\"/>\n            <Item ID=\"0x3910\"/>\n        </Group>\n        <Group name=\"Japanese Gate\">\n            <Item ID=\"0x24AD\"/>\n            <Item ID=\"0x24AE\"/>\n            <Item ID=\"0x24AF\"/>\n            <Item ID=\"0x24B0\"/>\n            <Item ID=\"0x24B1\"/>\n            <Item ID=\"0x24B2\"/>\n            <Item ID=\"0x24B3\"/>\n            <Item ID=\"0x24B4\"/>\n            <Item ID=\"0x24B5\"/>\n            <Item ID=\"0x24B6\"/>\n            <Item ID=\"0x24B7\"/>\n            <Item ID=\"0x24B8\"/>\n            <Item ID=\"0x24B9\"/>\n            <Item ID=\"0x24BA\"/>\n        </Group>\n        <Group name=\"Lighthouse\">\n            <Item ID=\"0x1AA4\"/>\n            <Item ID=\"0x1AA5\"/>\n            <Item ID=\"0x1AA6\"/>\n            <Item ID=\"0x1AA7\"/>\n            <Item ID=\"0x1AA8\"/>\n            <Item ID=\"0x1AA9\"/>\n            <Item ID=\"0x1AAA\"/>\n            <Item ID=\"0x1AAB\"/>\n            <Item ID=\"0x1AAC\"/>\n            <Item ID=\"0x1AAD\"/>\n            <Item ID=\"0x1AAE\"/>\n            <Item ID=\"0x1AAF\"/>\n            <Item ID=\"0x1AB0\"/>\n            <Item ID=\"0x1AB1\"/>\n            <Item ID=\"0x1AB2\"/>\n            <Item ID=\"0x1AB3\"/>\n            <Item ID=\"0x1AB4\"/>\n            <Item ID=\"0x1AB5\"/>\n            <Item ID=\"0x1AB6\"/>\n            <Item ID=\"0x1AB7\"/>\n            <Item ID=\"0x1AB8\"/>\n            <Item ID=\"0x1AB9\"/>\n            <Item ID=\"0x1ABA\"/>\n            <Item ID=\"0x1ABB\"/>\n            <Item ID=\"0x1ABC\"/>\n            <Item ID=\"0x1ABD\"/>\n            <Item ID=\"0x1ABE\"/>\n            <Item ID=\"0x1ABF\"/>\n            <Item ID=\"0x1AC0\"/>\n            <Item ID=\"0x1AC1\"/>\n            <Item ID=\"0x1AC2\"/>\n            <Item ID=\"0x1AC3\"/>\n            <Item ID=\"0x1AC4\"/>\n            <Item ID=\"0x1AC5\"/>\n            <Item ID=\"0x1AC6\"/>\n            <Item ID=\"0x1AC7\"/>\n            <Item ID=\"0x1AC8\"/>\n            <Item ID=\"0x1AC9\"/>\n            <Item ID=\"0x1ACA\"/>\n            <Item ID=\"0x1ACB\"/>\n            <Item ID=\"0x1ACC\"/>\n            <Item ID=\"0x1ACD\"/>\n            <Item ID=\"0x1ACE\"/>\n            <Item ID=\"0x1ACF\"/>\n            <Item ID=\"0x1AD0\"/>\n            <Item ID=\"0x1AD1\"/>\n            <Item ID=\"0x1AD2\"/>\n        </Group>\n        <Group name=\"Rose Rug E\">\n            <Item ID=\"0x38a0\"/>\n            <Item ID=\"0x38a1\"/>\n            <Item ID=\"0x38a2\"/>\n            <Item ID=\"0x38a3\"/>\n            <Item ID=\"0x38a4\"/>\n            <Item ID=\"0x38a5\"/>\n            <Item ID=\"0x38a6\"/>\n            <Item ID=\"0x38a7\"/>\n            <Item ID=\"0x38a8\"/>\n            <Item ID=\"0x38a9\"/>\n            <Item ID=\"0x38aa\"/>\n            <Item ID=\"0x38ab\"/>\n            <Item ID=\"0x38ac\"/>\n            <Item ID=\"0x38ad\"/>\n            <Item ID=\"0x38ae\"/>\n            <Item ID=\"0x38af\"/>\n            <Item ID=\"0x38b0\"/>\n            <Item ID=\"0x38b1\"/>\n            <Item ID=\"0x38b2\"/>\n            <Item ID=\"0x38b3\"/>\n            <Item ID=\"0x38b4\"/>\n            <Item ID=\"0x38b5\"/>\n            <Item ID=\"0x38b6\"/>\n            <Item ID=\"0x38b7\"/>\n            <Item ID=\"0x38b8\"/>\n            <Item ID=\"0x38b9\"/>\n            <Item ID=\"0x38ba\"/>\n            <Item ID=\"0x38bb\"/>\n            <Item ID=\"0x38bc\"/>\n        </Group>\n        <Group name=\"Serpent Pillar\">\n            <Item ID=\"0x233C\"/>\n            <Item ID=\"0x233D\"/>\n            <Item ID=\"0x233E\"/>\n            <Item ID=\"0x233F\"/>\n            <Item ID=\"0x2340\"/>\n            <Item ID=\"0x2341\"/>\n            <Item ID=\"0x2342\"/>\n            <Item ID=\"0x2343\"/>\n            <Item ID=\"0x2344\"/>\n            <Item ID=\"0x2345\"/>\n            <Item ID=\"0x2346\"/>\n            <Item ID=\"0x2347\"/>\n            <Item ID=\"0x2348\"/>\n            <Item ID=\"0x2349\"/>\n            <Item ID=\"0x234A\"/>\n        </Group>\n        <Group name=\"Sieges\">\n            <Group name=\"Ballista\">\n                <Item ID=\"0x16FA\"/>\n                <Item ID=\"0x1701\"/>\n                <Item ID=\"0x3FC0\"/>\n                <Item ID=\"0x3FC8\"/>\n                <Item ID=\"0x3FCF\"/>\n                <Item ID=\"0x3FD0\"/>\n                <Item ID=\"0x3FD2\"/>\n                <Item ID=\"0x3FD4\"/>\n                <Item ID=\"0x3FD6\"/>\n                <Item ID=\"0x3FD8\"/>\n                <Item ID=\"0x3FDA\"/>\n                <Item ID=\"0x3FDC\"/>\n                <Item ID=\"0x3FDE\"/>\n                <Item ID=\"0x3FE0\"/>\n                <Item ID=\"0x3FE2\"/>\n                <Item ID=\"0x3FE3\"/>\n            </Group>\n            <Group name=\"Ballista\">\n                <Item ID=\"0x3F90\"/>\n                <Item ID=\"0x3F95\"/>\n                <Item ID=\"0x3F9D\"/>\n                <Item ID=\"0x3FA4\"/>\n                <Item ID=\"0x3FA5\"/>\n                <Item ID=\"0x3FA7\"/>\n                <Item ID=\"0x3FA9\"/>\n                <Item ID=\"0x3FAB\"/>\n                <Item ID=\"0x3FAD\"/>\n                <Item ID=\"0x3FAF\"/>\n                <Item ID=\"0x3FB1\"/>\n                <Item ID=\"0x3FB3\"/>\n                <Item ID=\"0x3FB5\"/>\n                <Item ID=\"0x3FB7\"/>\n                <Item ID=\"0x3FB8\"/>\n                <Item ID=\"0x3FB9\"/>\n            </Group>\n            <Group name=\"Ballista\">\n                <Item ID=\"0x189F\"/>\n                <Item ID=\"0x18A0\"/>\n                <Item ID=\"0x18A1\"/>\n                <Item ID=\"0x18A2\"/>\n                <Item ID=\"0x18A3\"/>\n                <Item ID=\"0x18A4\"/>\n                <Item ID=\"0x18A5\"/>\n                <Item ID=\"0x18A6\"/>\n                <Item ID=\"0x18A7\"/>\n                <Item ID=\"0x18A8\"/>\n                <Item ID=\"0x18A9\"/>\n                <Item ID=\"0x18AA\"/>\n                <Item ID=\"0x18AC\"/>\n                <Item ID=\"0x18B1\"/>\n                <Item ID=\"0x3F77\"/>\n            </Group>\n            <Group name=\"Ballista\">\n                <Item ID=\"0x18F0\"/>\n                <Item ID=\"0x18F1\"/>\n                <Item ID=\"0x18F2\"/>\n                <Item ID=\"0x18F3\"/>\n                <Item ID=\"0x18F4\"/>\n                <Item ID=\"0x18F6\"/>\n                <Item ID=\"0x18F7\"/>\n                <Item ID=\"0x18F8\"/>\n                <Item ID=\"0x18F9\"/>\n                <Item ID=\"0x18FA\"/>\n                <Item ID=\"0x18FB\"/>\n                <Item ID=\"0x18FC\"/>\n                <Item ID=\"0x1904\"/>\n                <Item ID=\"0x1909\"/>\n                <Item ID=\"0x3F5D\"/>\n            </Group>\n            <Group name=\"Ballista\">\n                <Item ID=\"0x18F1\"/>\n                <Item ID=\"0x18FD\"/>\n                <Item ID=\"0x18FE\"/>\n                <Item ID=\"0x18FF\"/>\n                <Item ID=\"0x1900\"/>\n                <Item ID=\"0x1901\"/>\n                <Item ID=\"0x1902\"/>\n                <Item ID=\"0x1903\"/>\n                <Item ID=\"0x3F3F\"/>\n                <Item ID=\"0x3F44\"/>\n                <Item ID=\"0x3F50\"/>\n                <Item ID=\"0x3F61\"/>\n                <Item ID=\"0x3F62\"/>\n                <Item ID=\"0x3F64\"/>\n            </Group>\n            <Group name=\"Ballista\">\n                <Item ID=\"0x16FA\"/>\n                <Item ID=\"0x16FE\"/>\n                <Item ID=\"0x16FF\"/>\n                <Item ID=\"0x1701\"/>\n                <Item ID=\"0x3FC0\"/>\n                <Item ID=\"0x3FC5\"/>\n                <Item ID=\"0x3FC7\"/>\n                <Item ID=\"0x3FCC\"/>\n                <Item ID=\"0x3FCD\"/>\n                <Item ID=\"0x3FCE\"/>\n                <Item ID=\"0x3FCF\"/>\n                <Item ID=\"0x3FE2\"/>\n                <Item ID=\"0x3FE3\"/>\n            </Group>\n            <Group name=\"Ballista\">\n                <Item ID=\"0x189F\"/>\n                <Item ID=\"0x18A0\"/>\n                <Item ID=\"0x18A1\"/>\n                <Item ID=\"0x18A2\"/>\n                <Item ID=\"0x18AC\"/>\n                <Item ID=\"0x18B1\"/>\n                <Item ID=\"0x18CE\"/>\n                <Item ID=\"0x18CF\"/>\n                <Item ID=\"0x18D0\"/>\n                <Item ID=\"0x18D1\"/>\n                <Item ID=\"0x3F71\"/>\n                <Item ID=\"0x3F72\"/>\n                <Item ID=\"0x3F77\"/>\n            </Group>\n            <Group name=\"Ballista\">\n                <Item ID=\"0x3F90\"/>\n                <Item ID=\"0x3F95\"/>\n                <Item ID=\"0x3F9A\"/>\n                <Item ID=\"0x3F9B\"/>\n                <Item ID=\"0x3F9C\"/>\n                <Item ID=\"0x3FA0\"/>\n                <Item ID=\"0x3FA1\"/>\n                <Item ID=\"0x3FA2\"/>\n                <Item ID=\"0x3FA3\"/>\n                <Item ID=\"0x3FA4\"/>\n                <Item ID=\"0x3FB7\"/>\n                <Item ID=\"0x3FB8\"/>\n                <Item ID=\"0x3FB9\"/>\n            </Group>\n            <Group name=\"Cannon\">\n                <Item ID=\"0x0E6B\"/>\n                <Item ID=\"0x0E6C\"/>\n                <Item ID=\"0x0E6D\"/>\n                <Item ID=\"0x0E6E\"/>\n                <Item ID=\"0x0E6F\"/>\n                <Item ID=\"0x0E70\"/>\n                <Item ID=\"0x0E71\"/>\n                <Item ID=\"0x0E72\"/>\n                <Item ID=\"0x0E73\"/>\n                <Item ID=\"0x0E74\"/>\n            </Group>\n            <Group name=\"Catapult\">\n                <Item ID=\"0x1694\"/>\n                <Item ID=\"0x1695\"/>\n                <Item ID=\"0x1696\"/>\n                <Item ID=\"0x1697\"/>\n                <Item ID=\"0x1698\"/>\n                <Item ID=\"0x1699\"/>\n                <Item ID=\"0x169A\"/>\n                <Item ID=\"0x169B\"/>\n                <Item ID=\"0x169C\"/>\n                <Item ID=\"0x169D\"/>\n                <Item ID=\"0x16A2\"/>\n                <Item ID=\"0x16A7\"/>\n                <Item ID=\"0x16AC\"/>\n                <Item ID=\"0x16B1\"/>\n            </Group>\n            <Group name=\"Catapult\">\n                <Item ID=\"0x16B9\"/>\n                <Item ID=\"0x16BA\"/>\n                <Item ID=\"0x16BB\"/>\n                <Item ID=\"0x16BC\"/>\n                <Item ID=\"0x16BD\"/>\n                <Item ID=\"0x16BE\"/>\n                <Item ID=\"0x16BF\"/>\n                <Item ID=\"0x16C0\"/>\n                <Item ID=\"0x16C1\"/>\n                <Item ID=\"0x16C2\"/>\n                <Item ID=\"0x16C7\"/>\n                <Item ID=\"0x16CC\"/>\n                <Item ID=\"0x16D1\"/>\n                <Item ID=\"0x16D6\"/>\n            </Group>\n            <Group name=\"Catapult\">\n                <Item ID=\"0x1648\"/>\n                <Item ID=\"0x1649\"/>\n                <Item ID=\"0x164A\"/>\n                <Item ID=\"0x164B\"/>\n                <Item ID=\"0x164C\"/>\n                <Item ID=\"0x164D\"/>\n                <Item ID=\"0x164E\"/>\n                <Item ID=\"0x164F\"/>\n                <Item ID=\"0x1654\"/>\n                <Item ID=\"0x1659\"/>\n                <Item ID=\"0x165E\"/>\n                <Item ID=\"0x1663\"/>\n            </Group>\n            <Group name=\"Catapult\">\n                <Item ID=\"0x1672\"/>\n                <Item ID=\"0x1673\"/>\n                <Item ID=\"0x1674\"/>\n                <Item ID=\"0x1675\"/>\n                <Item ID=\"0x1676\"/>\n                <Item ID=\"0x1677\"/>\n                <Item ID=\"0x1678\"/>\n                <Item ID=\"0x1679\"/>\n                <Item ID=\"0x167E\"/>\n                <Item ID=\"0x1683\"/>\n                <Item ID=\"0x1688\"/>\n                <Item ID=\"0x168E\"/>\n            </Group>\n        </Group>\n        <Group name=\"Skull Rug E\">\n            <Item ID=\"0x3869\"/>\n            <Item ID=\"0x386a\"/>\n            <Item ID=\"0x386b\"/>\n            <Item ID=\"0x386c\"/>\n            <Item ID=\"0x386d\"/>\n            <Item ID=\"0x386e\"/>\n            <Item ID=\"0x386f\"/>\n            <Item ID=\"0x3870\"/>\n            <Item ID=\"0x3871\"/>\n            <Item ID=\"0x3872\"/>\n            <Item ID=\"0x3873\"/>\n            <Item ID=\"0x3874\"/>\n            <Item ID=\"0x3875\"/>\n            <Item ID=\"0x3876\"/>\n            <Item ID=\"0x3877\"/>\n            <Item ID=\"0x3878\"/>\n            <Item ID=\"0x3879\"/>\n            <Item ID=\"0x387a\"/>\n            <Item ID=\"0x387b\"/>\n            <Item ID=\"0x387c\"/>\n            <Item ID=\"0x387d\"/>\n            <Item ID=\"0x387e\"/>\n            <Item ID=\"0x387f\"/>\n            <Item ID=\"0x3880\"/>\n            <Item ID=\"0x3881\"/>\n            <Item ID=\"0x3882\"/>\n            <Item ID=\"0x3883\"/>\n            <Item ID=\"0x3884\"/>\n        </Group>\n        <Group name=\"Skull Rug S\">\n            <Item ID=\"0x3885\"/>\n            <Item ID=\"0x3886\"/>\n            <Item ID=\"0x3887\"/>\n            <Item ID=\"0x3888\"/>\n            <Item ID=\"0x3889\"/>\n            <Item ID=\"0x388a\"/>\n            <Item ID=\"0x388b\"/>\n            <Item ID=\"0x388c\"/>\n            <Item ID=\"0x388d\"/>\n            <Item ID=\"0x388e\"/>\n            <Item ID=\"0x388f\"/>\n            <Item ID=\"0x3890\"/>\n            <Item ID=\"0x3891\"/>\n            <Item ID=\"0x3892\"/>\n            <Item ID=\"0x3893\"/>\n            <Item ID=\"0x3894\"/>\n            <Item ID=\"0x3895\"/>\n            <Item ID=\"0x3896\"/>\n            <Item ID=\"0x3897\"/>\n            <Item ID=\"0x3898\"/>\n            <Item ID=\"0x3899\"/>\n            <Item ID=\"0x389a\"/>\n            <Item ID=\"0x389b\"/>\n            <Item ID=\"0x389c\"/>\n            <Item ID=\"0x389d\"/>\n            <Item ID=\"0x389e\"/>\n            <Item ID=\"0x389f\"/>\n            <Item ID=\"0x38a0\"/>\n        </Group>\n        <Group name=\"Skull Rug S\">\n            <Item ID=\"0x38bd\"/>\n            <Item ID=\"0x38be\"/>\n            <Item ID=\"0x38bf\"/>\n            <Item ID=\"0x38c0\"/>\n            <Item ID=\"0x38c1\"/>\n            <Item ID=\"0x38c2\"/>\n            <Item ID=\"0x38c3\"/>\n            <Item ID=\"0x38c4\"/>\n            <Item ID=\"0x38c5\"/>\n            <Item ID=\"0x38c6\"/>\n            <Item ID=\"0x38c7\"/>\n            <Item ID=\"0x38c8\"/>\n            <Item ID=\"0x38c9\"/>\n            <Item ID=\"0x38ca\"/>\n            <Item ID=\"0x38cb\"/>\n            <Item ID=\"0x38cc\"/>\n            <Item ID=\"0x38cd\"/>\n            <Item ID=\"0x38ce\"/>\n            <Item ID=\"0x38cf\"/>\n            <Item ID=\"0x38d0\"/>\n            <Item ID=\"0x38d1\"/>\n            <Item ID=\"0x38d2\"/>\n            <Item ID=\"0x38d3\"/>\n            <Item ID=\"0x38d4\"/>\n            <Item ID=\"0x38d5\"/>\n            <Item ID=\"0x38d6\"/>\n            <Item ID=\"0x38d7\"/>\n            <Item ID=\"0x38d8\"/>\n        </Group>\n        <Group name=\"Telescope\">\n            <Item ID=\"0x1459\"/>\n            <Item ID=\"0x145A\"/>\n            <Item ID=\"0x145B\"/>\n            <Item ID=\"0x145C\"/>\n            <Item ID=\"0x145D\"/>\n            <Item ID=\"0x145E\"/>\n            <Item ID=\"0x145F\"/>\n            <Item ID=\"0x1460\"/>\n            <Item ID=\"0x1461\"/>\n            <Item ID=\"0x1462\"/>\n            <Item ID=\"0x1463\"/>\n            <Item ID=\"0x1464\"/>\n            <Item ID=\"0x1465\"/>\n            <Item ID=\"0x1466\"/>\n            <Item ID=\"0x1467\"/>\n            <Item ID=\"0x1468\"/>\n            <Item ID=\"0x1469\"/>\n            <Item ID=\"0x146A\"/>\n            <Item ID=\"0x146B\"/>\n            <Item ID=\"0x146D\"/>\n            <Item ID=\"0x146E\"/>\n            <Item ID=\"0x146F\"/>\n            <Item ID=\"0x1470\"/>\n            <Item ID=\"0x1471\"/>\n            <Item ID=\"0x1472\"/>\n            <Item ID=\"0x1473\"/>\n            <Item ID=\"0x1474\"/>\n            <Item ID=\"0x1475\"/>\n            <Item ID=\"0x1476\"/>\n            <Item ID=\"0x1477\"/>\n            <Item ID=\"0x1478\"/>\n            <Item ID=\"0x1479\"/>\n            <Item ID=\"0x147A\"/>\n            <Item ID=\"0x147B\"/>\n            <Item ID=\"0x147C\"/>\n            <Item ID=\"0x147D\"/>\n            <Item ID=\"0x147E\"/>\n            <Item ID=\"0x147F\"/>\n            <Item ID=\"0x1480\"/>\n            <Item ID=\"0x1481\"/>\n            <Item ID=\"0x1482\"/>\n            <Item ID=\"0x1483\"/>\n            <Item ID=\"0x1484\"/>\n            <Item ID=\"0x1485\"/>\n            <Item ID=\"0x1486\"/>\n            <Item ID=\"0x1487\"/>\n            <Item ID=\"0x1488\"/>\n            <Item ID=\"0x1489\"/>\n            <Item ID=\"0x148A\"/>\n            <Item ID=\"0x148B\"/>\n            <Item ID=\"0x148C\"/>\n            <Item ID=\"0x148D\"/>\n            <Item ID=\"0x148E\"/>\n            <Item ID=\"0x148F\"/>\n            <Item ID=\"0x1490\"/>\n            <Item ID=\"0x1491\"/>\n            <Item ID=\"0x1492\"/>\n            <Item ID=\"0x1493\"/>\n            <Item ID=\"0x1494\"/>\n            <Item ID=\"0x1495\"/>\n            <Item ID=\"0x1496\"/>\n            <Item ID=\"0x1497\"/>\n            <Item ID=\"0x1498\"/>\n            <Item ID=\"0x1499\"/>\n            <Item ID=\"0x149A\"/>\n        </Group>\n        <Group name=\"Vat + Ladder E\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14D8\"/>\n            <Item ID=\"0x14D9\"/>\n            <Item ID=\"0x14DB\"/>\n            <Item ID=\"0x14DC\"/>\n            <Item ID=\"0x14DD\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x14E2\"/>\n        </Group>\n        <Group name=\"Vat + Ladder S\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14D9\"/>\n            <Item ID=\"0x14DA\"/>\n            <Item ID=\"0x14DB\"/>\n            <Item ID=\"0x14DC\"/>\n            <Item ID=\"0x14DD\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x14E1\"/>\n        </Group>\n        <Group name=\"Vat\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14D8\"/>\n            <Item ID=\"0x14D9\"/>\n            <Item ID=\"0x14DA\"/>\n            <Item ID=\"0x14DB\"/>\n            <Item ID=\"0x14DC\"/>\n            <Item ID=\"0x14DD\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n        </Group>\n        <Group name=\"Water Vat + Ladder E\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x1550\"/>\n            <Item ID=\"0x1552\"/>\n            <Item ID=\"0x1553\"/>\n            <Item ID=\"0x1555\"/>\n            <Item ID=\"0x1558\"/>\n            <Item ID=\"0x1559\"/>\n        </Group>\n        <Group name=\"Water Vat + Ladder S\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x1551\"/>\n            <Item ID=\"0x1552\"/>\n            <Item ID=\"0x1553\"/>\n            <Item ID=\"0x1556\"/>\n            <Item ID=\"0x1558\"/>\n            <Item ID=\"0x1559\"/>\n        </Group>\n        <Group name=\"Water Vat\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x1550\"/>\n            <Item ID=\"0x1552\"/>\n            <Item ID=\"0x1553\"/>\n            <Item ID=\"0x1556\"/>\n            <Item ID=\"0x1558\"/>\n            <Item ID=\"0x1559\"/>\n        </Group>\n        <Group name=\"Wine Vat + Ladder E\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x151E\"/>\n            <Item ID=\"0x151F\"/>\n            <Item ID=\"0x1521\"/>\n            <Item ID=\"0x1522\"/>\n            <Item ID=\"0x1523\"/>\n            <Item ID=\"0x1525\"/>\n        </Group>\n        <Group name=\"Wine Vat + Ladder S\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x151E\"/>\n            <Item ID=\"0x1520\"/>\n            <Item ID=\"0x1521\"/>\n            <Item ID=\"0x1522\"/>\n            <Item ID=\"0x1523\"/>\n            <Item ID=\"0x1524\"/>\n        </Group>\n        <Group name=\"Wine Vat\">\n            <Item ID=\"0x14D7\"/>\n            <Item ID=\"0x14DE\"/>\n            <Item ID=\"0x14DF\"/>\n            <Item ID=\"0x151E\"/>\n            <Item ID=\"0x151F\"/>\n            <Item ID=\"0x1521\"/>\n            <Item ID=\"0x1522\"/>\n            <Item ID=\"0x1523\"/>\n            <Item ID=\"0x1524\"/>\n        </Group>\n    </Group>\n    <Group name=\"Nature\">\n        <Group name=\"Acid\">\n            <Group name=\"corners\">\n                <Item ID=\"0x2E02\"/>\n                <Item ID=\"0x2E03\"/>\n                <Item ID=\"0x2E04\"/>\n                <Item ID=\"0x2E05\"/>\n                <Item ID=\"0x2E06\"/>\n                <Item ID=\"0x2E07\"/>\n                <Item ID=\"0x2E08\"/>\n                <Item ID=\"0x2E09\"/>\n                <Item ID=\"0x2E0a\"/>\n                <Item ID=\"0x2E0b\"/>\n                <Item ID=\"0x2E0c\"/>\n                <Item ID=\"0x2E0d\"/>\n                <Item ID=\"0x2E0e\"/>\n                <Item ID=\"0x2E0f\"/>\n                <Item ID=\"0x2E10\"/>\n                <Item ID=\"0x2E11\"/>\n                <Item ID=\"0x2E12\"/>\n                <Item ID=\"0x2E13\"/>\n                <Item ID=\"0x2E14\"/>\n                <Item ID=\"0x2E15\"/>\n                <Item ID=\"0x2E16\"/>\n                <Item ID=\"0x2E17\"/>\n                <Item ID=\"0x2E18\"/>\n                <Item ID=\"0x2E19\"/>\n                <Item ID=\"0x2E1a\"/>\n                <Item ID=\"0x2E1b\"/>\n                <Item ID=\"0x2E1c\"/>\n                <Item ID=\"0x2E1d\"/>\n                <Item ID=\"0x2E1e\"/>\n                <Item ID=\"0x2E1f\"/>\n                <Item ID=\"0x2E20\"/>\n                <Item ID=\"0x2E21\"/>\n                <Item ID=\"0x2E22\"/>\n                <Item ID=\"0x2E23\"/>\n                <Item ID=\"0x2E24\"/>\n                <Item ID=\"0x2E25\"/>\n                <Item ID=\"0x2E26\"/>\n                <Item ID=\"0x2E27\"/>\n                <Item ID=\"0x2E28\"/>\n                <Item ID=\"0x2E29\"/>\n            </Group>\n            <Item ID=\"0x2E2a\"/>\n            <Item ID=\"0x2E2b\"/>\n            <Item ID=\"0x2E2c\"/>\n            <Item ID=\"0x2E2d\"/>\n            <Item ID=\"0x2E2e\"/>\n            <Item ID=\"0x2E2f\"/>\n            <Item ID=\"0x2E30\"/>\n            <Item ID=\"0x2E31\"/>\n            <Item ID=\"0x2E32\"/>\n            <Item ID=\"0x2E33\"/>\n            <Item ID=\"0x2E34\"/>\n            <Item ID=\"0x2E35\"/>\n            <Item ID=\"0x2E36\"/>\n            <Item ID=\"0x2E37\"/>\n            <Item ID=\"0x2E38\"/>\n            <Item ID=\"0x2E39\"/>\n            <Item ID=\"0x2E3a\"/>\n            <Item ID=\"0x2E3b\"/>\n        </Group>\n        <Group name=\"Cave\">\n            <Group name=\"Cave Drawings\">\n                <Item ID=\"0x2F62\"/>\n                <Item ID=\"0x2F63\"/>\n                <Item ID=\"0x2F64\"/>\n                <Item ID=\"0x2F65\"/>\n                <Item ID=\"0x2F66\"/>\n                <Item ID=\"0x2F67\"/>\n                <Item ID=\"0x2F68\"/>\n                <Item ID=\"0x2F69\"/>\n                <Item ID=\"0x2F6a\"/>\n                <Item ID=\"0x2F6b\"/>\n                <Item ID=\"0x2F6c\"/>\n                <Item ID=\"0x2F6d\"/>\n                <Item ID=\"0x2F6e\"/>\n                <Item ID=\"0x2F6f\"/>\n                <Item ID=\"0x2F70\"/>\n                <Item ID=\"0x2F71\"/>\n                <Item ID=\"0x2F72\"/>\n                <Item ID=\"0x2F73\"/>\n                <Item ID=\"0x2F74\"/>\n                <Item ID=\"0x2F75\"/>\n                <Item ID=\"0x2F76\"/>\n                <Item ID=\"0x2F77\"/>\n                <Item ID=\"0x2F78\"/>\n                <Item ID=\"0x2F79\"/>\n                <Item ID=\"0x2F7a\"/>\n                <Item ID=\"0x2F7b\"/>\n                <Item ID=\"0x2F7c\"/>\n                <Item ID=\"0x2F7d\"/>\n                <Item ID=\"0x2F7e\"/>\n                <Item ID=\"0x2F7f\"/>\n                <Item ID=\"0x2F80\"/>\n                <Item ID=\"0x2F81\"/>\n                <Item ID=\"0x2F82\"/>\n                <Item ID=\"0x2F83\"/>\n                <Item ID=\"0x2F84\"/>\n                <Item ID=\"0x2F85\"/>\n                <Item ID=\"0x2F86\"/>\n                <Item ID=\"0x2F87\"/>\n                <Item ID=\"0x2F88\"/>\n                <Item ID=\"0x2F89\"/>\n                <Item ID=\"0x2F8a\"/>\n                <Item ID=\"0x2F8b\"/>\n                <Item ID=\"0x2F8c\"/>\n                <Item ID=\"0x2F8d\"/>\n                <Item ID=\"0x2F8e\"/>\n                <Item ID=\"0x2F8f\"/>\n                <Item ID=\"0x2F90\"/>\n                <Item ID=\"0x2F91\"/>\n                <Item ID=\"0x2F92\"/>\n                <Item ID=\"0x2F93\"/>\n                <Item ID=\"0x2F94\"/>\n                <Item ID=\"0x2F95\"/>\n                <Item ID=\"0x2F96\"/>\n                <Item ID=\"0x2F97\"/>\n                <Item ID=\"0x2F98\"/>\n                <Item ID=\"0x2F99\"/>\n                <Item ID=\"0x2F9a\"/>\n                <Item ID=\"0x2F9b\"/>\n                <Item ID=\"0x2F9c\"/>\n                <Item ID=\"0x2F9d\"/>\n                <Item ID=\"0x2F9e\"/>\n                <Item ID=\"0x2F9f\"/>\n                <Item ID=\"0x2Fa0\"/>\n                <Item ID=\"0x2Fa1\"/>\n                <Item ID=\"0x2Fa2\"/>\n                <Item ID=\"0x2Fa3\"/>\n                <Item ID=\"0x2Fa4\"/>\n                <Item ID=\"0x2Fa5\"/>\n                <Item ID=\"0x2Fa6\"/>\n                <Item ID=\"0x2Fa7\"/>\n                <Item ID=\"0x2Fa8\"/>\n                <Item ID=\"0x2Fa9\"/>\n                <Item ID=\"0x2Faa\"/>\n                <Item ID=\"0x2Fab\"/>\n                <Item ID=\"0x2Fac\"/>\n                <Item ID=\"0x2Fad\"/>\n                <Item ID=\"0x2Fae\"/>\n                <Item ID=\"0x2Faf\"/>\n                <Item ID=\"0x2Fb0\"/>\n                <Item ID=\"0x2Fb1\"/>\n                <Item ID=\"0x2Fb2\"/>\n                <Item ID=\"0x2Fb3\"/>\n                <Item ID=\"0x2Fb4\"/>\n                <Item ID=\"0x2Fb5\"/>\n            </Group>\n            <Group name=\"Cave Steps\">\n                <Item ID=\"0x079D\"/>\n                <Item ID=\"0x079E\"/>\n                <Item ID=\"0x079F\"/>\n                <Item ID=\"0x07B0\"/>\n                <Item ID=\"0x07B1\"/>\n                <Item ID=\"0x07B2\"/>\n                <Item ID=\"0x07B7\"/>\n                <Item ID=\"0x07B8\"/>\n                <Item ID=\"0x07B9\"/>\n            </Group>\n            <Group name=\"Cave Wall\">\n                <Item ID=\"0x025C\"/>\n                <Item ID=\"0x025D\"/>\n                <Item ID=\"0x025E\"/>\n                <Item ID=\"0x025F\"/>\n                <Item ID=\"0x0260\"/>\n                <Item ID=\"0x0261\"/>\n                <Item ID=\"0x0262\"/>\n                <Item ID=\"0x0263\"/>\n                <Item ID=\"0x0264\"/>\n                <Item ID=\"0x0265\"/>\n                <Item ID=\"0x0266\"/>\n                <Item ID=\"0x0267\"/>\n                <Item ID=\"0x0268\"/>\n                <Item ID=\"0x0269\"/>\n                <Item ID=\"0x026A\"/>\n                <Item ID=\"0x026B\"/>\n                <Item ID=\"0x026C\"/>\n                <Item ID=\"0x026D\"/>\n                <Item ID=\"0x026E\"/>\n                <Item ID=\"0x026F\"/>\n                <Item ID=\"0x0270\"/>\n                <Item ID=\"0x0271\"/>\n                <Item ID=\"0x0272\"/>\n                <Item ID=\"0x0273\"/>\n                <Item ID=\"0x0274\"/>\n                <Item ID=\"0x0275\"/>\n                <Item ID=\"0x0276\"/>\n                <Item ID=\"0x027D\"/>\n                <Item ID=\"0x027E\"/>\n                <Item ID=\"0x027F\"/>\n                <Item ID=\"0x0280\"/>\n                <Item ID=\"0x08E0\"/>\n                <Item ID=\"0x08E1\"/>\n                <Item ID=\"0x08E2\"/>\n                <Item ID=\"0x08E3\"/>\n                <Item ID=\"0x08E4\"/>\n                <Item ID=\"0x08E5\"/>\n                <Item ID=\"0x08E6\"/>\n                <Item ID=\"0x08E7\"/>\n                <Item ID=\"0x08E8\"/>\n                <Item ID=\"0x08E9\"/>\n                <Item ID=\"0x08EA\"/>\n                <Item ID=\"0x2166\"/>\n                <Item ID=\"0x2167\"/>\n                <Item ID=\"0x2168\"/>\n                <Item ID=\"0x216a\"/>\n                <Item ID=\"0x3539\"/>\n                <Item ID=\"0x353a\"/>\n                <Item ID=\"0x353b\"/>\n                <Item ID=\"0x353c\"/>\n            </Group>\n            <Group name=\"Corners\">\n                <Item ID=\"0x0540\"/>\n                <Item ID=\"0x0541\"/>\n                <Item ID=\"0x0542\"/>\n                <Item ID=\"0x0543\"/>\n                <Item ID=\"0x0544\"/>\n                <Item ID=\"0x0545\"/>\n                <Item ID=\"0x0546\"/>\n                <Item ID=\"0x0547\"/>\n                <Item ID=\"0x0548\"/>\n                <Item ID=\"0x0549\"/>\n                <Item ID=\"0x054A\"/>\n                <Item ID=\"0x054B\"/>\n                <Item ID=\"0x054C\"/>\n                <Item ID=\"0x054D\"/>\n                <Item ID=\"0x054E\"/>\n                <Item ID=\"0x054F\"/>\n                <Item ID=\"0x0551\"/>\n                <Item ID=\"0x0552\"/>\n                <Item ID=\"0x0553\"/>\n                <Item ID=\"0x056A\"/>\n            </Group>\n            <Item ID=\"0x040B\"/>\n            <Item ID=\"0x040C\"/>\n            <Item ID=\"0x040D\"/>\n            <Item ID=\"0x040E\"/>\n            <Item ID=\"0x040F\"/>\n            <Item ID=\"0x0410\"/>\n            <Item ID=\"0x0411\"/>\n            <Item ID=\"0x0412\"/>\n            <Item ID=\"0x0413\"/>\n            <Item ID=\"0x0414\"/>\n            <Item ID=\"0x0415\"/>\n            <Item ID=\"0x0416\"/>\n            <Item ID=\"0x0417\"/>\n            <Item ID=\"0x0418\"/>\n            <Item ID=\"0x0419\"/>\n            <Item ID=\"0x041A\"/>\n            <Item ID=\"0x041B\"/>\n            <Item ID=\"0x041C\"/>\n            <Item ID=\"0x041D\"/>\n            <Item ID=\"0x041E\"/>\n            <Item ID=\"0x053B\"/>\n            <Item ID=\"0x053c\"/>\n            <Item ID=\"0x053d\"/>\n            <Item ID=\"0x053e\"/>\n            <Item ID=\"0x053f\"/>\n        </Group>\n        <Group name=\"Dirt\">\n            <Item ID=\"0x1B27\"/>\n            <Item ID=\"0x1B28\"/>\n            <Item ID=\"0x1B29\"/>\n            <Item ID=\"0x1B2A\"/>\n            <Item ID=\"0x1B2B\"/>\n            <Item ID=\"0x1B2C\"/>\n            <Item ID=\"0x1B2D\"/>\n            <Item ID=\"0x1B2E\"/>\n            <Item ID=\"0x1B2F\"/>\n            <Item ID=\"0x1B30\"/>\n            <Item ID=\"0x1B31\"/>\n            <Item ID=\"0x1B32\"/>\n            <Item ID=\"0x1B33\"/>\n            <Item ID=\"0x1B34\"/>\n            <Item ID=\"0x1B35\"/>\n            <Item ID=\"0x1B36\"/>\n            <Item ID=\"0x1B37\"/>\n            <Item ID=\"0x1B38\"/>\n            <Item ID=\"0x1B39\"/>\n            <Item ID=\"0x1B3A\"/>\n            <Item ID=\"0x1B3B\"/>\n            <Item ID=\"0x1B3C\"/>\n            <Item ID=\"0x1B3D\"/>\n            <Item ID=\"0x1B3E\"/>\n            <Item ID=\"0x31F4\"/>\n            <Item ID=\"0x31F5\"/>\n            <Item ID=\"0x31F6\"/>\n            <Item ID=\"0x31F7\"/>\n            <Item ID=\"0x31F8\"/>\n            <Item ID=\"0x31F9\"/>\n            <Item ID=\"0x31Fa\"/>\n            <Item ID=\"0x31Fb\"/>\n            <Item ID=\"0x32c9\"/>\n            <Item ID=\"0x32ca\"/>\n        </Group>\n        <Group name=\"Flora + Fauna\">\n            <Group name=\"Broad Trees\">\n                <Item ID=\"0x30bd\"/>\n                <Item ID=\"0x30be\"/>\n                <Item ID=\"0x30bf\"/>\n                <Item ID=\"0x30c0\"/>\n                <Item ID=\"0x30c1\"/>\n                <Item ID=\"0x30c2\"/>\n                <Item ID=\"0x30c3\"/>\n                <Item ID=\"0x30c4\"/>\n                <Item ID=\"0x30c5\"/>\n                <Item ID=\"0x30c6\"/>\n                <Item ID=\"0x30c7\"/>\n                <Item ID=\"0x30c8\"/>\n                <Item ID=\"0x30c9\"/>\n                <Item ID=\"0x30ca\"/>\n                <Item ID=\"0x30cb\"/>\n                <Item ID=\"0x30cc\"/>\n                <Item ID=\"0x30cd\"/>\n                <Item ID=\"0x30ce\"/>\n                <Item ID=\"0x30cf\"/>\n                <Item ID=\"0x30d0\"/>\n                <Item ID=\"0x30d1\"/>\n                <Item ID=\"0x30d2\"/>\n                <Item ID=\"0x30d3\"/>\n                <Item ID=\"0x30d4\"/>\n                <Item ID=\"0x30d5\"/>\n                <Item ID=\"0x30d6\"/>\n                <Item ID=\"0x30d7\"/>\n                <Item ID=\"0x30d8\"/>\n                <Item ID=\"0x30d9\"/>\n                <Item ID=\"0x30da\"/>\n                <Item ID=\"0x30db\"/>\n                <Item ID=\"0x30dc\"/>\n                <Item ID=\"0x30dd\"/>\n                <Item ID=\"0x30de\"/>\n            </Group>\n            <Group name=\"Desert\">\n                <Item ID=\"0x0C93\"/>\n                <Item ID=\"0x0C94\"/>\n                <Item ID=\"0x0C95\"/>\n                <Item ID=\"0x0C96\"/>\n                <Item ID=\"0x0C97\"/>\n                <Item ID=\"0x0C98\"/>\n                <Item ID=\"0x0C99\"/>\n                <Item ID=\"0x0C9A\"/>\n                <Item ID=\"0x0C9B\"/>\n                <Item ID=\"0x0C9C\"/>\n                <Item ID=\"0x0C9D\"/>\n                <Item ID=\"0x0C9E\"/>\n                <Item ID=\"0x0CA5\"/>\n                <Item ID=\"0x0CA6\"/>\n                <Item ID=\"0x0CA7\"/>\n                <Item ID=\"0x0CA8\"/>\n                <Item ID=\"0x0CA9\"/>\n                <Item ID=\"0x0CAA\"/>\n                <Item ID=\"0x0CAB\"/>\n                <Item ID=\"0x0CC4\"/>\n                <Item ID=\"0x0CC5\"/>\n                <Item ID=\"0x0CC6\"/>\n                <Item ID=\"0x0CC7\"/>\n                <Item ID=\"0x0D25\"/>\n                <Item ID=\"0x0D26\"/>\n                <Item ID=\"0x0D27\"/>\n                <Item ID=\"0x0D28\"/>\n                <Item ID=\"0x0D2A\"/>\n                <Item ID=\"0x0D2C\"/>\n                <Item ID=\"0x0D2E\"/>\n                <Item ID=\"0x0D30\"/>\n                <Item ID=\"0x0D31\"/>\n                <Item ID=\"0x0D32\"/>\n                <Item ID=\"0x0D33\"/>\n                <Item ID=\"0x0D35\"/>\n                <Item ID=\"0x0D37\"/>\n                <Item ID=\"0x0D38\"/>\n                <Item ID=\"0x0D3F\"/>\n                <Item ID=\"0x0D40\"/>\n                <Item ID=\"0x0Dc4\"/>\n                <Item ID=\"0x0Dc5\"/>\n                <Item ID=\"0x3020\"/>\n                <Item ID=\"0x3021\"/>\n                <Item ID=\"0x3022\"/>\n                <Item ID=\"0x3023\"/>\n                <Item ID=\"0x3024\"/>\n            </Group>\n            <Group name=\"Flowers\">\n                <Item ID=\"0x0C37\"/>\n                <Item ID=\"0x0C38\"/>\n                <Item ID=\"0x0C45\"/>\n                <Item ID=\"0x0C46\"/>\n                <Item ID=\"0x0C47\"/>\n                <Item ID=\"0x0C48\"/>\n                <Item ID=\"0x0C49\"/>\n                <Item ID=\"0x0C4A\"/>\n                <Item ID=\"0x0C4b\"/>\n                <Item ID=\"0x0C4c\"/>\n                <Item ID=\"0x0C4d\"/>\n                <Item ID=\"0x0C4e\"/>\n                <Item ID=\"0x0D29\"/>\n                <Item ID=\"0x0D2B\"/>\n                <Item ID=\"0x0D2D\"/>\n                <Item ID=\"0x0D2F\"/>\n                <Item ID=\"0x0D34\"/>\n                <Item ID=\"0x0D36\"/>\n                <Item ID=\"0x0c83\"/>\n                <Item ID=\"0x0c84\"/>\n                <Item ID=\"0x0c85\"/>\n                <Item ID=\"0x0c86\"/>\n                <Item ID=\"0x0c87\"/>\n                <Item ID=\"0x0c88\"/>\n                <Item ID=\"0x0c89\"/>\n                <Item ID=\"0x0c8a\"/>\n                <Item ID=\"0x0c8b\"/>\n                <Item ID=\"0x0c8c\"/>\n                <Item ID=\"0x0c8d\"/>\n                <Item ID=\"0x0c8e\"/>\n                <Item ID=\"0x0cbe\"/>\n                <Item ID=\"0x0cbf\"/>\n                <Item ID=\"0x0cc0\"/>\n                <Item ID=\"0x0cc1\"/>\n                <Item ID=\"0x18DF\"/>\n                <Item ID=\"0x18E0\"/>\n                <Item ID=\"0x18E1\"/>\n                <Item ID=\"0x18E2\"/>\n                <Item ID=\"0x18E5\"/>\n                <Item ID=\"0x18E6\"/>\n                <Item ID=\"0x18E9\"/>\n                <Item ID=\"0x18EA\"/>\n                <Item ID=\"0x1f0d\"/>\n                <Item ID=\"0x1f0e\"/>\n                <Item ID=\"0x1f0f\"/>\n                <Item ID=\"0x1f10\"/>\n                <Item ID=\"0x1f11\"/>\n                <Item ID=\"0x1f12\"/>\n                <Item ID=\"0x234b\"/>\n                <Item ID=\"0x234c\"/>\n                <Item ID=\"0x234d\"/>\n            </Group>\n            <Group name=\"Fruit Trees\">\n                <Group name=\"Miniatures\">\n                    <Item ID=\"0x3128\"/>\n                    <Item ID=\"0x3129\"/>\n                    <Item ID=\"0x312a\"/>\n                    <Item ID=\"0x3f07\"/>\n                    <Item ID=\"0x3f0c\"/>\n                    <Item ID=\"0x3f16\"/>\n                </Group>\n                <Item ID=\"0x0CE0\"/>\n                <Item ID=\"0x0CE1\"/>\n                <Item ID=\"0x0CE2\"/>\n                <Item ID=\"0x0CE3\"/>\n                <Item ID=\"0x0CE4\"/>\n                <Item ID=\"0x0CE5\"/>\n                <Item ID=\"0x0D94\"/>\n                <Item ID=\"0x0D95\"/>\n                <Item ID=\"0x0D96\"/>\n                <Item ID=\"0x0D97\"/>\n                <Item ID=\"0x0D98\"/>\n                <Item ID=\"0x0D99\"/>\n                <Item ID=\"0x0D9A\"/>\n                <Item ID=\"0x0D9B\"/>\n                <Item ID=\"0x0D9C\"/>\n                <Item ID=\"0x0D9D\"/>\n                <Item ID=\"0x0D9E\"/>\n                <Item ID=\"0x0D9F\"/>\n                <Item ID=\"0x0DA0\"/>\n                <Item ID=\"0x0DA1\"/>\n                <Item ID=\"0x0DA2\"/>\n                <Item ID=\"0x0DA3\"/>\n                <Item ID=\"0x0DA4\"/>\n                <Item ID=\"0x0DA5\"/>\n                <Item ID=\"0x0DA6\"/>\n                <Item ID=\"0x0DA7\"/>\n                <Item ID=\"0x0DA8\"/>\n                <Item ID=\"0x0DA9\"/>\n                <Item ID=\"0x0DAA\"/>\n                <Item ID=\"0x0DAB\"/>\n                <Item ID=\"0x2471\"/>\n                <Item ID=\"0x2472\"/>\n                <Item ID=\"0x2473\"/>\n                <Item ID=\"0x2474\"/>\n                <Item ID=\"0x2475\"/>\n                <Item ID=\"0x2476\"/>\n                <Item ID=\"0x2477\"/>\n                <Item ID=\"0x26ed\"/>\n                <Item ID=\"0x26ee\"/>\n                <Item ID=\"0x26ef\"/>\n                <Item ID=\"0x26f0\"/>\n                <Item ID=\"0x26f1\"/>\n                <Item ID=\"0x26f2\"/>\n                <Item ID=\"0x26f3\"/>\n                <Item ID=\"0x3122\"/>\n                <Item ID=\"0x3123\"/>\n                <Item ID=\"0x3124\"/>\n                <Item ID=\"0x36a0\"/>\n            </Group>\n            <Group name=\"Hedge, Grass, Ferns\">\n                <Item ID=\"0x0C8F\"/>\n                <Item ID=\"0x0C90\"/>\n                <Item ID=\"0x0C91\"/>\n                <Item ID=\"0x0C92\"/>\n                <Item ID=\"0x0C9F\"/>\n                <Item ID=\"0x0CA0\"/>\n                <Item ID=\"0x0CA1\"/>\n                <Item ID=\"0x0CA2\"/>\n                <Item ID=\"0x0CA3\"/>\n                <Item ID=\"0x0CA4\"/>\n                <Item ID=\"0x0CAC\"/>\n                <Item ID=\"0x0CAD\"/>\n                <Item ID=\"0x0CAE\"/>\n                <Item ID=\"0x0CAF\"/>\n                <Item ID=\"0x0CB0\"/>\n                <Item ID=\"0x0CB1\"/>\n                <Item ID=\"0x0CB2\"/>\n                <Item ID=\"0x0CB3\"/>\n                <Item ID=\"0x0CB4\"/>\n                <Item ID=\"0x0CB5\"/>\n                <Item ID=\"0x0CB6\"/>\n                <Item ID=\"0x0CBC\"/>\n                <Item ID=\"0x0CBD\"/>\n                <Item ID=\"0x0CC3\"/>\n                <Item ID=\"0x0DB8\"/>\n                <Item ID=\"0x0DB9\"/>\n            </Group>\n            <Group name=\"Misc Nature\">\n                <Item ID=\"0x0CF3\"/>\n                <Item ID=\"0x0CF4\"/>\n                <Item ID=\"0x0CF5\"/>\n                <Item ID=\"0x0CF6\"/>\n                <Item ID=\"0x0CF7\"/>\n                <Item ID=\"0x0D3B\"/>\n                <Item ID=\"0x0D3C\"/>\n                <Item ID=\"0x0D3D\"/>\n                <Item ID=\"0x0DAC\"/>\n                <Item ID=\"0x0DAD\"/>\n                <Item ID=\"0x0E56\"/>\n                <Item ID=\"0x0E57\"/>\n                <Item ID=\"0x0E58\"/>\n                <Item ID=\"0x0E59\"/>\n                <Item ID=\"0x1Ad4\"/>\n                <Item ID=\"0x1Ad5\"/>\n                <Item ID=\"0x1B1F\"/>\n                <Item ID=\"0x1B20\"/>\n                <Item ID=\"0x1B21\"/>\n                <Item ID=\"0x1B22\"/>\n                <Item ID=\"0x1B23\"/>\n                <Item ID=\"0x1B24\"/>\n                <Item ID=\"0x1B25\"/>\n                <Item ID=\"0x1B26\"/>\n                <Item ID=\"0x1B81\"/>\n                <Item ID=\"0x1B82\"/>\n                <Item ID=\"0x1B83\"/>\n                <Item ID=\"0x1B84\"/>\n                <Item ID=\"0x1B85\"/>\n                <Item ID=\"0x1B86\"/>\n                <Item ID=\"0x1B87\"/>\n                <Item ID=\"0x1B88\"/>\n                <Item ID=\"0x1B89\"/>\n                <Item ID=\"0x1B8A\"/>\n                <Item ID=\"0x1B8B\"/>\n                <Item ID=\"0x1B8C\"/>\n                <Item ID=\"0x1B8D\"/>\n                <Item ID=\"0x1B8E\"/>\n                <Item ID=\"0x1B8F\"/>\n                <Item ID=\"0x1B90\"/>\n                <Item ID=\"0x1B91\"/>\n                <Item ID=\"0x1B92\"/>\n                <Item ID=\"0x1B93\"/>\n                <Item ID=\"0x1B97\"/>\n                <Item ID=\"0x1B98\"/>\n                <Item ID=\"0x1B99\"/>\n                <Item ID=\"0x1B9A\"/>\n                <Item ID=\"0x1B9B\"/>\n                <Item ID=\"0x1B9C\"/>\n                <Item ID=\"0x1B9D\"/>\n                <Item ID=\"0x1B9E\"/>\n                <Item ID=\"0x2232\"/>\n                <Item ID=\"0x2233\"/>\n            </Group>\n            <Group name=\"Mushroom\">\n                <Item ID=\"0x0D0C\"/>\n                <Item ID=\"0x0D0D\"/>\n                <Item ID=\"0x0D0E\"/>\n                <Item ID=\"0x0D0F\"/>\n                <Item ID=\"0x0D10\"/>\n                <Item ID=\"0x0D11\"/>\n                <Item ID=\"0x0D11\"/>\n                <Item ID=\"0x0D12\"/>\n                <Item ID=\"0x0D12\"/>\n                <Item ID=\"0x0D13\"/>\n                <Item ID=\"0x0D14\"/>\n                <Item ID=\"0x0D15\"/>\n                <Item ID=\"0x0D16\"/>\n                <Item ID=\"0x0D17\"/>\n                <Item ID=\"0x0D18\"/>\n                <Item ID=\"0x0D19\"/>\n                <Item ID=\"0x222E\"/>\n                <Item ID=\"0x222F\"/>\n                <Item ID=\"0x2230\"/>\n                <Item ID=\"0x2231\"/>\n            </Group>\n            <Group name=\"Tall Trees\">\n                <Item ID=\"0x0D41\"/>\n                <Item ID=\"0x0D42\"/>\n                <Item ID=\"0x0D43\"/>\n                <Item ID=\"0x0D44\"/>\n                <Item ID=\"0x0D45\"/>\n                <Item ID=\"0x0D46\"/>\n                <Item ID=\"0x0D47\"/>\n                <Item ID=\"0x0D48\"/>\n                <Item ID=\"0x0D49\"/>\n                <Item ID=\"0x0D4A\"/>\n                <Item ID=\"0x0D4B\"/>\n                <Item ID=\"0x0D4C\"/>\n                <Item ID=\"0x0D4D\"/>\n                <Item ID=\"0x0D4E\"/>\n                <Item ID=\"0x0D4F\"/>\n                <Item ID=\"0x0D50\"/>\n                <Item ID=\"0x0D51\"/>\n                <Item ID=\"0x0D52\"/>\n                <Item ID=\"0x0D53\"/>\n                <Item ID=\"0x0D54\"/>\n                <Item ID=\"0x0D55\"/>\n                <Item ID=\"0x0D56\"/>\n                <Item ID=\"0x0D57\"/>\n                <Item ID=\"0x0D58\"/>\n                <Item ID=\"0x0D59\"/>\n                <Item ID=\"0x0D5A\"/>\n                <Item ID=\"0x0D5B\"/>\n                <Item ID=\"0x0D5C\"/>\n                <Item ID=\"0x0D5D\"/>\n                <Item ID=\"0x0D5E\"/>\n                <Item ID=\"0x0D5F\"/>\n                <Item ID=\"0x0D60\"/>\n                <Item ID=\"0x0D61\"/>\n                <Item ID=\"0x0D62\"/>\n                <Item ID=\"0x0D63\"/>\n                <Item ID=\"0x0D64\"/>\n                <Item ID=\"0x0D65\"/>\n                <Item ID=\"0x0D66\"/>\n                <Item ID=\"0x0D67\"/>\n                <Item ID=\"0x0D68\"/>\n                <Item ID=\"0x0D69\"/>\n                <Item ID=\"0x0D6A\"/>\n                <Item ID=\"0x0D6B\"/>\n                <Item ID=\"0x0D6C\"/>\n                <Item ID=\"0x0D6D\"/>\n                <Item ID=\"0x0D6E\"/>\n                <Item ID=\"0x0D6F\"/>\n                <Item ID=\"0x0D70\"/>\n                <Item ID=\"0x0D71\"/>\n                <Item ID=\"0x0D72\"/>\n                <Item ID=\"0x0D73\"/>\n                <Item ID=\"0x0D74\"/>\n                <Item ID=\"0x0D75\"/>\n                <Item ID=\"0x0D76\"/>\n                <Item ID=\"0x0D77\"/>\n                <Item ID=\"0x0D78\"/>\n                <Item ID=\"0x0D79\"/>\n                <Item ID=\"0x0D7A\"/>\n                <Item ID=\"0x0D7B\"/>\n                <Item ID=\"0x0D7C\"/>\n                <Item ID=\"0x0D7D\"/>\n                <Item ID=\"0x0D7E\"/>\n                <Item ID=\"0x0D7F\"/>\n                <Item ID=\"0x0D80\"/>\n                <Item ID=\"0x0D81\"/>\n                <Item ID=\"0x0D82\"/>\n                <Item ID=\"0x0D83\"/>\n                <Item ID=\"0x0D84\"/>\n                <Item ID=\"0x0D85\"/>\n                <Item ID=\"0x0D86\"/>\n                <Item ID=\"0x0D87\"/>\n                <Item ID=\"0x0D88\"/>\n                <Item ID=\"0x0D89\"/>\n                <Item ID=\"0x0D8A\"/>\n                <Item ID=\"0x0D8B\"/>\n                <Item ID=\"0x0D8C\"/>\n                <Item ID=\"0x0D8D\"/>\n                <Item ID=\"0x0D8E\"/>\n                <Item ID=\"0x0D8F\"/>\n                <Item ID=\"0x0D90\"/>\n                <Item ID=\"0x0D91\"/>\n                <Item ID=\"0x0D92\"/>\n                <Item ID=\"0x0D93\"/>\n                <Item ID=\"0x309c\"/>\n                <Item ID=\"0x309d\"/>\n                <Item ID=\"0x309e\"/>\n                <Item ID=\"0x309f\"/>\n                <Item ID=\"0x30a0\"/>\n                <Item ID=\"0x30a1\"/>\n                <Item ID=\"0x30a2\"/>\n                <Item ID=\"0x30a3\"/>\n                <Item ID=\"0x30a4\"/>\n                <Item ID=\"0x30a5\"/>\n                <Item ID=\"0x30a6\"/>\n                <Item ID=\"0x30a7\"/>\n                <Item ID=\"0x30a8\"/>\n                <Item ID=\"0x30a9\"/>\n                <Item ID=\"0x30aa\"/>\n                <Item ID=\"0x30ab\"/>\n                <Item ID=\"0x30ac\"/>\n                <Item ID=\"0x30ad\"/>\n                <Item ID=\"0x30ae\"/>\n                <Item ID=\"0x30af\"/>\n                <Item ID=\"0x30b0\"/>\n                <Item ID=\"0x30b1\"/>\n                <Item ID=\"0x30b2\"/>\n                <Item ID=\"0x30b3\"/>\n                <Item ID=\"0x30b4\"/>\n                <Item ID=\"0x30b5\"/>\n                <Item ID=\"0x30b6\"/>\n                <Item ID=\"0x30b7\"/>\n                <Item ID=\"0x30b8\"/>\n                <Item ID=\"0x30b9\"/>\n                <Item ID=\"0x30ba\"/>\n                <Item ID=\"0x30bb\"/>\n                <Item ID=\"0x30bc\"/>\n                <Item ID=\"0x39a3\"/>\n                <Item ID=\"0x39a4\"/>\n                <Item ID=\"0x39a5\"/>\n                <Item ID=\"0x39a6\"/>\n                <Item ID=\"0x39a7\"/>\n                <Item ID=\"0x39a8\"/>\n                <Item ID=\"0x39a9\"/>\n                <Item ID=\"0x39aa\"/>\n                <Item ID=\"0x39ab\"/>\n                <Item ID=\"0x39ac\"/>\n                <Item ID=\"0x39ad\"/>\n                <Item ID=\"0x39ae\"/>\n                <Item ID=\"0x39af\"/>\n                <Item ID=\"0x39b1\"/>\n                <Item ID=\"0x39b2\"/>\n                <Item ID=\"0x39b3\"/>\n                <Item ID=\"0x39b4\"/>\n                <Item ID=\"0x39b5\"/>\n                <Item ID=\"0x39b6\"/>\n                <Item ID=\"0x39b7\"/>\n                <Item ID=\"0x39b8\"/>\n                <Item ID=\"0x39b9\"/>\n                <Item ID=\"0x39ba\"/>\n                <Item ID=\"0x39bb\"/>\n                <Item ID=\"0x39bc\"/>\n                <Item ID=\"0x39c3\"/>\n                <Item ID=\"0x39c4\"/>\n                <Item ID=\"0x39c5\"/>\n                <Item ID=\"0x39c6\"/>\n                <Item ID=\"0x39c7\"/>\n                <Item ID=\"0x39c8\"/>\n                <Item ID=\"0x39c9\"/>\n                <Item ID=\"0x39ca\"/>\n                <Item ID=\"0x39cb\"/>\n                <Item ID=\"0x39cc\"/>\n                <Item ID=\"0x39cd\"/>\n                <Item ID=\"0x39ce\"/>\n                <Item ID=\"0x39cf\"/>\n                <Item ID=\"0x39d0\"/>\n                <Item ID=\"0x39d1\"/>\n                <Item ID=\"0x39d2\"/>\n                <Item ID=\"0x39d3\"/>\n                <Item ID=\"0x39e7\"/>\n                <Item ID=\"0x39e8\"/>\n                <Item ID=\"0x39e9\"/>\n                <Item ID=\"0x39ea\"/>\n                <Item ID=\"0x39eb\"/>\n                <Item ID=\"0x39ec\"/>\n                <Item ID=\"0x39ed\"/>\n                <Item ID=\"0x39ee\"/>\n                <Item ID=\"0x39ef\"/>\n                <Item ID=\"0x39f0\"/>\n                <Item ID=\"0x39f1\"/>\n                <Item ID=\"0x39f2\"/>\n                <Item ID=\"0x39f3\"/>\n                <Item ID=\"0x39f4\"/>\n                <Item ID=\"0x39f5\"/>\n                <Item ID=\"0x39f6\"/>\n                <Item ID=\"0x39f7\"/>\n                <Item ID=\"0x39f8\"/>\n                <Item ID=\"0x39f9\"/>\n                <Item ID=\"0x39fa\"/>\n                <Item ID=\"0x39fb\"/>\n                <Item ID=\"0x39fc\"/>\n                <Item ID=\"0x39fd\"/>\n                <Item ID=\"0x39fe\"/>\n                <Item ID=\"0x39ff\"/>\n                <Item ID=\"0x3a00\"/>\n                <Item ID=\"0x3a01\"/>\n                <Item ID=\"0x3a02\"/>\n                <Item ID=\"0x3a03\"/>\n                <Item ID=\"0x3a04\"/>\n                <Item ID=\"0x3a05\"/>\n                <Item ID=\"0x3a06\"/>\n                <Item ID=\"0x3a09\"/>\n                <Item ID=\"0x3a0a\"/>\n                <Item ID=\"0x3a0b\"/>\n                <Item ID=\"0x3a0c\"/>\n                <Item ID=\"0x3a0d\"/>\n                <Item ID=\"0x3a0e\"/>\n                <Item ID=\"0x3a0f\"/>\n                <Item ID=\"0x3a10\"/>\n                <Item ID=\"0x3a11\"/>\n                <Item ID=\"0x3a12\"/>\n                <Item ID=\"0x3a13\"/>\n                <Item ID=\"0x3a14\"/>\n                <Item ID=\"0x3a15\"/>\n                <Item ID=\"0x3a16\"/>\n                <Item ID=\"0x3a17\"/>\n                <Item ID=\"0x3a18\"/>\n                <Item ID=\"0x3a19\"/>\n                <Item ID=\"0x3a1a\"/>\n                <Item ID=\"0x3a1b\"/>\n                <Item ID=\"0x3a1c\"/>\n                <Item ID=\"0x3a1d\"/>\n                <Item ID=\"0x3a1e\"/>\n                <Item ID=\"0x3a33\"/>\n                <Item ID=\"0x3a34\"/>\n                <Item ID=\"0x3a35\"/>\n                <Item ID=\"0x3a36\"/>\n                <Item ID=\"0x3a37\"/>\n                <Item ID=\"0x3a38\"/>\n                <Item ID=\"0x3a39\"/>\n                <Item ID=\"0x3a3a\"/>\n                <Item ID=\"0x3a3b\"/>\n                <Item ID=\"0x3a3c\"/>\n                <Item ID=\"0x3a3d\"/>\n                <Item ID=\"0x3a3e\"/>\n                <Item ID=\"0x3a3f\"/>\n                <Item ID=\"0x3a40\"/>\n                <Item ID=\"0x3a41\"/>\n                <Item ID=\"0x3a42\"/>\n                <Item ID=\"0x3a43\"/>\n                <Item ID=\"0x3a44\"/>\n                <Item ID=\"0x3a9c\"/>\n                <Item ID=\"0x3a9d\"/>\n                <Item ID=\"0x3a9e\"/>\n                <Item ID=\"0x3a9f\"/>\n                <Item ID=\"0x3aa0\"/>\n                <Item ID=\"0x3aa1\"/>\n                <Item ID=\"0x3aa2\"/>\n                <Item ID=\"0x3aa3\"/>\n                <Item ID=\"0x3aa4\"/>\n                <Item ID=\"0x3aa5\"/>\n                <Item ID=\"0x3aa6\"/>\n                <Item ID=\"0x3aa7\"/>\n                <Item ID=\"0x3aa8\"/>\n                <Item ID=\"0x3aa9\"/>\n                <Item ID=\"0x3aaa\"/>\n                <Item ID=\"0x3aab\"/>\n                <Item ID=\"0x3aac\"/>\n                <Item ID=\"0x3aad\"/>\n                <Item ID=\"0x3aae\"/>\n                <Item ID=\"0x3aaf\"/>\n                <Item ID=\"0x3ab0\"/>\n                <Item ID=\"0x3ab1\"/>\n                <Item ID=\"0x3ab2\"/>\n                <Item ID=\"0x3ab3\"/>\n                <Item ID=\"0x3ab4\"/>\n                <Item ID=\"0x3ab5\"/>\n                <Item ID=\"0x3ab6\"/>\n                <Item ID=\"0x3ab7\"/>\n                <Item ID=\"0x3ab8\"/>\n                <Item ID=\"0x3ab9\"/>\n                <Item ID=\"0x3aba\"/>\n                <Item ID=\"0x3abb\"/>\n                <Item ID=\"0x3abc\"/>\n                <Item ID=\"0x3abd\"/>\n                <Item ID=\"0x3abe\"/>\n                <Item ID=\"0x3abf\"/>\n                <Item ID=\"0x3ac0\"/>\n                <Item ID=\"0x3ac1\"/>\n                <Item ID=\"0x3ac2\"/>\n                <Item ID=\"0x3ac3\"/>\n                <Item ID=\"0x3ac4\"/>\n                <Item ID=\"0x3ac5\"/>\n                <Item ID=\"0x3ac6\"/>\n                <Item ID=\"0x3ac7\"/>\n                <Item ID=\"0x3ac8\"/>\n                <Item ID=\"0x3ac9\"/>\n                <Item ID=\"0x3aca\"/>\n                <Item ID=\"0x3acb\"/>\n                <Item ID=\"0x3acc\"/>\n                <Item ID=\"0x3acd\"/>\n                <Item ID=\"0x3ace\"/>\n                <Item ID=\"0x3acf\"/>\n                <Item ID=\"0x3ad0\"/>\n                <Item ID=\"0x3ad1\"/>\n                <Item ID=\"0x3ad2\"/>\n                <Item ID=\"0x3ad3\"/>\n                <Item ID=\"0x3ad4\"/>\n                <Item ID=\"0x3ad5\"/>\n                <Item ID=\"0x3ad6\"/>\n                <Item ID=\"0x3ad7\"/>\n                <Item ID=\"0x3ad8\"/>\n                <Item ID=\"0x3ad9\"/>\n                <Item ID=\"0x3ada\"/>\n                <Item ID=\"0x3adb\"/>\n                <Item ID=\"0x3adc\"/>\n                <Item ID=\"0x3add\"/>\n                <Item ID=\"0x3ade\"/>\n                <Item ID=\"0x3adf\"/>\n                <Item ID=\"0x3ae0\"/>\n                <Item ID=\"0x3ae1\"/>\n                <Item ID=\"0x3ae2\"/>\n                <Item ID=\"0x3ae3\"/>\n                <Item ID=\"0x3ae4\"/>\n                <Item ID=\"0x3ae5\"/>\n                <Item ID=\"0x3ae6\"/>\n                <Item ID=\"0x3ae7\"/>\n                <Item ID=\"0x3ae8\"/>\n                <Item ID=\"0x3ae9\"/>\n                <Item ID=\"0x3aea\"/>\n                <Item ID=\"0x3aeb\"/>\n                <Item ID=\"0x3aec\"/>\n                <Item ID=\"0x3aed\"/>\n                <Item ID=\"0x3aee\"/>\n                <Item ID=\"0x3aef\"/>\n            </Group>\n            <Group name=\"Trees for Wood\">\n                <Item ID=\"0x0CC8\"/>\n                <Item ID=\"0x0CC9\"/>\n                <Item ID=\"0x0CCA\"/>\n                <Item ID=\"0x0CCB\"/>\n                <Item ID=\"0x0CCC\"/>\n                <Item ID=\"0x0CCD\"/>\n                <Item ID=\"0x0CCE\"/>\n                <Item ID=\"0x0CCF\"/>\n                <Item ID=\"0x0CD0\"/>\n                <Item ID=\"0x0CD1\"/>\n                <Item ID=\"0x0CD2\"/>\n                <Item ID=\"0x0CD3\"/>\n                <Item ID=\"0x0CD4\"/>\n                <Item ID=\"0x0CD5\"/>\n                <Item ID=\"0x0CD6\"/>\n                <Item ID=\"0x0CD7\"/>\n                <Item ID=\"0x0CD8\"/>\n                <Item ID=\"0x0CD9\"/>\n                <Item ID=\"0x0CDA\"/>\n                <Item ID=\"0x0CDB\"/>\n                <Item ID=\"0x0CDC\"/>\n                <Item ID=\"0x0CDD\"/>\n                <Item ID=\"0x0CDE\"/>\n                <Item ID=\"0x0CDF\"/>\n                <Item ID=\"0x0CE6\"/>\n                <Item ID=\"0x0CE7\"/>\n                <Item ID=\"0x0CE8\"/>\n                <Item ID=\"0x0CE9\"/>\n                <Item ID=\"0x0CEA\"/>\n                <Item ID=\"0x0CF8\"/>\n                <Item ID=\"0x0CF9\"/>\n                <Item ID=\"0x0CFA\"/>\n                <Item ID=\"0x0CFB\"/>\n                <Item ID=\"0x0CFC\"/>\n                <Item ID=\"0x0CFD\"/>\n                <Item ID=\"0x0CFE\"/>\n                <Item ID=\"0x0CFF\"/>\n                <Item ID=\"0x0D00\"/>\n                <Item ID=\"0x0D01\"/>\n                <Item ID=\"0x0D02\"/>\n                <Item ID=\"0x0D03\"/>\n                <Item ID=\"0x0db7\"/>\n                <Item ID=\"0x1B7E\"/>\n                <Item ID=\"0x22aa\"/>\n                <Item ID=\"0x2478\"/>\n                <Item ID=\"0x2479\"/>\n                <Item ID=\"0x247A\"/>\n                <Item ID=\"0x247B\"/>\n                <Item ID=\"0x247C\"/>\n                <Item ID=\"0x247D\"/>\n                <Item ID=\"0x247E\"/>\n                <Item ID=\"0x36a1\"/>\n            </Group>\n            <Group name=\"Vines\">\n                <Item ID=\"0x0CEB\"/>\n                <Item ID=\"0x0CEC\"/>\n                <Item ID=\"0x0CED\"/>\n                <Item ID=\"0x0CEE\"/>\n                <Item ID=\"0x0CEF\"/>\n                <Item ID=\"0x0CF0\"/>\n                <Item ID=\"0x0CF1\"/>\n                <Item ID=\"0x0CF2\"/>\n                <Item ID=\"0x0D34\"/>\n                <Item ID=\"0x1f0d\"/>\n                <Item ID=\"0x1f0e\"/>\n                <Item ID=\"0x1f0f\"/>\n                <Item ID=\"0x1f10\"/>\n                <Item ID=\"0x1f11\"/>\n                <Item ID=\"0x1f12\"/>\n                <Item ID=\"0x2CF9\"/>\n                <Item ID=\"0x2CFA\"/>\n                <Item ID=\"0x2CFB\"/>\n                <Item ID=\"0x2CFC\"/>\n            </Group>\n            <Group name=\"Water Plants\">\n                <Item ID=\"0x0CB7\"/>\n                <Item ID=\"0x0CB8\"/>\n                <Item ID=\"0x0CB9\"/>\n                <Item ID=\"0x0CBA\"/>\n                <Item ID=\"0x0CBB\"/>\n                <Item ID=\"0x0D04\"/>\n                <Item ID=\"0x0D05\"/>\n                <Item ID=\"0x0D06\"/>\n                <Item ID=\"0x0D07\"/>\n                <Item ID=\"0x0D08\"/>\n                <Item ID=\"0x0D09\"/>\n                <Item ID=\"0x0D0A\"/>\n                <Item ID=\"0x0D0B\"/>\n                <Item ID=\"0x0DBA\"/>\n                <Item ID=\"0x0DBB\"/>\n                <Item ID=\"0x0DBC\"/>\n                <Item ID=\"0x0DBD\"/>\n                <Item ID=\"0x0DBE\"/>\n                <Item ID=\"0x0Dc1\"/>\n                <Item ID=\"0x0Dc2\"/>\n                <Item ID=\"0x0Dc3\"/>\n                <Item ID=\"0x246C\"/>\n                <Item ID=\"0x246D\"/>\n                <Item ID=\"0x246E\"/>\n                <Item ID=\"0x246F\"/>\n                <Item ID=\"0x2470\"/>\n            </Group>\n        </Group>\n        <Group name=\"Grass\">\n            <Item ID=\"0x177D\"/>\n            <Item ID=\"0x177e\"/>\n            <Item ID=\"0x177f\"/>\n            <Item ID=\"0x1780\"/>\n            <Item ID=\"0x1781\"/>\n            <Item ID=\"0x1782\"/>\n            <Item ID=\"0x1783\"/>\n            <Item ID=\"0x1784\"/>\n            <Item ID=\"0x1785\"/>\n            <Item ID=\"0x1786\"/>\n            <Item ID=\"0x1787\"/>\n            <Item ID=\"0x1788\"/>\n            <Item ID=\"0x1789\"/>\n        </Group>\n        <Group name=\"Lava\">\n            <Group name=\"Lava with Stone\">\n                <Item ID=\"0x131e\"/>\n                <Item ID=\"0x1324\"/>\n                <Item ID=\"0x1327\"/>\n                <Item ID=\"0x132a\"/>\n                <Item ID=\"0x132d\"/>\n                <Item ID=\"0x1330\"/>\n                <Item ID=\"0x1333\"/>\n                <Item ID=\"0x1336\"/>\n                <Item ID=\"0x1339\"/>\n                <Item ID=\"0x133c\"/>\n                <Item ID=\"0x133f\"/>\n                <Item ID=\"0x1342\"/>\n                <Item ID=\"0x1345\"/>\n                <Item ID=\"0x1348\"/>\n                <Item ID=\"0x134b\"/>\n                <Item ID=\"0x3286\"/>\n                <Item ID=\"0x3287\"/>\n                <Item ID=\"0x3288\"/>\n                <Item ID=\"0x3289\"/>\n                <Item ID=\"0x328a\"/>\n                <Item ID=\"0x328b\"/>\n                <Item ID=\"0x328c\"/>\n                <Item ID=\"0x328d\"/>\n                <Item ID=\"0x328e\"/>\n                <Item ID=\"0x328f\"/>\n                <Item ID=\"0x3290\"/>\n                <Item ID=\"0x3291\"/>\n                <Item ID=\"0x3292\"/>\n                <Item ID=\"0x3293\"/>\n                <Item ID=\"0x3294\"/>\n                <Item ID=\"0x3295\"/>\n                <Item ID=\"0x329a\"/>\n                <Item ID=\"0x329b\"/>\n            </Group>\n            <Group name=\"Lavafall\">\n                <Item ID=\"0x1A19\"/>\n                <Item ID=\"0x1A1E\"/>\n                <Item ID=\"0x1A23\"/>\n                <Item ID=\"0x1A28\"/>\n                <Item ID=\"0x1A2D\"/>\n                <Item ID=\"0x1A32\"/>\n                <Item ID=\"0x1A37\"/>\n                <Item ID=\"0x1A3B\"/>\n                <Item ID=\"0x1A3F\"/>\n                <Item ID=\"0x1A43\"/>\n                <Item ID=\"0x1A47\"/>\n                <Item ID=\"0x1A4C\"/>\n                <Item ID=\"0x1A51\"/>\n                <Item ID=\"0x1A56\"/>\n                <Item ID=\"0x1A5B\"/>\n                <Item ID=\"0x1A60\"/>\n                <Item ID=\"0x1A65\"/>\n                <Item ID=\"0x1A69\"/>\n                <Item ID=\"0x1A6D\"/>\n                <Item ID=\"0x1A71\"/>\n            </Group>\n            <Group name=\"animation\">\n                <Item ID=\"0x1A75\"/>\n                <Item ID=\"0x1A7C\"/>\n                <Item ID=\"0x1A7D\"/>\n                <Item ID=\"0x1A7E\"/>\n                <Item ID=\"0x2AE4\"/>\n                <Item ID=\"0x343b\"/>\n                <Item ID=\"0x3447\"/>\n                <Item ID=\"0x344e\"/>\n                <Item ID=\"0x3457\"/>\n                <Item ID=\"0x3462\"/>\n                <Item ID=\"0x3468\"/>\n                <Item ID=\"0x36b0\"/>\n                <Item ID=\"0x36bd\"/>\n                <Item ID=\"0x36ca\"/>\n                <Item ID=\"0x36e4\"/>\n                <Item ID=\"0x36fe\"/>\n                <Item ID=\"0x3709\"/>\n            </Group>\n            <Group name=\"stone only\">\n                <Item ID=\"0x329c\"/>\n                <Item ID=\"0x329d\"/>\n                <Item ID=\"0x329e\"/>\n                <Item ID=\"0x329f\"/>\n                <Item ID=\"0x32a0\"/>\n                <Item ID=\"0x32a1\"/>\n                <Item ID=\"0x32a2\"/>\n                <Item ID=\"0x32a3\"/>\n                <Item ID=\"0x32a4\"/>\n                <Item ID=\"0x32a5\"/>\n                <Item ID=\"0x32a6\"/>\n                <Item ID=\"0x32a7\"/>\n                <Item ID=\"0x32a8\"/>\n                <Item ID=\"0x32aa\"/>\n                <Item ID=\"0x32ab\"/>\n                <Item ID=\"0x32ac\"/>\n                <Item ID=\"0x32ad\"/>\n                <Item ID=\"0x32ae\"/>\n                <Item ID=\"0x32af\"/>\n                <Item ID=\"0x32b0\"/>\n                <Item ID=\"0x32b1\"/>\n                <Item ID=\"0x3546\"/>\n                <Item ID=\"0x354d\"/>\n                <Item ID=\"0x354e\"/>\n                <Item ID=\"0x354f\"/>\n                <Item ID=\"0x3550\"/>\n                <Item ID=\"0x3551\"/>\n                <Item ID=\"0x3552\"/>\n                <Item ID=\"0x3553\"/>\n                <Item ID=\"0x3554\"/>\n                <Item ID=\"0x3555\"/>\n                <Item ID=\"0x3556\"/>\n                <Item ID=\"0x3557\"/>\n                <Item ID=\"0x3558\"/>\n                <Item ID=\"0x3559\"/>\n                <Item ID=\"0x355a\"/>\n                <Item ID=\"0x355b\"/>\n                <Item ID=\"0x355c\"/>\n                <Item ID=\"0x355d\"/>\n                <Item ID=\"0x355e\"/>\n                <Item ID=\"0x355f\"/>\n                <Item ID=\"0x3560\"/>\n                <Item ID=\"0x3561\"/>\n            </Group>\n            <Item ID=\"0x12ee\"/>\n            <Item ID=\"0x12f4\"/>\n            <Item ID=\"0x12fa\"/>\n            <Item ID=\"0x1300\"/>\n            <Item ID=\"0x1306\"/>\n            <Item ID=\"0x1312\"/>\n            <Item ID=\"0x1318\"/>\n            <Item ID=\"0x136e\"/>\n            <Item ID=\"0x137e\"/>\n            <Item ID=\"0x1380\"/>\n            <Item ID=\"0x1382\"/>\n            <Item ID=\"0x2B3E\"/>\n            <Item ID=\"0x2B45\"/>\n            <Item ID=\"0x2B4b\"/>\n            <Item ID=\"0x2B50\"/>\n            <Item ID=\"0x2B5c\"/>\n            <Item ID=\"0x3296\"/>\n            <Item ID=\"0x3297\"/>\n            <Item ID=\"0x3298\"/>\n            <Item ID=\"0x3299\"/>\n            <Item ID=\"0x3547\"/>\n            <Item ID=\"0x3548\"/>\n            <Item ID=\"0x3549\"/>\n            <Item ID=\"0x354a\"/>\n            <Item ID=\"0x354b\"/>\n            <Item ID=\"0x354c\"/>\n        </Group>\n        <Group name=\"Rock + Boulder\">\n            <Item ID=\"0x134F\"/>\n            <Item ID=\"0x1350\"/>\n            <Item ID=\"0x1351\"/>\n            <Item ID=\"0x1352\"/>\n            <Item ID=\"0x1353\"/>\n            <Item ID=\"0x1354\"/>\n            <Item ID=\"0x1355\"/>\n            <Item ID=\"0x1356\"/>\n            <Item ID=\"0x1357\"/>\n            <Item ID=\"0x1358\"/>\n            <Item ID=\"0x1359\"/>\n            <Item ID=\"0x135A\"/>\n            <Item ID=\"0x135B\"/>\n            <Item ID=\"0x135C\"/>\n            <Item ID=\"0x135D\"/>\n            <Item ID=\"0x135E\"/>\n            <Item ID=\"0x135F\"/>\n            <Item ID=\"0x1360\"/>\n            <Item ID=\"0x1361\"/>\n            <Item ID=\"0x1362\"/>\n            <Item ID=\"0x1363\"/>\n            <Item ID=\"0x1364\"/>\n            <Item ID=\"0x1365\"/>\n            <Item ID=\"0x1366\"/>\n            <Item ID=\"0x1367\"/>\n            <Item ID=\"0x1368\"/>\n            <Item ID=\"0x1369\"/>\n            <Item ID=\"0x136A\"/>\n            <Item ID=\"0x136B\"/>\n            <Item ID=\"0x136C\"/>\n            <Item ID=\"0x136D\"/>\n            <Item ID=\"0x1771\"/>\n            <Item ID=\"0x1772\"/>\n            <Item ID=\"0x1773\"/>\n            <Item ID=\"0x1774\"/>\n            <Item ID=\"0x1775\"/>\n            <Item ID=\"0x1776\"/>\n            <Item ID=\"0x1777\"/>\n            <Item ID=\"0x1778\"/>\n            <Item ID=\"0x1779\"/>\n            <Item ID=\"0x177A\"/>\n            <Item ID=\"0x177B\"/>\n            <Item ID=\"0x177C\"/>\n            <Item ID=\"0x364E\"/>\n            <Item ID=\"0x364F\"/>\n        </Group>\n        <Group name=\"Snow\">\n            <Item ID=\"0x17BD\"/>\n            <Item ID=\"0x17BE\"/>\n            <Item ID=\"0x17BF\"/>\n            <Item ID=\"0x17C0\"/>\n            <Item ID=\"0x17C1\"/>\n            <Item ID=\"0x17C2\"/>\n            <Item ID=\"0x17C3\"/>\n            <Item ID=\"0x17C4\"/>\n            <Item ID=\"0x17C5\"/>\n            <Item ID=\"0x17C6\"/>\n            <Item ID=\"0x17C7\"/>\n            <Item ID=\"0x17C8\"/>\n            <Item ID=\"0x17C9\"/>\n            <Item ID=\"0x17CA\"/>\n            <Item ID=\"0x17CB\"/>\n            <Item ID=\"0x17CC\"/>\n            <Item ID=\"0x17cD\"/>\n            <Item ID=\"0x17cE\"/>\n        </Group>\n        <Group name=\"Swamp\">\n            <Group name=\"Animation\">\n                <Item ID=\"0x320d\"/>\n                <Item ID=\"0x3213\"/>\n                <Item ID=\"0x321a\"/>\n                <Item ID=\"0x3220\"/>\n                <Item ID=\"0x3226\"/>\n                <Item ID=\"0x322c\"/>\n                <Item ID=\"0x3236\"/>\n                <Item ID=\"0x3241\"/>\n            </Group>\n            <Group name=\"Corners\">\n                <Item ID=\"0x3252\"/>\n                <Item ID=\"0x3253\"/>\n                <Item ID=\"0x3254\"/>\n                <Item ID=\"0x3255\"/>\n                <Item ID=\"0x3256\"/>\n                <Item ID=\"0x3257\"/>\n                <Item ID=\"0x3269\"/>\n                <Item ID=\"0x3270\"/>\n                <Item ID=\"0x3271\"/>\n                <Item ID=\"0x3272\"/>\n                <Item ID=\"0x3273\"/>\n                <Item ID=\"0x3274\"/>\n                <Item ID=\"0x3275\"/>\n                <Item ID=\"0x3276\"/>\n                <Item ID=\"0x3277\"/>\n                <Item ID=\"0x3278\"/>\n                <Item ID=\"0x3279\"/>\n                <Item ID=\"0x327a\"/>\n                <Item ID=\"0x327b\"/>\n                <Item ID=\"0x327c\"/>\n                <Item ID=\"0x327d\"/>\n                <Item ID=\"0x327e\"/>\n                <Item ID=\"0x327f\"/>\n                <Item ID=\"0x3280\"/>\n                <Item ID=\"0x3281\"/>\n                <Item ID=\"0x3282\"/>\n                <Item ID=\"0x3283\"/>\n                <Item ID=\"0x3284\"/>\n                <Item ID=\"0x3285\"/>\n            </Group>\n            <Group name=\"Growth\">\n                <Item ID=\"0x3209\"/>\n                <Item ID=\"0x320a\"/>\n                <Item ID=\"0x3258\"/>\n                <Item ID=\"0x3259\"/>\n                <Item ID=\"0x325a\"/>\n                <Item ID=\"0x325b\"/>\n                <Item ID=\"0x325c\"/>\n                <Item ID=\"0x325d\"/>\n                <Item ID=\"0x325e\"/>\n                <Item ID=\"0x325f\"/>\n                <Item ID=\"0x3260\"/>\n                <Item ID=\"0x3261\"/>\n                <Item ID=\"0x3262\"/>\n                <Item ID=\"0x3263\"/>\n                <Item ID=\"0x3264\"/>\n                <Item ID=\"0x3265\"/>\n                <Item ID=\"0x3266\"/>\n                <Item ID=\"0x3267\"/>\n                <Item ID=\"0x3268\"/>\n            </Group>\n            <Group name=\"Stumps\">\n                <Item ID=\"0x324b\"/>\n                <Item ID=\"0x324c\"/>\n                <Item ID=\"0x324d\"/>\n                <Item ID=\"0x324e\"/>\n                <Item ID=\"0x324f\"/>\n                <Item ID=\"0x3250\"/>\n                <Item ID=\"0x3251\"/>\n            </Group>\n            <Item ID=\"0x326A\"/>\n            <Item ID=\"0x326a\"/>\n            <Item ID=\"0x326b\"/>\n            <Item ID=\"0x326c\"/>\n            <Item ID=\"0x326d\"/>\n            <Item ID=\"0x326e\"/>\n            <Item ID=\"0x326f\"/>\n        </Group>\n        <Group name=\"Water\">\n            <Group name=\"Corners\">\n                <Item ID=\"0x179D\"/>\n                <Item ID=\"0x179E\"/>\n                <Item ID=\"0x179F\"/>\n                <Item ID=\"0x17A0\"/>\n                <Item ID=\"0x17A1\"/>\n                <Item ID=\"0x17A2\"/>\n                <Item ID=\"0x17A3\"/>\n                <Item ID=\"0x17A4\"/>\n                <Item ID=\"0x17A5\"/>\n                <Item ID=\"0x17A6\"/>\n                <Item ID=\"0x17A7\"/>\n                <Item ID=\"0x17A8\"/>\n                <Item ID=\"0x17A9\"/>\n                <Item ID=\"0x17AA\"/>\n                <Item ID=\"0x17AB\"/>\n                <Item ID=\"0x17AC\"/>\n                <Item ID=\"0x17AD\"/>\n                <Item ID=\"0x17AE\"/>\n                <Item ID=\"0x17AF\"/>\n                <Item ID=\"0x17B0\"/>\n                <Item ID=\"0x17B1\"/>\n                <Item ID=\"0x17B2\"/>\n            </Group>\n            <Group name=\"Objects\">\n                <Item ID=\"0x3421\"/>\n                <Item ID=\"0x3426\"/>\n                <Item ID=\"0x342c\"/>\n                <Item ID=\"0x3486\"/>\n                <Item ID=\"0x348b\"/>\n                <Item ID=\"0x34ac\"/>\n                <Item ID=\"0x34b0\"/>\n            </Group>\n            <Group name=\"Waterfall\">\n                <Item ID=\"0x34ED\"/>\n                <Item ID=\"0x34F4\"/>\n                <Item ID=\"0x34F9\"/>\n                <Item ID=\"0x34FF\"/>\n                <Item ID=\"0x3505\"/>\n                <Item ID=\"0x350B\"/>\n                <Item ID=\"0x3513\"/>\n                <Item ID=\"0x3517\"/>\n                <Item ID=\"0x351D\"/>\n                <Item ID=\"0x3523\"/>\n            </Group>\n            <Group name=\"Wave etc.\">\n                <Item ID=\"0x1fa3\"/>\n                <Item ID=\"0x1fa8\"/>\n                <Item ID=\"0x1fae\"/>\n                <Item ID=\"0x1fb2\"/>\n                <Item ID=\"0x1fb7\"/>\n                <Item ID=\"0x1fbc\"/>\n                <Item ID=\"0x1fc6\"/>\n                <Item ID=\"0x346e\"/>\n                <Item ID=\"0x3474\"/>\n                <Item ID=\"0x347a\"/>\n                <Item ID=\"0x3480\"/>\n                <Item ID=\"0x3490\"/>\n                <Item ID=\"0x3494\"/>\n                <Item ID=\"0x349a\"/>\n                <Item ID=\"0x34a0\"/>\n                <Item ID=\"0x34a6\"/>\n                <Item ID=\"0x34ab\"/>\n                <Item ID=\"0x34b5\"/>\n                <Item ID=\"0x34b9\"/>\n                <Item ID=\"0x34bd\"/>\n                <Item ID=\"0x34c2\"/>\n                <Item ID=\"0x34c7\"/>\n                <Item ID=\"0x34d1\"/>\n                <Item ID=\"0x352d\"/>\n            </Group>\n            <Item ID=\"0x1797\"/>\n            <Item ID=\"0x1798\"/>\n            <Item ID=\"0x179a\"/>\n            <Item ID=\"0x179b\"/>\n            <Item ID=\"0x179c\"/>\n            <Item ID=\"0x3499\"/>\n            <Item ID=\"0x349f\"/>\n            <Item ID=\"0x34a5\"/>\n            <Item ID=\"0x34ab\"/>\n        </Group>\n    </Group>\n</Items>\n"
  },
  {
    "path": "etc/license.txt",
    "content": "Razor Software License Agreement\r\n\r\n\r\nThis Agreement sets forth the terms and conditions under which\r\nthe software known as Razor(tm) will be licensed by the author(s)\r\n(\"The Razor Author\") to you (\"Licensee\"), and by which Derivative \r\nWorks (as hereafter defined) of Razor will be licensed by you\r\nto The Razor Author.\r\n\r\nDefinitions:\r\n\r\n \"Derivative Work(s)\" shall mean any revision, enhancement,\r\n modification, translation, abridgement, condensation or\r\n expansion created by Licensee or The Razor Author that is based upon the\r\n Software or a portion thereof that would be a copyright\r\n infringement if prepared without the authorization of the\r\n copyright owners of the Software or portion thereof.\r\n\r\n \"Standard Version\" shall mean Razor, as originally created by\r\n The Razor Author.\r\n\r\n \"Software\" shall mean Razor and the Derivative Works created\r\n by Licensee and the collection of files distributed by the\r\n Licensee with The Razor Author, and the collection of files created\r\n through textual modifications.\r\n\r\n \"Copyright Holder\" is whoever is named in the copyright or\r\n copyrights for the Derivative Works.\r\n\r\n \"Licensee\" is you, only if you agree to be bound by the terms\r\n and conditions set forth in this Agreement.\r\n\r\n \"Freely Available\" means that no fee is charged for the item\r\n It also means that recipients of the item may not redistribute\r\n it in any way shape or form.\r\n\r\n1. The Razor Author maintains all rights, title and interest in and to\r\nRazor, including all applicable copyrights, trade secrets,\r\npatents and other intellectual rights therein.  Licensee hereby\r\ngrants to The Razor Author all right, title and interest into the compilation\r\nof Razor. \r\n\r\n2. The Razor Author hereby grants to Licensee a royalty free, worldwide right\r\nand license to use, Razor in accordance with the terms and conditions\r\nof this Agreement.\r\n\r\n3. Licensee hereby grants to The Razor Author a royalty free, worldwide right\r\nand license to use, copy, distribute and make Derivative Works of\r\nDerivative Works created by Licensee and sublicensing rights of\r\nany of the foregoing.\r\n\r\n4. The data and images supplied as input to or produced as output\r\nfrom the Software do not automatically fall under the copyright\r\nof this Software, but belong to whomever generated them, and may\r\nbe sold commercially, but may not be aggregated with this Software.\r\n\r\n5. The Razor Author makes no representation about the suitability of Razor\r\nfor any purposes.  The Razor Author shall have no duty or requirement to\r\ninclude any Derivative Works into Razor.\r\n\r\n6. THIS PACKAGE IS PROVIDED \"AS IS\" WITHOUT WARRANTIES OF ANY\r\nKIND, WHETHER EXPRESS OR IMPLIED, INCLUDING (BUT NOT LIMITED TO)\r\nALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND\r\nWITHOUT ANY WARRANTIES AS TO NONINFRINGEMENT.\r\n\r\n7. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,\r\nSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER RESULTING\r\nFROM LOSS OF USE OF DATA OR PROFITS, WHETHER IN AN ACTION OF\r\nCONTRACT, NEGLIGENCE OR OTHER TORTIOUS CONDUCT, ARISING OUT OF OR\r\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PACKAGE.\r\n\r\n8. Without limitation of the foregoing, You agree to commit no\r\nact which, directly or indirectly, would violate any U.S. law,\r\nregulation, or treaty, or any other international treaty or\r\nagreement to which the United States adheres or with which the\r\nUnited States complies, relating to the export or re-export of\r\nany commodities, software, or technical data.\r\n\r\n9. At no time shall anyone affiliated with Electronic Arts download\r\nor use this software.  This software is provided soley for end-users\r\nwho have purchased Ultima Online for use in non-profit ways.\r\n\r\n10. In addition to local, federal, and international laws \r\nprohibiting reverse engineering, the Licensee herby agrees to at no \r\ntime make any attempts to decompile Razor or associated libraries \r\nor alter them in any way other without express written consent \r\nfrom the author.\r\n\r\n"
  },
  {
    "path": "etc/overrides.def",
    "content": "# This file allows you to override static values in Razor\n\n## Two-Handed Weapons\n# Razor uses the standard 1H and 2H for weapons to determine if they are one\n# handed or two handed. You can override which weapon is two-handed\n\n# twohanded id true/false\n# Example: Crossbow\n#twohanded 0xF4F false\n#twohanded 0xF50 false\n"
  },
  {
    "path": "etc/spells.def",
    "content": "# Flag | Spell | Circle | Name | Words of Power | Regs Used\r\n# Flag = H(armful) N(eutral) B(eneficial)\r\n\r\n#\r\n# Magery:\r\n#\r\nH | 1 | 1 | Clumsy | Uus Jux | BM | NS\r\nN | 2 | 1 | Create Food | In Mani Ylem | GL | GS | MR\r\nH | 3 | 1 | Feeblemind | Rel Wis | GS | NS\r\nB | 4 | 1 | Heal | In Mani | GL | GS | SS\r\nH | 5 | 1 | Magic Arrow | In Por Ylem | SA\r\nN | 6 | 1 | Night Sight | In Lor | SS | SA\r\nB | 7 | 1 | Reactive Armor | Flam Sanct | GL | SA | SS\r\nH | 8 | 1 | Weaken | Des Mani | GL | NS\r\nB | 1 | 2 | Agility | Ex Uus | BM | MR\r\nB | 2 | 2 | Cunning | Uus Wis | MR | NS\r\nB | 3 | 2 | Cure | An Nox | GL | GS\r\nH | 4 | 2 | Harm | An Mani | NS | SS\r\nN | 5 | 2 | Magic Trap | In Jux | GL | SA | SS\r\nN | 6 | 2 | Magic Untrap | An Jux | BM | SA\r\nB | 7 | 2 | Protection | Uus Sanct | GL | GS | SA\r\nB | 8 | 2 | Strength | Uus Mani | MR | NS\r\nB | 1 | 3 | Bless | Rel Sanct | GL | MR\r\nH | 2 | 3 | Fireball | Vas Flam | BP\r\nN | 3 | 3 | Magic Lock | An Por | SA | BM | GL\r\nH | 4 | 3 | Poison | In Nox | NS\r\nN | 5 | 3 | Telekinesis | Ort Por Ylem | BM | MR\r\nN | 6 | 3 | Teleport | Rel Por | BM | MR\r\nN | 7 | 3 | Unlock | Ex Por | BM | SA\r\nN | 8 | 3 | Wall of Stone | In Sanct Ylem | BM | GL\r\nB | 1 | 4 | Arch Cure | Vas An Nox | GL | GS | MR\r\nB | 2 | 4 | Arch Protection | Vas Uus Sanct | GL | GS | MR | SA\r\nH | 3 | 4 | Curse | Des Sanct | GL | NS | SA\r\nN | 4 | 4 | Fire Field | In Flam Grav | BP | SS | SA\r\nB | 5 | 4 | Greater Heal | In Vas Mani | GL | GS | MR | SS\r\nH | 6 | 4 | Lightning | Por Ort Grav | MR | SA\r\nH | 7 | 4 | Mana Drain | Ort Rel | BP | MR | SS\r\nN | 8 | 4 | Recall | Kal Ort Por | BP | BM | MR\r\nH | 1 | 5 | Blade Spirits | In Jux Hur Ylem | BP | MR | NS\r\nN | 2 | 5 | Dispel Field | An Grav | GL | BP | SS | SA\r\nN | 3 | 5 | Incognito | Kal In Ex | BM | GL | NS\r\nB | 4 | 5 | Magic Reflection | In Jux Sanct | GL | MR | SS\r\nH | 5 | 5 | Mind Blast | Por Corp Wis | BP | MR | NS | SA\r\nH | 6 | 5 | Paralyze | An Ex Por | GL | MR | SS\r\nN | 7 | 5 | Poison Field | In Nox Grav | BP | NS | SS\r\nN | 8 | 5 | Summon Creature | Kal Xen | BM | MR | SS\r\nN | 1 | 6 | Dispel | An Ort | GL | MR | SA\r\nH | 2 | 6 | Energy Bolt | Corp Por | BP | NS\r\nH | 3 | 6 | Explosion | Vas Ort Flam | BM | MR\r\nN | 4 | 6 | Invisibility | An Lor Xen | BM | NS\r\nN | 5 | 6 | Mark | Kal Por Ylem | BP | BM | MR\r\nN | 6 | 6 | Mass Curse | Vas Des Sanct | GL | MR | NS | SA\r\nN | 7 | 6 | Paralyze Field | In Ex Grav | BP | GS | SS\r\nN | 8 | 6 | Reveal | Wis Quas | BM | SA\r\nH | 1 | 7 | Chain Lightning | Vas Ort Grav | BP | MR | BM | SA\r\nN | 2 | 7 | Energy Field | In Sanct Grav | BP | MR | SS | SA\r\nH | 3 | 7 | Flamestrike | Kal Vas Flam | SS | SA\r\nN | 4 | 7 | Gate Travel | Vas Rel Por | BP | MR | SA\r\nH | 5 | 7 | Mana Vampire | Ort Sanct | BP | BM | MR | SS\r\nN | 6 | 7 | Mass Dispel | Vas An Ort | BP | GL | MR | SA\r\nH | 7 | 7 | Meteor Swarm | Flam Kal Des Ylem | BM | SS | MR | SA\r\nN | 8 | 7 | Polymorph | Vas Ylem Rel | BM | MR | SS\r\nH | 1 | 8 | Earthquake | In Vas Por | BM | GS | MR | SA\r\nH | 2 | 8 | Energy Vortex | Vas Corp Por | BP | BM | MR | NS\r\nB | 3 | 8 | Resurrection | An Corp | BM | GL | GS\r\nN | 4 | 8 | Summon Air Elemental | Kal Vas Xen Hur | BM | MR | SS\r\nN | 5 | 8 | Summon Daemon | Kal Vas Xen Corp | BM | MR | SS | SA\r\nN | 6 | 8 | Summon Earth Elemental | Kal Vas Xen Ylem | BM | MR | SS\r\nN | 7 | 8 | Summon Fire Elemental | Kal Vas Xen Flam | BM | MR | SS | SA\r\nN | 8 | 8 | Summon Water Elemental | Kal Vas Xen An Flam | BM | MR | SS\r\n\r\n#\r\n# Necromancy\r\n#\r\nN | 1 | 10 | Animate Dead | Uus Corp | DB | GD\r\nH | 2 | 10 | Blood Oath | In Jux Mani Xen | DB\r\nN | 3 | 10 | Corpse Skin | In Agle Corp Ylem | BW | GD\r\nB | 4 | 10 | Curse Weapon | An Sanct Gra Char | PI\r\nH | 5 | 10 | Evil Omen | Pas Tym An Sanct | BW | NC\r\nN | 6 | 10 | Horrific Beast | Rel Xen Vas Bal | BW | DB\r\nN | 7 | 10 | Lich Form | Rel Xen Corp Ort | NC | DB | GD\r\nH | 8 | 10 | Mind Rot | Wis An Ben | BW | DB | PI\r\nH | 9 | 10 | Pain Spike | In Sar | GD | PI\r\nH | 10 | 10 | Poison Strike | In Vas Nox | NC\r\nH | 11 | 10 | Strangle | In Bal Nox | NC | DB\r\nN | 12 | 10 | Summon Familiar | Kal Xen Bal | BW | GD | DB\r\nN | 13 | 10 | Vampiric Embrace | Rel Xen An Sanct | BW | NC | PI\r\nH | 14 | 10 | Vengeful Spirit | Kal Xen Bal Beh | BW | GD | PI\r\nH | 15 | 10 | Wither | Kal Vas An Flam | NC | GD | PI\r\nN | 16 | 10 | Wraith Form | Rel Xen Um | PI | NC\r\nN | 17 | 10 | Exorcism | Ort Corp Grav | NC | GD\r\n\r\n#\r\n# Chivalry\r\n#\r\nB | 1 | 20 | Cleanse by Fire | Expor Flamus\r\nB | 2 | 20 | Close Wounds | Obsu Vulni\r\nB | 3 | 20 | Consecrate Weapon | Consecrus Arma\r\nN | 4 | 20 | Dispel Evil | Dispiro Malas\r\nB | 5 | 20 | Divine Fury | Divinum Furis\r\nH | 6 | 20 | Enemy of One | Forul Solum\r\nH | 7 | 20 | Holy Light | Augus Luminos\r\nB | 8 | 20 | Noble Sacrifice | Dium Prostra\r\nB | 9 | 20 | Remove Curse | Extermo Vomica\r\nN | 10 | 20 | Sacred Journey | Sanctum Viatas\r\n\r\n#\r\n# Bushido\r\n#\r\nH | 1 | 40 | Honorable Execution | \r\nB | 2 | 40 | Confidence | \r\nB | 3 | 40 | Evasion | \r\nH | 4 | 40 | Counter Attack | \r\nH | 5 | 40 | Lightning Strike | \r\nH | 6 | 40 | Momentum Strike | \r\n\r\n#\r\n# Ninjisu\r\n#\r\nH | 1 | 50 | Focus Attack | \r\nH | 2 | 50 | Death Strike | \r\nB | 3 | 50 | Animal Form | \r\nH | 4 | 50 | Ki Attack | \r\nH | 5 | 50 | Surprise Attack | \r\nH | 6 | 50 | Backstab | \r\nN | 7 | 50 | Shadowjump | \r\nN | 8 | 50 | Mirror Image | \r\n\r\n#\r\n# Spellweaving\r\n#\r\nN | 1 | 60 | Arcane Circle | Myrshalee\r\nB | 2 | 60 | Gift of Renewal | Olorisstra\r\nN | 3 | 60 | Immolating Weapon | Thalshara\r\nH | 4 | 60 | Attune Weapon | Haeldril\r\nH | 5 | 60 | Thunderstorm | Erelonia\r\nH | 6 | 60 | Nature's Fury | Rauvvrae\r\nN | 7 | 60 | Summon Fey | Alalithra\r\nN | 8 | 60 | Summon Fiend | Nylisstra\r\nN | 9 | 60 | Reaper Form | Tarisstree\r\nH | 10 | 60 | Wildfire | Haelyn\r\nH | 11 | 60 | Essence of Wind | Anathrae\r\nN | 12 | 60 | Dryad Allure | Rathril\r\nN | 13 | 60 | Ethereal Voyage | Orlavdra\r\nH | 14 | 60 | Word of Death | Nyraxle\r\nB | 15 | 60 | Gift of Life | Illorae\r\nB | 16 | 60 | Arcane Empowerment | Aslavdra\r\n\r\n#\r\n# Mysticism\r\n#\r\nH | 28 | 65 | Nether Bolt | In Corp Ylem\r\nN | 29 | 65 | Healing Stone | Kal In Mani\r\nH | 30 | 65 | Purge Magic | An Ort Sanct\r\nN | 31 | 65 | Enchant | In Ort Ylem\r\nH | 32 | 65 | Sleep | In Zu\r\nH | 33 | 65 | Eagle Strike | Kal Por Xen\r\nH | 34 | 65 | Animated Weapon | In Jux Por Ylem\r\nN | 35 | 65 | Stone Form | In Rel Ylem\r\nN | 36 | 65 | Spell Trigger | In Vas Ort Ex\r\nH | 37 | 65 | Mass Sleep | Vas Zu\r\nB | 38 | 65 | Cleansing Winds | In Vas Mani Hur\r\nH | 39 | 65 | Bombard | Corp Por Ylem\r\nH | 40 | 65 | Spell Plague | Vas Rel Jux Ort\r\nH | 41 | 65 | Hail Storm | Kal Des Ylem\r\nH | 42 | 65 | Nether Cyclone | Grav Hur\r\nH | 43 | 65 | Rising Colossus | Kal Vas Xen Corp Ylem\r\n\r\n#\r\n# Masteries\r\n# TODO: Correct flags\r\n#\r\nN | 1 | 70 | Inspire | Uus Por\r\nN | 2 | 70 | Invigorate | An Zu\r\nN | 3 | 70 | Resilience | Kal Mani Tym\r\nN | 4 | 70 | Perserverance | Uus Jux Sanct\r\nN | 5 | 70 | Tribulation | In Jux Hur Rel\r\nN | 6 | 70 | Despair | Kal Des Mani Tym\r\nN | 7 | 70 | Death Ray | In Grav Corp\r\nN | 8 | 70 | Ethereal Burst | Uus Ort Grav\r\nN | 9 | 70 | Nether Blast | In Vas Xen Por\r\nN | 10 | 70 | Mystic Weapon | Vas Ylem Wis\r\nN | 11 | 70 | Command Undead | In Corp Xen Por\r\nN | 12 | 70 | Conduit | Uus Corp Grav\r\nN | 13 | 70 | Mana Shield | Faerkulggen\r\nN | 14 | 70 | Summon Reaper | Lartarisstree\r\nN | 15 | 70 | Enchanted Summoning | NA\r\nN | 16 | 70 | Anticipate Hit | NA\r\nN | 17 | 70 | Warcry | NA\r\nN | 18 | 70 | Intuition | NA\r\nN | 19 | 70 | Rejuvenate | NA\r\nN | 20 | 70 | Holy Fist | NA\r\nN | 21 | 70 | Shadow | NA\r\nN | 22 | 70 | White Tiger Form | NA\r\nN | 23 | 70 | Flaming Shot | NA\r\nN | 24 | 70 | Playing The Odds | NA\r\nN | 25 | 70 | Thrust | NA\r\nN | 26 | 70 | Pierce | NA\r\nN | 27 | 70 | Stagger | NA\r\nN | 28 | 70 | Toughness | NA\r\nN | 29 | 70 | Onslaught | NA\r\nN | 30 | 70 | Focused Eye | NA\r\nN | 31 | 70 | Elemental Fury | NA\r\nN | 32 | 70 | Called Shot | NA\r\nN | 33 | 70 | Saving Throw | NA\r\nN | 34 | 70 | Shield Bash | NA\r\nN | 35 | 70 | Bodyguard | NA\r\nN | 36 | 70 | Heighten Senses | NA\r\nN | 37 | 70 | Tolerance | NA\r\nN | 38 | 70 | Injected Strike | NA\r\nN | 39 | 70 | Potency | NA\r\nN | 40 | 70 | Rampage | NA\r\nN | 41 | 70 | Fists of Fury | NA\r\nN | 42 | 70 | Knockout | NA\r\nN | 43 | 70 | Whispering | NA\r\nN | 44 | 70 | Combat Training | NA\r\nN | 45 | 70 | Boarding | NA\r\n\r\n"
  },
  {
    "path": "etc/uorguardlines.def",
    "content": "# Papua\n5639 3095 192 223 -128 127\n5831 3237 20 30 -128 127\n\n# Delucia\n5123 3942 192 122 -128 127\n5147 4064 125 20 -128 127\n5235 3930 80 12 -128 127\n\n# Yew\n92 656 349 225 -30 39\n441 746 216 135 0 39\n258 881 399 380 0 39\n657 922 42 307 0 39\n657 806 17 28 0 39\n718 874 38 22 0 39\n761 741 19 21 0 39\n\n# Wind\n5132 3 70 55 -128 127\n5132 58 81 68 -128 127\n5213 98 39 28 -128 127\n5197 126 55 78 -128 127\n5252 112 42 58 -128 127\n5252 170 32 8 -128 127\n5252 178 20 5 -128 127\n5252 183 10 10 -128 127\n5294 19 72 120 -128 127\n5279 57 15 55 -128 127\n5286 25 8 32 -128 127\n\n# Jhelom\n1303 3670 189 225 -20 127\n1338 3895 74 28 -20 127\n1383 3951 109 94 -20 127\n1494 3767 12 11 -20 127\n\n# Vesper\n2899 599 25 9 -128 127\n2899 608 84 26 -128 127\n2983 624 25 32 -128 127\n2937 634 46 22 -128 127\n2983 617 7 7 -128 127\n2845 634 92 110 -128 127\n2937 685 58 59 -128 127\t\t\t\n2822 744 235 270 -128 127\t\t\t\n2818 696 27 14 -128 127\t\t\t\n2760 944 62 55 -128 127\t\t\t\n2728 966 32 33 -128 127\t\t\t\n2747 958 13 8 -128 127\t\t\t\n\n# Minoc\n2411 366 135 241 -10 127\n2548 495 72 55 -10 127\n2564 585 3 42 -10 127\n2567 585 61 61 -10 127\n2499 627 68 63 -10 127\n2694 685 15 16 -10 127\n\n# Serpent's Hold. Get\n2868 3324 205 195 0 127\n2978 3545 11 11 0 127\n\n# Magincia\n3653 2046 27 48 0 127\n3752 2046 52 48 0 127\n3680 2045 72 49 0 127\n3652 2094 160 180 -128 127\n3649 2256 54 47 -128 127\n3554 2132 18 18 -128 127\n\n# Nujel'm\n3583 1000 252 435 0 127\n3544 1169 39 44 0 127\n3514 1202 11 11 0 127\n\n# Cove\n2200 1110 50 50 -10 127\n2200 1160 86 86 -10 127\n2339 1256 11 11 0 127\n\n# Ocllo\n3597 2456 129 99 -128 127 F\n3726 2493 7 13 -128 127 F\n3597 2555 158 145 -128 127 F\n3590 2595 7 40 -128 127 F\n\n\n# Britain\n1416 1498 324 279 -10 127\n1500 1408 46 90 0 127\n1385 1538 31 239 -10 127\n1416 1777 324 60 0 127\n1385 1777 31 130 0 127\n1093 1538 292 369 0 127\n1330 1991 13 13 -10 127\n\n# Skara Brae\n638 2062 12 11 0 127\n538 2107 150 190 -10 127\n\n# Trinsic\n1856 2636 75 28 -10 127\n1816 2664 283 231 -10 127\n2099 2782 18 25 -10 127\n1970 2895 47 32 -10 127\n1796 2696 20 67 0 127\n1800 2796 16 52 0 127\n1823 2943 11 11 -128 127\n\n# Moonglow\n4535 844 20 3 0 127\n4530 847 31 61 0 127\n4521 914 56 49 0 127\n4278 915 54 19 0 127\n4283 944 53 73 0 127\n4377 1015 59 37 -10 127\n4367 1050 142 145 0 127\n4539 1036 27 18 0 127\n4517 1053 23 22 0 127\n4389 1198 47 39 0 127\n4466 1211 32 25 0 127\n4700 1108 17 18 0 127\n4656 1127 26 13 0 127\n4678 1162 25 25 0 127\n4613 1196 23 22 0 127\n4646 1212 14 17 0 127\n4677 1214 26 22 0 127\n4459 1276 16 16 0 127\n4622 1316 22 24 0 127\n4487 1353 59 21 0 127\n4477 1374 69 35 0 127\n4659 1387 40 40 0 127\n4549 1482 29 27 0 127\n4405 1451 23 23 0 127\n4483 1468 21 13 0 127\n\n\n#duel\n#5307 3681 33 26 -127 127 \n#5158 3436 33 28 -127 127 \n#5848 3500 27 30 -127 127 \n#6055 2324 39 24 -127 127 \n#5757 3658 27 26 -127 127"
  },
  {
    "path": "help/docs/download.md",
    "content": "---\ndescription: Download Razor, a free tool designed to help with simple tasks while playing Ultima Online\n---\n\n# Download UO Razor\n\n???+ tip \"Client Support\"\n    It's **highly recommended** that you use the [ClassicUO](https://www.classicuo.eu/) client with this version of Razor, however it should work with the original 5.x and 7.x clients though support for any bugs may be limited.\n\n    If you plan on using Razor with the original client, download the `x86` version otherwise download `x64` for ClassicUO.\n\n## Latest Release\n\nUse the links below to download the **latest** version of Razor. To learn more about each version, view the [release notes](releasenotes.md). You can also download previous versions on [Github](https://github.com/markdwags/Razor/releases).\n\n[Download Razor 1.9.77.0 (x64)](https://github.com/markdwags/Razor/releases/download/v1.9.77.0/Razor-x64-1.9.77.0.zip){ .md-button .md-button--primary }\n\n[Download Razor 1.9.77.0 (x86)](https://github.com/markdwags/Razor/releases/download/v1.9.77.0/Razor-x86-1.9.77.0.zip){ .md-button }\n\n## Developer Preview\n\nThis is built automatically after each commit to master, so it may contain bugs and/or unfinished features but is generally considered stable.\n\n[![Build & Deploy Dev Preview](https://github.com/markdwags/Razor/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/markdwags/Razor/actions/workflows/build.yml)\n\n[Download Developer Preview (1.9.X.0) (x64)](https://github.com/markdwags/Razor/releases/download/Razor-dev-preview/Razor-dev-x64-preview.zip){ .md-button .md-button--primary }\n\n[Download Developer Preview (1.9.X.0) (x86)](https://github.com/markdwags/Razor/releases/download/Razor-dev-preview/Razor-dev-x86-preview.zip){ .md-button }\n\n[More Info](https://github.com/markdwags/Razor/releases/tag/Razor-dev-preview)\n"
  },
  {
    "path": "help/docs/faq.md",
    "content": "# Portability\n\nThis version of Razor is completely portable and can be installed in any location. All profiles, scripts, macros are all stored within subfolders of `Razor.exe`.\n\n# Migrating Existing Profiles\n\nTo migrate/move Profiles, Scripts and Macros between Razor installations, simply close out of all instances of Razor and copy/paste the following folders/files from your old Razor location to the new location:\n\n- `Profiles`\n- `Macros`\n- `Scripts`\n- `counters.xml`\n- `Razor.exe.config` (only if you made changes)\n\n# Application Layout\n\n## Folders\n\n### Profiles\n\nWhen you open Razor for the first time, a set of default settings are created.\n\n!!! tip \"Multiple Profiles\"\n    It's **highly recommend** that have you have 1 profile per character. If you use the same profile among multiple characters while logged in, you could potentially lose changes to your profile. It's doable, but requires an extra bit a caution to ensure you keep all your profiles synced up.\n\n### Macros\n\nMacros are stored in the `Macros` folder and saved with the `.macro` file extension. These files can be read using any basic text editor.\n\n!!! tip \"Absolute Target Variables\"\n    Macros are scared across Profiles. To avoid making multiple macros that do the same thing, be sure to review [Absolute Target Variables](help/macros.md#absolute-target-variables)\n\n!!! warning\n    Editing macros within the file can be difficult beyond simply copy/pasting due to syntax. If you'd like the ability to edit scripts in a text editor, check out the [Razor Scripting Engine](guide/index.md).\n\n### Scripts\n\nScripts are stored in the `Scripts` folder and saved with the `.razor` file extension. These files can be read using any basic text editor.\n\n!!! tip \"Razor Scripting Engine\"\n    Razor has a built-in editor to help with syntax, color coding and auto-completion. Review the [Razor Scripting Engine](guide/index.md) for more details.\n\n## Files\n\n| File               | Descripton                                                                                                                                                                                                                                                  |\n| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `animdata.csv`     | This file contains the list of animations used when filtering different mobiles in                                                                                                                                                                          |\n| `counters.xml`     | This files contains the list of items that can be counted by Razor. While the use of the counter in the titlebar has been deprecated for the in-game counter bar available in ClassicUO it's still required for the macro and script system to count items. |\n| `guidelines.def`   | This file contains the guardline definitions that display on the UOPS map                                                                                                                                                                                   |\n| `overrides.def`    | This file contains overrides for specific static values in Razor. See file for details.                                                                                                                                                                     |\n| `Razor.exe.config` | This file is the base configuration for Razor and contains a few settings, such as more organizer or restock agents, that require the application to be started when those values are changed.                                                              |\n| `spells.def`       | This file contains the list of spells in game and if they are considered Harmful or Beneficial.                                                                                                                                                             |\n\n!!! warning\n    Files not listed here the related binaries required for Razor to work. They include files ending with `.dll, .lib, .exe, .exp, .pdb` and **_should not_** be part of restoring Razor files between installations.\n\n## Configuration\n\n| File                   | Description                                                                 |\n| ---------------------- | --------------------------------------------------------------------------- |\n| `Razor.exe.config`     | This configuration is used if you are using Razor with the OSI client       |\n| `ClassicUO.exe.config` | This configuration is used if you are using Razor with the ClassicUO client |\n\nYou must manually edit that file if you want to set any of these values.\n\n```xml\n  <appSettings>\n    <add key=\"UODataDir\" value=\"C:\\Games\\UO\" />\n    <add key=\"UOClient\" value=\"C:\\Games\\UO\\client.exe\" />\n    <add key=\"LastPort\" value=\"2593\" />\n    <add key=\"LastProfile\" value=\"default\" />\n    <add key=\"LastServer\" value=\"login.server.com\" />\n    <add key=\"LastServerId\" value=\"0\" />\n    <add key=\"ClientEncrypted\" value=\"1\" />\n    <add key=\"ServerEncrypted\" value=\"0\" />\n    <add key=\"ShowWelcome\" value=\"1\" />\n    <add key=\"UId\" value=\"21613fcd\" />\n    <add key=\"MaxOrganizerAgents\" value=\"20\" />\n    <add key=\"MaxBuyAgents\" value=\"10\" />\n    <add key=\"MaxRestockAgents\" value=\"10\" />\n    <add key=\"ImportProfilesAndMacros\" value=\"true\" />\n    <add key=\"BackupPath\" value=\".\\Backup\" />\n  </appSettings>\n```\n\n### Agents\n\nIf you need more Organizer, Buy or Restock agents, modify these values or add them to the ClassicUO config.\n\n```xml\n<add key=\"MaxOrganizerAgents\" value=\"20\" />\n<add key=\"MaxBuyAgents\" value=\"10\" />\n<add key=\"MaxRestockAgents\" value=\"10\" />\n```\n\n# Overhead Messages\n\nFor details on how to use the Overhead Messages feature, view the [help guide](help/displaycounters.md#overhead-messages).\n\n# In-Game Commands\n\nRazor supports the following in-game commands (not case-sensitive).\n\n!!! note \"Command Prefix\"\n    The command prefix with the OSI client is `-`.\n\nIf you are using ClassicUO, you must prefix each command with `>`.\n\nFor example, instead of `-where` you would type `>where`. This is due to ClassicUO commands starting with `-` and several UO commands for yell, whisper, guild use other symbols so Razor had find something unique.\n\n- `help` - Displays all the in-game commands you see here.\n- `adduseonce` - Creates a target that adds the item to the **UseOnce** list.\n- `time` - Displays the current client system time.\n- `where` - Displays your X/Y/Z coordinates according to Razor.\n\n!!! tip\n    Some shards support `[where` to get your location from the server.\n\n- `ping` - Pings the server 5 times and returns the results.\n- `echo` - Send a message to yourself. Useful for leaving a note to yourself when macroing, for example.\n- `getserial` - Get information on the RPV you are viewing to verify authenticity.\n- `rpvinfo` - Get information on the RPV you are viewing to verify authenticity.\n- `macro [name]` - This will run a macro in-game. If you have a macro called `CreateRobes` you would type `macro CreateRobes`.\n- `hue` - Display information about an item, include the hue.\n- `item` - Same as `hue`.\n- `info` - Display a gump that shows info about the item or mobile selected.\n- `resync` - This will resync your client, the same way the resync hotkey does.\n- `mobile` - Display some general information about a mobile (used for debugging)\n- `weather [weather_type] [num_of_effects]` - Set the weather in the game. Weather will end automatically after 6 minutes, on newer clients it will end in 10 minutes.\n  - `[weather_type]`:\n    - `0` - It starts to rain\n    - `1` - A fierce storm approaches\n    - `2` - It begins to snow\n    - `3` - A storm is brewing\n  - `[num_of_effects]` - Max number on the screen (client restriction) is 70.\n- `season [season_type]` - Sets the season. This is client side only.\n  - `[season_type]`:\n    - `0` - Spring\n    - `1` - Summer\n    - `2` - Fall\n    - `3` - Winter\n    - `4` - Desolation\n- `set [variable]` - Sets a macro variable\\*\n- `waypoint [x] [y]` or `track off` - Sets a waypoint at a specific `X/Y` location. If you pass `off` it will remove it from the client.\n- `sysmsgs` - Show the current system message buffer\n- `boat` - Show in-game boat control gump\n- `hotkeys` - Show in-game gump with used hot keys\n\n# Legacy Versions\n\nThese versions were developed before ClassicUO and will only work with the standard OSI client.\n\n!!! warning\n    These versions are no longer supported and while they should work just fine they should be considered legacy.\n\n| Razor Version                                                       | Hash                                                                       |\n| ------------------------------------------------------------------- | -------------------------------------------------------------------------- |\n| [Razor v1.5.0.16](https://www.razorce.com/Razor_UOR_CE-1.5.0.16.zip) | `SHA256: 63D0B617FCE217C067A3270323C9E58B63F379F401B4224E0EA937DAA7871B8B` |\n| [Razor v1.5.0.15](https://www.razorce.com/Razor_UOR_CE-1.5.0.15.zip) | `SHA256: 64916F16A72FDE5E9C17B3A180001A896E9472458C8DB69E09DC7E37D78A6B30` |\n| [Razor v1.5.0.14](https://www.razorce.com/Razor_UOR_CE-1.5.0.14.zip) | `SHA256: 1D352F7814311FDBFC3EF16DEAD6664562C85B3817D953112F687099A98D104A` |\n| [Razor v1.5.0.13](https://www.razorce.com/Razor_UOR_CE-1.5.0.13.zip) | `SHA256: 090D753820B791E115532E96703DE1650B4DB0CE88191355D0F65A5799A51571` |\n| [Razor v1.5.0.12](https://www.razorce.com/Razor_UOR_CE-1.5.0.12.zip) | `SHA256: 1AC1DAFBBDEE3DBEB1D031E63CAF904D43B60A05E98CB83ECA4872F892BD4F36` |\n| [Razor v1.5.0.11](https://www.razorce.com/Razor_UOR_CE-1.5.0.11.zip) | `SHA256: 5945E5F9D5C87FEF552881C319167BD4ED012AE01D31FA855449B034129F7225` |\n| [Razor v1.5.0.10](https://www.razorce.com/Razor_UOR_CE-1.5.0.10.zip) | `SHA256: 80FACEE8DB005E5CB7A89EFEBEE4BEE2DA242C0BF9AFA31B20ADEBEC44ED7FEF` |\n| [Razor v1.5.0.9](https://www.razorce.com/Razor_UOR_CE-1.5.0.9.zip)   | `SHA256: 63158C8987BA0E7FBBA5917018595617830CF7B72A699A50A34F79A943365EE0` |\n| [Razor v1.5.0.8](https://www.razorce.com/Razor_UOR_CE-1.5.0.8.zip)   | `SHA256: 0D25D01C85CFC8BA51D4FFEEBF59A3DC23B2400850A4B41C613DFC50AFAD5487` |\n| [Razor v1.5.0.7](https://www.razorce.com/Razor_UOR_CE-1.5.0.7.zip)   | `SHA256: BD239C8F10FB80C3D1F6D185557679A0FCCF0CE35B2DB6D726B0DB0DB8BE7B7A` |\n\n## Experimental\n\nThis version of Razor is identical to version `1.5.0.16` except with one major change to how Razor figures our your position to address the Razor \"desync\" issue.\n\nSome users have reported issues when logging in so that is why this version is marked as experimental. If you experience issues, please revert to 1.5.0.16.\n\n| Razor Version                                                       | Hash                                                                       |\n| ------------------------------------------------------------------- | -------------------------------------------------------------------------- |\n| [Razor v1.5.0.17](https://www.razorce.com/Razor_UOR_CE-1.5.0.17.zip) | `SHA256: D26E8B887FC26B94FB5B0C50530BE07A4393783CCBEAA9C3FD5B38171A857571` |\n\n## Validate Checksum\n\n- Windows (using Powershell)\n\n```powershell\nGet-FileHash '.\\Razor-1.x.x.x.zip' -Algorithm SHA25\n```\n\n- Mac\n\n```bash\nshasum -a 256 /path/to/Razor-1.x.x.x.zip' -Algorithm SHA256\n```\n\n- Linux\n\n```bash\nsha256sum /path/to/Razor-1.x.x.x.zip\n```\n\n## Configuration File\n\nThe **Welcome Screen** will control some of these settings, but some settings can only be changed by editing `.\\Razor.exe.config`.\n\n```xml\n<appSettings>\n    <add key=\"PatchEncy\" value=\"1\" /> <!-- Patch client encryption -->\n    <add key=\"ServerEnc\" value=\"0\" /> <!-- Use OSI encryption -->\n    <add key=\"MaxOrganizerAgents\" value=\"20\" /> <!-- Override the default Organizer agent count -->\n    <add key=\"MaxBuyAgents\" value=\"10\" /> <!-- Override the default Buy agent count -->\n    <add key=\"MaxRestockAgents\" value=\"10\" /> <!-- Override the default Restock agent count -->\n    <add key=\"ImportProfilesAndMacros\" value=\"false\" />  <!-- If true, will import macros and profiles from %AppData%\\Razor -->\n    <add key=\"LastProfile\" value=\"Test\" /> <!-- Last profile used in Razor -->\n    <add key=\"LastServer\" value=\"test.server.com\" /> <!-- Last server connected to in Razor -->\n    <add key=\"LastPort\" value=\"2597\" /> <!-- Last server port connected to in Razor -->\n    <add key=\"LastServerId\" value=\"1\" /> <!-- Index of the server selected in the dropdown -->\n    <add key=\"ShowWelcome\" value=\"1\" /> <!-- Show the Welcome Screen when loading Razor -->\n    <add key=\"UOClient\" value=\"D:\\Games\\UO\\client.exe\" /> <!-- Location to Ultima Online client -->\n    <add key=\"UODataDir\" value=\"D:\\Games\\UO\" /> <!-- Location to Ultima Online data directory -->\n</appSettings>\n\n<!-- You can define a list of servers here by adding values between <Servers></Servers> -->\n<Servers>\n    <add key=\"Custom Server\" value=\"server.someserver.com,2593\" />\n</Servers>\n```\n"
  },
  {
    "path": "help/docs/guide/commands.md",
    "content": "---\ntitle: Script Commands\ndescription: A list of all script commands for Razor, complete with descriptions and examples\n---\n\n# Command Overview\n\nThe commands issued in the scripting engine are similar to commands you might enter into a command prompt or shell.  Each line has a starting command and a set of parameters.  Some of those parameters are required, some are optional.\n\n`command (required) [optional]`\n\nAll parameters are shown inside of parenthesis or brackets.  Parameters within parenthesis are **required** while those in brackets are _optional_ and will default to specific value if not provided.\n\nIf you want to pass several words as a single parameter you must wrap them using `'` or `\"`. For example `'hello goodbye'` is one parameter, while `hello` `goodbye` is two.\n\nFor example, if your script is something like:\n\n```razor\n# Say 'Hello'\nsay Hello friends!\n```\n\nYou will end up just saying `Hello`.  Instead, you if you wrap the words in single (') or double quotes (\") the engine will see it as a single parameter.\n\n```razor\n# Say 'Hello friends!'\nsay 'Hello friends!'\n```\n\nIf you prefix a command with the `@` this will silence any warning/output from the command.  For example:\n\n!!! example\n\n    ```razor\n    // Generate warning if robe is out of reach\n    lifttype 'robe'\n\n    // Silence warning if robe is out of reach\n    @lifttype 'robe'\n    ```\n\nWithout the `@` symbol, if a robe isn't available, you would get an warning message telling you that it couldn't find a robe. But since the `@` symbol was provided, no warning is displayed.\n\n# Action Commands\n\n## attack\n\n**Syntax**: `attack (serial)` or `attack ('variablename')`\n\n**Description**: Attack a specific serial or variable tied to a serial.\n\n!!! example\n\n    === \"Attack Target\"\n\n        ```razor\n        attack '0x21B4'\n        ```\n\n    === \"Attack Variable\"\n\n        ```razor\n        attack 'attackdummy'\n        ```\n## cast\n\n**Syntax**: `cast ('name of spell')`\n\n**Description**: Cast a spell by name\n\n!!! example\n\n    === \"Cast specific spell\"\n\n        ```razor\n        cast 'greater heal'\n        wft\n        target 'self'\n        ```\n\n## classicuo\n\n**Syntax**: `classicuo ('setting') ('value')` or `cuo ('setting') ('value')`\n\n**Description**: This command will change specific settings/properties in your current ClassicUO profile.\n\n!!! tip\n    Type `>cuo list` to get a list of profile settings/properties to change\n\n!!! example\n\n    === \"Turn off CUO music\"\n\n        ```razor\n        overhead 'Turn off the music!'\n        classicuo 'enablemusic' false\n        ```\n\n    === \"Adjust music volume to 50%\"\n\n        ```razor\n        overhead 'Turning music to 50%'\n        classicuo 'musicvolume' 50\n        ```\n\n## cleardragdrop\n\n**Syntax**: `cleardragdrop`\n\n**Description**: Clears Razor's the drag/drop queue\n\n!!! example\n\n    === \"Clear on sysmsg message\"\n\n        ```razor\n        if insysmsg 'cannot reach'\n            cleardragdrop\n        endif\n        ```\n\n## clearhands\n\n**Syntax**: `clearhands ('left'/'right'/'both')`\n\n**Description**: Undress your hands based on the param.\n\n!!! example\n\n    === \"Undress both hands\"\n\n        ```razor\n        clearhands 'both'\n        ```\n\n    === \"Undress left hand\"\n\n        ```razor\n        clearhands 'left'\n        ```\n\n## cooldown\n\n**Syntax**: `cooldown ('name') ('seconds') ['hue'] ['icon name'] ['sound'] ['stay visible'] ['foreground color'] ['background color']`\n\n**Description**: This command will add a custom cooldown that will display as a gump in-game.\n\n??? tip \"Supported Foreground & Background Colors\"\n    You can set the foreground and background color of the specific cooldown down by using one of the colors below:\n\n    > AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure, Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood, CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan, DarkBlue, DarkCyan, DarkGoldenrod, DarkGray, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue, DimGray, DodgerBlue, Firebrick, FloralWhite, ForestGreen, Fuchsia, Gainsboro, GhostWhite, Gold, Goldenrod, Gray, Green, GreenYellow, Honeydew, HotPink, IndianRed, Indigo, Ivory, Khaki, Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenrodYellow, LightGray, LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSteelBlue, LightYellow, Lime, LimeGreen, Linen, Magenta, Maroon, MediumAquamarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue, MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin, NavajoWhite, Navy, OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid, PaleGoldenrod, PaleGreen, PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple, RebeccaPurple, Red, RosyBrown, RoyalBlue, SaddleBrown, Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, Snow, SpringGreen, SteelBlue, Tan, Teal, Thistle, Tomato, Transparent, Turquoise, Violet, Wheat, White, WhiteSmoke, Yellow, YellowGreen\n\n??? tip \"Supported Icon Names\"\n    You can use any of the following icons.\n\n    **NOTE:** Icon availability is based on the version of the client you have. If the icon doesn't display, it must be an icon that doesn't exist your data files.\n\n    > AchievePerfection, ActiveMeditation, Agility, AnimalForm, AnticipateHit, ArcaneEmpowerment, ArchProtection, ArmorPierce, AttuneWeapon, AuraOfNausea, BarakoDraftOfMight, BarrabHemolymphConcentrate, Berserk, Bleed, Bless, Block, BloodOathCaster, BloodOathCurse, BloodwormAnemia, Boarding, Bodyguard, BoneBreaker, BoneBreakerImmune, CaddelliteInfused, CalledShot, CityTradeDeal, Clumsy, CombatTraining, Conduit, Confidence, ConsecrateWeapon, CorpseSkin, CounterAttack, CriminalStatus, Cunning, Curse, CurseWeapon, DeathRay, DeathRayDebuff, DeathStrike, DefenseMastery, DespairCaster, DespairTarget, Disarm, Disguised, DivineFury, DragonTurtleDebuff, DualWield, ElementalFury, ElementalFuryDebuff, Enchant, EnchantedSummoning, EnemyOfOne, EnemyOfOneDebuff, EssenceOfWind, EtherealBurst, EtherealVoyage, Evasion, EvilOmen, FactionStatLoss, FanDancerFanFire, FeebleMind, Feint, FeintDebuff, FishPie, FistsOfFury, Fly, FocusedEye, ForceArrow, GazeDespair, GiftOfLife, GiftOfRenewal, GrapesOfWrath, Healing, HeatOfBattleStatus, HeightenedSenses, HidingAndOrStealth, HiryuPhysicalResistance, HitLowerAttack, HitLowerDefense, HonorableExecution, Honored, HonoredDebuff, HorrificBeast, HowlOfCacophony, Humility, HumilityDebuff, ImmolatingWeapon, Incognito, InjectedStrike, InjectedStrikeDebuff, Inspire, Intuition, Invigorate, Invisibility, JukariBurnPoiltice, Knockout, KurakAmbushersEssence, LichForm, LightningStrike, MagicReflection, ManaPhase, ManaShield, MassCurse, MassSleep, MedusaStone, Mindrot, MomentumStrike, MortalStrike, MysticalPolymorphTotem, MysticWeapon, NightSight, Onslaught, OrangePetals, PainSpike, Paralyze, Perfection, Perseverance, Pierce, PlayingTheOdds, PlayingTheOddsDebuff, Poison, PoisonImmunity, Polymorph, Potency, PotionGloriousFortune, Protection, PsychicAttack, Rage, RageFocusingBuff, RageFocusingDebuff, Rampage, ReactiveArmor, ReaperForm, Resilience, RoseOfTrinsic, RotwormBloodDisease, RuneBeetleCorruption, SakkhraProphylaxis, SavingThrow, Shadow, ShieldBash, SkillUseDelay, Sleep, Sparks, SpellFocusingBuff, SpellFocusingDebuff, SpellPlague, Spirituality, SplinteringEffect, Stagger, StoneForm, Strangle, Strength, Surge, Swarm, SwarmImmune, SwingSpeedDebuff, TalonStrike, Thrust, ThrustDebuff, Thunderstorm, Tolerance, Toughness, TribulationCaster, TribulationTarget, TrueFear, UnknownGoblin, UnknownRedDrop, UnknownStar, UnknownTomato, UraliTranceTonic, VampiricEmbrace, Veterinary, Warcry, Warding, Weaken, Webbing, Whispering, WhiteTigerForm, WraithForm    \n\n!!! example\n\n    === \"Simple cooldown\"\n\n        ```razor\n        cooldown 'Refresh' 20\n        ```\n\n    === \"Cooldown with custom hued text\"\n\n        ```razor\n        cooldown 'Refresh' 20 234\n        ```\n\n    === \"Cooldown with icon\"\n\n        ```razor\n        cooldown 'Refresh' 15 0 'Agility'\n        ```\n\n    === \"Cooldown a custom sound (flute)\"\n\n        ```razor\n        cooldown 'Health Check' 20 0 0 61\n        ```\n\n    === \"Cooldown remains when expired\"\n\n        ```razor\n        # default cooldown, 20 seconds, remains after it expires\n        cooldown 'Health Check' 20 0 0 0 true\n\n        # default cooldown, 25 seconds, 235 hue, icon 30012, no sound, remains after it expires\n        cooldown 'Health Check' 20 235 30012 0 true\n        ```\n\n    === \"Cooldown with custom colors\"\n\n        ```razor\n        cooldown 'Stay 1' 20 0 0 0 false 'Firebrick' 'Peru'\n        ```\n\n    === \"Reset existing cooldown\"\n\n        ```razor        \n        cooldown 'Refresh' 20\n\n        wait 10 seconds\n\n        cooldown 'Refresh' 20\n        ```\n\n## dclick\n\n**Syntax**: `dclick (serial)` or `dclick ('left'/'right'/'hands')`\n\n**Description**: This command will use (double-click) a specific item or mobile or use the item in one of your hands using `left`, `right` or `hands` to use an item in either hand.\n\n!!! example\n\n    === \"Double-click a specific item id\"\n\n        ```razor\n        dclick '0x34AB'\n        ```\n\n    === \"Double-click a variable\"\n\n        ```razor\n        dclick 'myvariable'\n        ```\n\n    === \"Double-click any item in your hands\"\n        ```razor\n        dclick 'hands'\n        ```\n    \n    === \"Double-click item in right hand\"\n        ```razor\n        dclick 'right'\n        ```\n\n## dclicktype\n\n**Syntax**: `dclicktype ('name of item'/'graphicId') [inrange (true/false)/backpack] [hue]`\n\n**Description**: This command will use (double-click) an item type either provided by the name or the graphic ID.\n\n!!! tip \"Range Check\"\n    If you include the optional `true` parameter, items within range (2 tiles) will only be considered. If you include the optional `backpack` parameter, items in your backpack only be considered.\n\n!!! tip \"Getting the graphic name or ID\"\n    To get the name or the ID of item, use the `>info` command in Razor and click on the item. You can use either the `Item Name` or `Id`.\n\n    ![item-command](../images/infocommand.png)\n\n!!! example\n\n    === \"Use any item\"\n\n        ```razor\n        dclicktype 'dagger'\n        waitfortarget\n        targettype 'robe'\n        ```\n\n    === \"..with range check\"\n\n        ```razor hl_lines=\"1\"\n        dclicktype 'dagger' true\n        waitfortarget\n        targettype 'robe' true\n        ```\n\n    === \"..with backpack only\"\n\n        ```razor hl_lines=\"1\"\n        dclicktype 'dagger' backpack\n        waitfortarget\n        targettype 'robe' backpack\n        ```\n\n    === \"..with backpack and hue only\"\n\n        ```razor hl_lines=\"1\"\n        dclicktype 'dagger' backpack 45\n        waitfortarget\n        targettype 'robe' backpack\n        ```\n\n## dress\n\n**Syntax**: `dress ('name of dress list')` or `dress (serial)`\n\n**Description**: This command will execute a spec dress list you have defined in Razor or dress (left and drop) a specific serial\n\n!!! example\n\n    === \"Use existing dress list\"\n\n        ```razor\n        dress 'My Sunday Best'\n        ```\n    \n    === \"Using a serial\"\n\n        ```razor hl_lines=\"1\"\n        dress '0x345234'\n        ```\n\n    === \"Using a variable\"\n\n        ```razor hl_lines=\"2\"\n        setvar 'hat'\n        dress 'hat'\n        ```\n\n## drop\n\n**Syntax**: `drop (serial) (x) (y) [z]` or `drop (serial) (layer)` or `drop 'ground' (x) (y) [z]`\n\n**Description**: This command will drop the item you are holding either at your feet, on a specific layer , at a specific X/Y/Z location on the ground or within the defined serial.\n\n!!! tip\n    The functionality of `drop 'ground' (x) (y) [z]` is also available in with [droprelloc](./#droprelloc).\n\n!!! tip\n    A list of available [layers](./layers.md) for reference that can be used with this command.\n\n!!! example\n\n    === \"Lift item, drop on your chest/torso\"\n\n        ```razor\n        lift '0x400D54A7'\n        drop 'self' InnerTorso\n        ```\n\n    === \"Lift item, drop on ground at location\"\n\n        ```razor\n        lift '0x400D54A7'\n        drop 'ground' 5926 1148 0\n        ```\n\n## droprelloc\n\n**Syntax**: `droprelloc (x) (y)`\n\n**Description**: This command will drop the item you're holding to a location relative to your position.\n\nExample:\n\n!!! example\n\n    === \"Drop Relative Location\"\n\n        ```razor\n        lift '0x400EED2A'\n        wait 1000\n        droprelloc 1 1\n        ```\n\n## getlabel\n\n**Syntax**: `getlabel ('serial') ('variable name')`\n\n**Description**: This command will get the label (text obtained by single-clicking an item) and save it to a variable.\n\n!!! example\n\n    === \"Find a dog\"\n\n        ```razor\n        if findtype '217' as 'a_dog'\n            getlabel 'a_dog' 'dog_label'\n\n            if 'Fido' in 'dog_label'\n                overhead 'found mydog!' 5\n                overhead 'dog_label' 67\n            endif    \n        endif\n        ```\n\n    === \"Find a silver kryss\"\n\n        ```razor        \n        setvar 'silver_bag'\n\n        if findtype '0x140' as 'kryss'\n            getlabel 'kryss' 'kryss_label'\n\n            if 'silver' in 'kryss_label'\n                overhead 'found silver kryss!' 5\n                \n                lift 'kryss' 1\n                drop 'silver_bag' -1 -1 0\n            endif    \n        endif\n        ```\n\n## hotkey\n\n**Syntax**: `hotkey ('name of hotkey')`\n\n**Description**: This command will execute any Razor hotkey by name.\n\n!!! example\n\n    === \"Hotkey\"\n\n        ```razor\n        skill 'detect hidden'\n        waitfortarget\n        hotkey 'target self'\n        ```\n\n## interrupt\n\n**Syntax**: `interrupt ['layer']`\n\n**Description**: This command will interrupt a casting action. You can pass an [optional layer](layers.md) if you want interrupt to only attempt an interrupt using a specific layer.\n\n!!! tip\n    If you don't provide a specific layer to use for interrupt, Razor will search in the following order:\n\n    `shirt, shoes, pants, head, gloves, ring, neck, waist, innertorse, bracelet, middletorso, earrings, arms, cloak, outertorso, outerlegs, innerlegs, righthand, lefthand`\n\n!!! example\n\n    === \"Example\"\n\n        ```razor\n        cast 'energy bolt'\n        if hp < 10\n            interrupt\n            cast 'greater healing'\n            wft\n            target 'self'\n        else\n            wft\n            target 'last'    \n        endif        \n        ```\n\n    === \"Specific layer\"\n\n        ```razor hl_lines=\"3\"\n        cast 'energy bolt'\n        if hp < 10\n            interrupt 'pants'\n            cast 'greater healing'\n            wft\n            target 'self'\n        else\n            wft\n            target 'last'    \n        endif \n        ```\n\n## lift\n\n**Syntax**: `lift ('serial') ['amount'] ['timeout']`\n\n**Description**: This command will lift a specific item and amount. If no amount is provided, `1` is set as default. If no timeout is provided, `30000` (30 seconds) is set as default\n\n!!! tip \"dress command\"\n    If you're looking to lift an item to wear, consider using the `dress` command instead.\n\n!!! example\n\n    === \"Lift item and drop to the ground\"\n\n        ```razor\n        lift '0x400EED2A'\n        wait 1000\n        droprelloc 1 1 0\n        ```\n\n    === \"Lift item, timeout in 5 seconds if unable\"\n        \n        ```razor       \n        lift '0x400EED2A' 1 5000\n        droprelloc 1 1 0\n        ```\n\n## lifttype\n\n**Syntax**: `lifttype ('gfx') ['amount'] ['hue']` or `lifttype ('name of item') ['amount'] ['hue']`\n\n**Description**: This command will lift a specific item by type either by the graphic id or by the name from your backpack. If no amount is provided, `1` is defaulted.\n\n!!! example\n\n    === \"Lift by name\"\n\n        ```razor\n        lifttype 'robe'\n        wait 1000\n        droprelloc 1 1\n        ```\n\n    === \"Lift by item id\"\n\n        ```razor\n        lifttype '0x1FCD'\n        wait 1000\n        droprelloc 1 1\n        ```\n\n    === \"Lift by name, max 5\"\n\n        ```razor\n        lifttype 'fish steak%s%' 5\n        wait 1000\n        droprelloc 1 1\n        ```\n\n    === \"Lift by name, max 5, specific hue\"\n\n        ```razor\n        lifttype 'fish steak%s%' 5 45\n        wait 1000\n        droprelloc 1 1\n        ```\n\n## music\n\n**Syntax**: `music ('index')`\n\n**Description**: This command will play music based on the ID.\n\n!!! tip\n    The music ID can often be found in `Music\\Digital\\Config.txt` in the main client files.\n\n!!! example\n\n    === \"Description\"\n\n        ```razor hl_lines=\"3\"\n        overhead 'playings bucsden'\n        wait 500\n        music 11\n        ```\n\n## potion\n\n**Syntax**: `potion ('potion type')`\n\nTypes: `heal, cure, refresh, nightsight, ns, explosion, strength, str, agility`\n\n**Description**: This command will use a specific potion based on the type.\n\n!!! example\n\n    === \"Use agility potion\"\n\n        ```razor\n        potion 'agility'\n        ```\n\n    === \"Use heal potion\"\n\n        ```razor\n        potion 'heal'\n        ```\n\n## rename\n\n**Syntax**: `rename (serial) ('name')`\n\n**Description**: This command will attempt to rename the mobile to a new name.\n\n!!! example\n\n    === \"Rename using serial\"\n\n        ```razor\n        rename '0x453' 'Fluffy'\n        ```\n\n    === \"Rename using variables\"\n\n        ```razor\n        setvar 'mypet'\n\n        rename 'mypet' 'Fluffy'\n        ```\n\n    === \"Rename using last target\"\n\n        ```razor\n        rename 'lasttarget' 'Fluffy'\n        ```\n\n## random\n\n**Syntax**: `random ('max number')`\n\n**Description**: This command will generate a random number between 1 and the max number.\n\n!!! example\n\n    === \"Random Message Check\"\n\n        ```razor\n        clearsysmsg\n\n        random 10\n\n        if insysmsg 'Random: 5'\n            say 'Hello!'\n        else\n            say 'Hail!'\n        endif\n        ```\n\n## script\n\n**Syntax**: `script ('name')` or `script ('category\\name')`\n\n**Description**: This command will call another script.\n\n!!! tip\n    You can call scripts in categories using a `category1\\category2\\scriptname` format.\n\n!!! example\n\n    === \"Execute script\"\n\n        ```razor hl_lines=\"2\"\n        if hp = 40\n            script 'healcure'\n        endif\n        ```\n\n    === \"Execute script in category\"\n\n        ```razor hl_lines=\"2\"\n        if mana = 40\n            script 'magery\\meditation'\n        endif\n        ```\n\n## setability\n\n**Syntax**: `setability ('primary'/'secondary'/'stun'/'disarm') ['on'/'off']`\n\n**Description**: This will set a specific ability on or off. If `on` or `off` is missing, `on` is defaulted.\n\n!!! example\n\n    === \"Set stun\"\n\n        ```razor\n        setability 'stun'\n        ```\n\n    === \"Turn off stun\"\n\n        ```razor\n        setability 'stun' off\n        ```\n\n## setvar\n\n**Syntax**: `setvar ('variable') ['serial'] ['timeout']` or `setvariable ('variable') ['serial'] ['timeout']`\n\n**Description**: This command will pause the script until you select a target to be assigned a variable. You can also provide a serial directly, which will bypass the target selection. Default timeout is 30 seconds that can be changed by passing in a new timeout value in milliseconds.\n\n!!! tip \"Temp variables\"\n    If you use `setvar!` (note the `!`) the variable will not be available in Razor's variable list to be used by other scripts and will go away at the end of the script's execution. You can remove it with the `unsetvar!` command.\n\n!!! example\n\n    === \"Set variable and use it\"\n\n        ```razor\n        setvar 'dummy'\n\n        cast 'magic arrow'\n        waitfortarget\n        target 'dummy'\n        ```\n\n    === \"Set variable with serial\"\n\n        ```razor\n        setvar 'spellbook' '0x40000D'\n\n        dress 'spellbook'        \n        ```\n    \n    === \"Set temp variable with serial\"\n\n        ```razor\n        setvar! 'tempvar' '0x40000D'\n\n        dclick 'tempvar'       \n        ```\n\n## skill\n\n**Syntax**: `skill ('name of skill')` or `skill last`\n\n**Description**: This command will use a specific skill (assuming it's a usable skill).\n\n!!! tip \"Supported skill names\"\n    `anatomy, animallore, itemidentification, itemid, armslore, begging, peacemaking, peace, cartography, detectinghidden, discord, discordance, evaluatingintelligence, evalint, forensicevaluation, forensiceval, hiding, provocation, provo, inscription, poisoning, spiritspeak, stealing, taming, tasteidentification, tasteid, tracking, meditation, stealth, removetrap, imbuing`\n\n!!! example\n\n    === \"Use meditation\"\n\n        ```razor\n        while mana < maxmana\n            say 'mediation!'\n            skill 'meditation'\n            wait 11000\n        endwhile\n        ```\n\n## sound\n\n**Syntax**: `sound ('serial')`\n\n**Description**: This command will play a specific sound based on serial id.\n\n!!! example\n\n    === \"Description\"\n\n        ```razor hl_lines=\"3\"\n        overhead 'daemon sound'\n        wait 500\n        sound '0x166'\n        ```\n\n## unsetvar\n\n**Syntax**: `unsetvar ('variable')`\n\n**Description**: This command will remove the variable from the variable list.\n\n!!! tip \"Temp variables\"\n    If you use `unsetvar!` (note the `!`) with `setvar!` the variable will be removed from the list of variables just available for the script's execution.\n\n!!! example\n\n    === \"Set variable, use it, unset\"\n\n        ```razor\n        setvar 'dummy'\n\n        cast 'magic arrow'\n        waitfortarget\n        target 'dummy'\n\n        unsetvar 'dummy'\n        ```\n    \n    === \"Set temp variable with serial, unset\"\n\n        ```razor\n        setvar! 'tempvar' '0x40000D'\n\n        dclick 'tempvar'       \n\n        unsetvar! 'tempvar'\n        ```\n\n## virtue\n\n**Syntax**: `virtue ('honor'/'sacrifice'/'valor')`\n\n**Description**: This command will invoke Honor, Sacrifice or Valor.\n\n!!! example\n\n    === \"Invoke Honor\"\n\n        ```razor\n        virtue 'honor'\n        ```\n\n    === \"Invoke Sacrifice\"\n\n        ```razor\n        virtue 'sacrifice'\n        ```\n\n    === \"Invoke Valor\"\n\n        ```razor\n        virtue 'valor'\n        ```\n\n## walk\n\n**Syntax**: `walk ('direction')`\n\n**Description**: This command will turn and/or walk your player in a certain direction.\n\n!!! example\n\n    === \"Walk around\"\n\n        ```razor\n        walk 'North'\n        walk 'Up'\n        walk 'West'\n        walk 'Left'\n        walk 'South'\n        walk 'Down'\n        walk 'East'\n        walk 'Right'\n        ```\n\n## wait & pause\n\n**Syntax**: `wait (time in milliseconds)` or `pause (time in milliseconds)` or `wait (duration) (shorthand)`\n\n**Description**: This command will pause the execution of a script for a given time.\n\n!!! tip \"Tips\"\n    `1000` milliseconds is equal to `1` second. `1000 x number of seconds = total milliseconds`\n\n    To make your script easier to read, you can **shorthand** instead of defining the full time in milliseconds.\n\n    | Accepted Shorthand              |\n    | ------------------------------- |\n    | `seconds`, `second`, `sec`, `s` |\n    | `minutes`, `minute`, `min`, `m` |\n\n!!! example\n\n    === \"Wait 5 seconds\"\n\n        ```razor hl_lines=\"2\"\n        while stam < 100    \n            wait 5000\n        endwhile\n        ```\n\n    === \"Wait 2 seconds (with shorthand)\"\n\n        ```razor hl_lines=\"2 6\"\n        while stam < 100    \n            wait 2 sec\n        endwhile\n\n        while stam < 100    \n            wait 2 seconds\n        endwhile\n        ```\n\n    === \"Wait 3 minutes (with shorthand)\"\n\n        ```razor hl_lines=\"2\"\n        say 'AFK for 3 minutes'\n        wait 3 minutes\n        say 'Back!'\n        ```\n\n## undress\n\n**Syntax**: `undress ('name of dress list')'` or `undress 'LayerName'` or `undress (serial)`\n\n**Description**: This command will either undress you completely if no dress list is provided. If you provide a dress list, only those specific items will be undressed. Lastly, you can define a layer name to undress.\n\n!!! tip\n    Available [layers](./layers.md) for reference\n\n!!! example\n\n    === \"Full naked\"\n\n        ```razor\n        undress\n        ```\n\n    === \"Specfic items in dress list\"\n\n        ```razor\n        undress 'My Sunday Best'\n        ```\n\n    === \"Remove your shirt and pants\"\n\n        ```razor\n        undress 'Shirt'\n        undress 'Pants'\n        ```\n    === \"Using a serial\"\n\n        ```razor hl_lines=\"1\"\n        undress '0x345234'\n        ```\n\n    === \"Using a variable\"\n\n        ```razor hl_lines=\"2\"\n        setvar 'hat'\n        undress 'hat'\n        ```\n\n# Agent Commands\n\n## organizer\n\n**Syntax**: `organizer ('number') ['set']`\n\n**Description**: This command will execute a specific organizer agent. If the `set` parameter is included, you will instead be prompted to set the organizer agent's hotbag.\n\n!!! example\n\n    === \"Execute organizer agent 1\"\n\n        ```razor\n        organizer 1\n        ```\n\n    === \"Set a hotbag on organizer agent 4\"\n\n        ```razor\n        organizer 4 'set'\n        ```\n\n## restock\n\n**Syntax**: `restock ('number') ['set']`\n\n**Description**: This command will execute a specific restock agent. If the `set` parameter is included, you will instead be prompted to set the restock agent's hotbag.\n\n!!! example\n\n    === \"Use Restock Agent 1\"\n\n        ```razor\n        if count garlic < 4\n            restock 1\n        endif\n        ```\n\n    === \"Set a hotbag on Restock Agent 4\"\n\n        ```razor\n        restock 4 'set'\n        ```\n\n## scavenger\n\n**Syntax**: `scavenger ('clear'/'add'/'on'/'off'/'set')`\n\n**Description**: This command will control the scavenger agent.\n\n* `clear`: Clear scavenger agent cache\n* `add`: Select an item to add to the list\n* `on`: Turn on the scavenger agent\n* `off`: Turn off the scavenger agent\n* `set`: Set the scavenger agent's hotbag\n\n!!! example\n\n    === \"Turn off scavenger\"\n\n        ```razor\n        scavenger 'off'\n        ```\n\n## sell\n\n**Syntax**: `sell`\n\n**Description**: This command will set the Sell agent's hotbag.\n\n!!! example\n\n    === \"Set Agent Hotbag\"\n\n        ```razor\n        sell\n        ```\n\n## useonce\n\n**Syntax**: `useonce ('add'/'addcontainer')`\n\n**Description**: This command will execute the UseOnce agent. If the `add` parameter is included, you can add items to your UseOnce list. If the `addcontainer` parameter is included, you can add all items in a container to your UseOnce list.\n\n!!! example\n\n    === \"Use top item\"\n\n        ```razor\n        useonce\n        ```\n\n    === \"Add to list\"\n\n        ```razor\n        useonce 'add'\n        ```\n\n    === \"Add to container\"\n\n        ```razor\n        useonce 'addcontainer'\n        ```\n\n# Gumps, Menus, & Prompt Commands\n\n## gumpresponse\n\n**Syntax**: `gumpresponse ('buttonID')`\n\n**Description**: Responds to a specific gump button\n\n!!! example\n\n    === \"Gump Response\"\n\n        ```razor\n        gumpresponse 4\n        ```\n\n## gumpclose\n\n**Syntax**: `gumpclose ['gumpID']`\n\n**Description**: This command will close the last gump that opened. You may pass an optional gump ID.\n\n!!! example\n\n    === \"Close last gump\"\n\n        ```razor\n        gumpclose\n        ```\n\n    === \"Close gump with id\"\n\n        ```razor\n        dclick '0x4000174B'\n        waitforgump 2341449854        \n        gumpclose 2341449854\n        ```\n\n## menu\n\n**Syntax**: `menu ('serial') ('index') ['false']`\n\n**Description**: Selects a specific index within a context menu. Razor will block the menu from appearing by default. If you include the optional `false` parameter, the context menu won't be blocked by Razor.\n\n!!! tip \"Context Menu\"\n    This command applies to the context menu accessed on some servers via a single-click (such as on yourself, to open your paperdoll or backpack).\n\n    ![context-menu](../images/contextmenu.png)\n\n!!! example\n\n    === \"Open Paperdoll\"\n\n        ```razor\n        menu 0 0\n        ```\n\n    === \"Open Backpack\"\n\n        ```razor\n        menu 0 1\n        ```\n\n## menuresponse\n\n**Syntax**: `menuresponse ('index') ('menuId') ['hue']`\n\n**Description**: Responds to a specific menu and menu ID\n\n!!! warning\n    This command does not work on context menus, they are for a less used menu type.  See the `menu` command to use context/popup menus.\n\n!!! example\n\n    === \"Description\"\n\n        ```razor\n        menuresponse 3 4\n        ```\n\n## promptresponse\n\n**Syntax**: `promptresponse ('prompt response')`\n\n**Description**: This command will respond to a prompt triggered from actions such as renaming runes or giving a guild title.\n\n!!! example\n\n    === \"Rename a recall rune\"\n\n        ```razor\n        dclicktype 'rune'\n        waitforprompt\n        promptresponse 'to home'\n        ```\n\n## waitforgump\n\n**Syntax**: `waitforgump (gump id/'any') [timeout]`\n\n**Description**: This command will wait for a gump. If no `gump id` is provided, it will wait for **any** gump. Default timeout is 30 seconds that can be changed by passing in a new timeout value in milliseconds.\n\n!!! tip \"Timeout parameter\"\n    To modify the default 30 second timeout for any gump, you must include include the `any` keyword before the timeout.\n\n    `waitforgump 'any' 5000` will wait for 5 seconds\n\n    `waitforgump 5000` will wait 30 seconds for a gump with the id of 5000\n\n!!! example\n\n    === \"Wait for any gump\"\n\n        ```razor\n        waitforgump 'any' \n        ```\n\n    === \"Wait for any gump for 10 seconds\"\n\n        ```razor\n        waitforgump 'any' 10000\n        ```\n\n    === \"Wait for specific gump\"\n\n        ```razor\n        waitforgump 4\n        ```\n\n    === \"Wait for specific gump for 5 seconds\"\n\n        ```razor\n        waitforgump 34252 5000\n        ```\n\n## waitformenu\n\n**Syntax**: `waitformenu (menu id/'any') [timeout]`\n\n**Description**: This command will wait for a context menu. If no `menu id` is provided, it will wait for **any** menu. Default timeout is 30 seconds that can be changed by passing in a new timeout value in milliseconds.\n\n!!! tip \"Timeout parameter\"\n    To modify the default 30 second timeout for any menu, you must include include the `any` keyword before the timeout.\n\n    `waitformenu 'any' 5000` will wait for 5 seconds\n\n    `waitformenu 5000` will wait 30 seconds for a menu with the id of 5000\n\n!!! warning\n    This command does not work on context menus, they are for an less used menu type.  See the `menu` command to use context/popup menus.\n\n!!! example\n\n    === \"Wait for any menu\"\n\n        ```razor\n        waitformenu\n        ```\n\n    === \"Wait for any menu for 5 seconds\"\n\n        ```razor\n        waitformenu 'any' 5000\n        ```\n\n    === \"Wait for specific menu\"\n\n        ```razor\n        waitformenu 4\n        ```\n\n## waitforprompt\n\n**Syntax**: `waitforprompt (promptid/'any') [timeout]`\n\n**Description**: This command will wait for a prompt before continuing. If no `prompt id` is provided, it will wait for **any** prompt. Default timeout is 30 seconds that can be changed by passing in a new timeout value in milliseconds.\n\n!!! tip \"Timeout parameter\"\n    To modify the default 30 second timeout for any gump, you must include include the `any` keyword before the timeout.\n\n    `waitforprompt 'any' 5000` will wait for 5 seconds\n\n    `waitforprompt 5000` will wait 30 seconds for a prompt with the id of 5000\n\n!!! example\n\n    === \"Renaming recalling rune\"\n\n        ```razor hl_lines=\"2\"\n        dclicktype 'rune'\n        waitforprompt\n        promptresponse 'to home'\n        ```\n\n    === \"Rename recalling rune with wait\"\n\n        ```razor hl_lines=\"2\"\n        dclicktype 'rune'\n        waitforprompt 'any' 5000\n        promptresponse 'to home'\n        ```\n\n# Ignore Commands\n\n## clearignore\n\n**Syntax**: `clearignore`\n\n**Description**: Clears your scripting ignore list\n\n!!! tip\n    Works in conjunction with `ignore` and `unignore`\n\n!!! example\n\n    === \"General\"\n\n        ```razor hl_lines=\"1\"\n        clearignore\n\n        if findtype 3572 backpack as 'wand' or findtype 3570 backpack as 'wand'\n            overhead 'found' 44\n            overhead 'wand' 44\n    \n            ignore 'wand'\n        else\n            overhead 'not found' 33\n        endif\n        ```\n\n## ignore\n\n**Syntax**: `ignore ('serial')` or `ignore ('list name')`\n\n**Description**: Adds a specific serial to the script engine's ignore list to avoid finding items when using commands like `findtype`\n\n!!! example\n\n    === \"Ignore by serial\"\n\n        ```razor hl_lines=\"3\"\n        clearignore\n\n        ignore '0x123A'\n        ```\n\n    === \"Ignore by variable\"\n\n        ```razor hl_lines=\"7\"\n        clearignore\n\n        if findtype 3572 backpack as 'wand' or findtype 3570 backpack as 'wand'\n            overhead 'found' 44\n            overhead 'wand' 44\n    \n            ignore 'wand'\n        else\n            overhead 'not found' 33\n        endif\n        ```\n\n## unignore\n\n**Syntax**: `unignore ('serial')` or `unignore ('list name')`\n\n**Description**: Removes a specific serial to the script engine's ignore list\n\n!!! example\n\n    === \"Unignore by serial\"\n\n        ```razor hl_lines=\"1\"\n        unignore '0x123A'\n        ```\n\n    === \"Unignore by variable\"\n\n        ```razor hl_lines=\"11\"\n        clearignore\n\n        if findtype 3572 backpack as 'wand' or findtype 3570 backpack as 'wand'\n            overhead 'found' 44\n            overhead 'wand' 44\n    \n            ignore 'wand'\n\n            wait 1000\n\n            unignore 'wand'\n        else\n            overhead 'not found' 33\n        endif\n        ```\n\n# List Commands\n\n## clearlist\n\n**Syntax**: `clearlist ('list name')`\n\n**Description**: This command will clear a list but doesn't remove it.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if list 'mylist' > 0\n            clearlist 'mylist'\n        endif\n\n        pushlist 'sample' 'hello'\n        ```\n\n## createlist\n\n**Syntax**: `createlist ('list name')`\n\n**Description**: This command will create an empty list.\n\n!!! example\n\n    === \"Simple\"\n\n        ```razor\n        if not listexists 'sample'\n            createlist 'sample'\n        endif\n\n        pushlist 'sample' 'hello'\n        ```\n\n    === \"Iterating Lists (foreach)\"\n\n        ```razor        \n        if not listexists 'words'\n            createlist 'words'\n        endif\n\n        pushlist 'words' 'loot'\n        pushlist 'words' 'taming'\n        pushlist 'words' 'felucca'\n        pushlist 'words' 'trammel'\n        pushlist 'words' 'pk'\n        pushlist 'words' 'pvp'\n        pushlist 'words' 'britannia'\n        pushlist 'words' 'dungeon'\n        pushlist 'words' 'crafting'\n        pushlist 'words' 'gm'\n        pushlist 'words' 'mobs'\n        pushlist 'words' 'spawn'\n        pushlist 'words' 'vendor'\n\n        # Start at loot, and keep saying each item in the list the end.\n        foreach 'word' in 'words'\n            # Show the current item in the list above your head\n            overhead 'word'\n        endfor\n        ```\n\n## poplist\n\n**Syntax**: `poplist ('list name') ('list value'/'front'/'back')`\n\n**Description**: This command will remove an item from the list. You can either pass in the specific item, or use `front` or `back` to remove the item from the front or back of the list.\n\n!!! tip\n    You can use `poplist` as an [expression](../expressions/#poplist).\n\n!!! example\n\n    === \"Remove first item in list\"\n\n        ```razor\n        createlist 'list'\n        pushlist 'list' 'hello'\n        pushlist 'list' 'bye'\n\n        poplist 'list' 'front'        \n        ```\n\n## pushlist\n\n**Syntax**: `pushlist ('list name') ('list item') ['front'/'back']`\n\n**Description**: This command will add an item to the list. You can define where in the list using `front` or `back` to remove the item from the front or back of the list. Default `pushlist` will add the item to end of the list.\n\n!!! example\n\n    === \"Add item to list\"\n\n        ```razor\n        createlist 'list'\n        pushlist 'list' 'hello'\n        pushlist 'list' 'bye'        \n        ```\n\n    === \"Add item to front of list\"\n\n        ```razor\n        createlist 'list'\n        pushlist 'list' 'hello'\n        pushlist 'list' 'bye' 'front'\n        ```\n\n## removelist\n\n**Syntax**: `removelist ('list name')`\n\n**Description**: This command will remove a list completely including all items in the list.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        removelist 'listname'        \n        ```\n# Messaging Commands\n\n## alliance\n\n**Syntax**: `alliance ('message to send')`\n\n**Description**: This command will force your character to say an alliance message passed as the parameter.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        alliance 'Allies assemble!'\n        ```\n\n## clearsysmsg\n\n**Syntax**: `clearsysmsg`\n\n**Description**: Clears the internal system message queue\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        sysmsg 'hello'\n        sysmsg 'bye'\n\n        if insysmsg 'hello'\n            say 'hello!'\n        endif\n\n        clearsysmsg\n\n        if insysmsg 'bye'\n            say 'this condition wont be met since it was cleared on line 8'\n        endif\n        ```\n\n## emote\n\n**Syntax**: `emote ('message to send') [hue]`\n\n**Description**: This command will force your character to emote the message passed as the parameter.\n\n!!! tip\n    This command will append `*` around the emote so `emote 'smiles'` will be displayed in game as `*smiles*`.\n\n!!! example\n\n    === \"Emote\"\n\n        ```razor\n        emote 'smiles'\n        ```\n\n    === \"Emote with hue\"\n\n        ```razor\n        emote 'smiles in another color' 454\n        ```\n\n## guild\n\n**Syntax**: `guild ('message to send')`\n\n**Description**: This command will force your character to say a guild message passed as the parameter.\n\n!!! example\n\n    === \"Guild message\"\n\n        ```razor\n        guild 'Hello fellow guildmates!'\n        ```\n\n## overhead\n\n**Syntax**: `overhead ('text') ['color'] ['serial']`\n\n**Description**: This command will display a message over your head. Only you can see this.\n\n!!! example\n\n    === \"Overhead message\"\n\n        ```razor\n        if stam = 100\n            overhead 'ready to go!'\n        endif\n        ```\n\n## say\n\n**Syntax**: `say ('message to send') [hue]` or `msg ('message to send') [hue]`\n\n**Description**: This command will force your character to say the message passed as the parameter.\n\n!!! example\n\n    === \"Say message\"\n\n        ```razor\n        say 'Hello world!'\n        ```\n\n    === \"Say message with hue\"\n\n        ```razor\n        say 'Hello world!' 454\n        ```\n\n## sysmsg\n\n**Syntax**: `sysmsg ('message to display in system message')`\n\n**Description**: This command will display a message in the lower-left of the client.\n\n!!! example\n\n    === \"Description\"\n\n        ```razor hl_lines=\"2\"\n        if stam = 100\n            sysmsg 'ready to go!'\n        endif\n        ```\n\n## waitforsysmsg\n\n**Syntax**: `waitforsysmsg ('message to wait for') [timeout]` or `wfsysmsg ('message to wait for') [timeout]`\n\n**Description**: This command will wait a specific message to be added to the system message queue before continuing.  Default timeout is 30 seconds that can be changed by passing in a new timeout value in milliseconds.\n\n!!! example\n\n    === \"Wait for system message\"\n\n        ```razor hl_lines=\"1\"\n        waitforsysmsg 'ready to go'\n        overhead 'Ready!'\n        ```\n\n    === \"Wait for system message for 5 seconds\"\n\n        ```razor hl_lines=\"1\"\n        waitforsysmsg 'ready to go' 5000\n        overhead 'Done waiting'\n        ```\n\n## whisper\n\n**Syntax**: `whisper ('message to send') [hue]`\n\n**Description**: This command will force your character to whisper the message passed as the parameter.\n\n!!! example\n\n    === \"Whisper message\"\n\n        ```razor\n        whisper 'Hello world!'\n        ```\n\n    === \"Whisper message with hue\"\n\n        ```razor\n        whisper 'Hello world!' 454\n        ```\n\n## yell\n\n**Syntax**: `yell ('message to send') [hue]`\n\n**Description**: This command will force your character to yell the message passed as the parameter.\n\n!!! example\n\n    === \"Yell message\"\n\n        ```razor\n        yell 'Hello world!'\n        ```\n\n    === \"Yell message with hue\"\n\n        ```razor\n        yell 'Hello world!' 454\n        ```\n\n# Targeting Commands\n\n## clearall\n\n**Syntax**: `clearall`\n\n**Description**: Combines the following actions into one command: `Cancel Current Target, Clear Target Queue, Drop What You Are Currently Holding and Clear Drag/Drop Queue` into a single command.\n\n!!! example\n\n    === \"Clear on sysmsg message\"\n\n        ```razor\n        if insysmsg 'cannot find'\n            clearall\n        endif\n        ```\n\n## lasttarget\n\n**Syntax**: `lasttarget`\n\n**Description**: This command will target your last target set in Razor.\n\n!!! example\n\n    === \"Cast on last target\"\n\n        ```razor\n        cast 'magic arrow'\n        waitfortarget\n        lasttarget\n        ```\n\n## setlasttarget\n\n**Syntax**: `setlasttarget ('serial')`\n\n**Description**: This command will set the last target to the serial you pass as a parameter.\n\n!!! tip\n    You can use `hotkey 'Set Last Target'` if you prefer getting a cursor and targetting a specific object.\n\n!!! example\n\n    === \"Set last target on variable\"\n\n        ```razor\n        setvar 'dog' 0x239\n        setlasttarget 'dog'\n        ```\n\n    === \"..with findtype\"\n\n        ```razor\n        // find a dog\n        if findtype '217' as 'dog'\n            setlasttarget 'dog'\n            cast 'lightning'\n            wft\n            target 'dog'\n        endif\n        ```\n\n## target\n\n**Syntax**: `target ('closest/random/next/prev') [type1,type2] [humanoid/monster]` or `target ('closest/random/next/prev') [type1!type2] [humanoid/monster]` or `target (serial)` or `target (clear/cancel)`\n\n**Description**: This command will target a specific mobile based either the type searched for or the serial. If you provide a list of target types, you can use `,` for a general list and `!` for a priority list.\n\n| Type              | Notoriety Name                                   | Notoriety Color                            |\n| ----------------- | ------------------------------------------------ | ------------------------------------------ |\n| `nonfriendly`     | Attackable, Criminal, Enemy, Murderer            | Gray (but not criminal), Gray, Orange, Red |\n| `friendly`        | Innocent, Guild/Ally                             | Blue, Green                                |\n| `enemy`           | Enemy                                            | Orange                                     |\n| `red`/`murderer`  | Murderer                                         | Red                                        |\n| `gray`/`grey`     | Attackable, Criminal                             | Gray (but not criminal), Gray              |\n| `criminal`        | Criminal                                         | Gray                                       |\n| `blue`/`innocent` | Innocent                                         | Blue                                       |\n| `friend`          | Based on your [friends list](../../help/friends) | Any                                        |\n\n| List Type | Delimiter | Description                                                                                                        |\n| --------- | --------- | ------------------------------------------------------------------------------------------------------------------ |\n| General   | `,`       | When the script tries to acquire a target, it will look for all the target types passed in the list. See Examples. |\n| Priority  | `!`       | When the script tries to acquire a target, it will prioritize each type. See Examples.                             |\n\n!!! example\n\n    === \"Specific target\"\n\n        ```razor\n        cast 'lightning'\n        waitfortarget\n        target '0xBB3'\n        ```\n\n    === \"General list\"\n\n        ```razor\n        cast 'lightning'\n        waitfortarget\n\n        // General list using a ,\n        // If a red mobile is closer than a gray mobile, this will target the red mobile\n        target closest gray,red\n        ```\n\n    === \"Priority list\"\n\n        ```razor\n        cast 'lightning'\n        waitfortarget\n\n        // Priority list using a !\n        // If a red mobile is closer than a gray mobile, this will target the gray mobile\n        target closest gray!red\n        ```\n\n    === \"Target closest red\"\n\n        ```razor\n        cast 'lightning'\n        waitfortarget\n        target closest 'red'\n        ```\n\n    === \"Target closest gray or red monster\"\n\n        ```razor\n        cast 'lightning'\n        waitfortarget\n        target closest 'gray,red' monster\n        ```\n\n    === \"Target random mobile\"\n\n        ```razor\n        cast 'lightning'\n        waitfortarget\n        target random\n        ```\n\n    === \"Target random red monster\"\n\n        ```razor\n        cast 'lightning'\n        waitfortarget\n        target random 'red' monster\n        ```\n\n    === \"Next humanoid target\"\n\n        ```razor        \n        target next humanoid\n        ```    \n\n    === \"Cancel current target\"\n\n        ```razor        \n        target cancel\n        ```\n    \n    === \"Clear target queue\"\n\n        ```razor        \n        target clear\n        ```\n\n## targetrelloc\n\n**Syntax**: `targetrelloc (x-offset) (y-offset)`\n\n**Description**: This command will target a specific location on the map relative to your position.\n\n!!! example\n\n    === \"Target 1 X, 1 Y from player location\"\n\n        ```razor\n        cast 'fire field'\n        waitfortarget\n        targetrelloc 1 1\n        ```\n\n## targetloc\n\n**Syntax**: `targetloc (x) (y) (z)`\n\n**Description**: This command will target a specific location on the map.\n\n!!! example\n\n    === \"Specific location\"\n     \n        ```razor\n        cast 'fire field'\n        waitfortarget\n        targetloc 5923 1145 0\n        ```\n\n## targettype\n\n**Syntax**: `targettype ('name of item or mobile type'/'graphicId') [inrange (true/false)/backpack] [hue]`\n\n**Description**: This command will target a specific type of mobile or item based on the graphic id or based on the name of the item or mobile.\n\n!!! tip \"Range Check\"\n    If the optional parameter is passed in as `true` only items within the range of `2` tiles will be considered. If the optional parameter is passed in as `backpack` only items in your backpack will be considered.\n\n!!! tip \"Getting the graphic name or ID\"\n    To get the name or the ID of item, use the `>info` command in Razor and click on the item. You can use either the `Item Name` or `Id`.\n\n    ![item-command](../images/infocommand.png)\n\n!!! example\n\n    === \"Target by name (any range)\"\n\n        ```razor hl_lines=\"3\"\n        dclicktype 'dagger'\n        waitfortarget\n        targettype 'robe'\n        ```\n\n    === \"Target by type (any range)\"\n\n        ```razor hl_lines=\"3\"\n        dclick '0x4005ECAF'\n        waitfortarget\n        targettype '0x1F03'\n        ```\n\n    === \"Target by type using serial (in range)\" \n\n        ```razor hl_lines=\"3\"\n        dclick '0x4005ECAF'\n        waitfortarget\n        targettype '0x1F03' true\n        ```\n    \n    === \"Target by type using name (in range)\" \n\n        ```razor hl_lines=\"3\"\n        dclick 'dagger'\n        waitfortarget\n        targettype 'robe' true\n        ```\n\n    === \"Target by name (in backpack)\" \n           \n        ```razor hl_lines=\"3\"\n        dclicktype 'dagger' backpack\n        waitfortarget\n        targettype 'robe' backpack\n        ```\n    \n    === \"Target by name with hue (in backpack)\" \n           \n        ```razor hl_lines=\"3\"\n        dclicktype 'dagger' backpack\n        waitfortarget\n        targettype 'robe' backpack 45\n        ```\n\n## waitfortarget\n\n**Syntax**: `waitfortarget [pause in milliseconds]` or `wft [pause in milliseconds]`\n\n**Description**: This command will cause the script to pause until you have a target cursor.  By default it will wait 30 seconds but you can define a specific wait time if you prefer.\n\n!!! example\n\n    === \"Cast and wait\"\n\n        ```razor hl_lines=\"2\"\n        cast 'energy bolt'\n        waitfortarget\n        hotkey 'Target Closest Enemy'\n        ```\n\n    === \"Using 'wft' shorthand on last target\"\n\n        ```razor hl_lines=\"2\"\n        cast 'energy bolt'\n        wft\n        target 'last'\n        ```\n\n# Timer Commands\n\n## createtimer\n\n**Syntax**: `createtimer ('timer name')`\n\n**Description**: This command will create a timer and immediately start counting up from 0\n\n!!! example\n\n    === \"Create Timer\"\n\n        ```razor        \n        if not timerexists 'sample'\n            createtimer 'sample'\n        endif           \n        ```\n\n## removetimer\n\n**Syntax**: `removetimer ('timer name')`\n\n**Description**: This command will remove/delete a specific timer\n\n!!! example\n\n    === \"Delete Timer\"\n\n        ```razor        \n        if timerexists 'sample'\n            removetimer 'sample'\n        endif           \n        ```\n\n## settimer\n\n**Syntax**: `settimer ('timer name') ('number in milliseconds')`\n\n**Description**: This command will set a timer to a specific number and start to count up immediately.\n\n!!! example\n\n    === \"Set Timer\"\n\n        ```razor\n        // Create a new timer\n        if not timerexists 'sample'\n            createtimer 'sample'\n        endif\n\n        // Reset every 10 seconds\n        if timer 'sample' > 10000\n            settimer 'sample' 0\n        endif            \n        ```\n"
  },
  {
    "path": "help/docs/guide/comments.md",
    "content": "---\ntitle: Script Comments\ndescription: A simple overview on how to leave comments in your UO Razor Scripts\n---\n\n# Comments Overview\n\nYou can use `//` or `#` at the beginning of the line to leave comments in your script.  These lines will be ignored during execution.\n\n## // or #\n\n!!! example\n\n    === \"Using //\"\n\n        ```razor\n        // Hello world example\n        say 'hello'\n        //say 'world'\n        ```\n\n    === \"Using #\"\n\n        ```razor\n        # Hello world example\n        say 'hello'\n        # say 'world'\n        ```\n"
  },
  {
    "path": "help/docs/guide/expressions.md",
    "content": "---\ntitle: Script Expressions\ndescription: A list of all script expressions for Razor, complete with descriptions and examples\n---\n\n# Statements & Loops\n\nAs found in the Razor macro system, you can use `if`, `for`, `foreach`, and `while` when writing a script to add some basic logic and flows.\n\n## if\n\n**Syntax**:\n\n```razor\nif (expression)\n    // commands to execute if this expression is true\nelseif (expression)\n    // commands to execute if the first expression was false, and this expression is true\nelse\n    // commands to execute if both expressions above were false, default to running these\nendif\n```\n\n**Description**: This selects a path to execute based on the value of a boolean expression. An `if` statement can be combined with `else` or `elseif` to choose two or more distinct paths based on the result of the boolean expression. All `if` statements must end with `endif`.\n\n!!! example\n\n    === \"if/endif\"\n\n        ```razor\n        if stam = 100\n            overhead 'Stam at 100!'\n        endif\n        ```\n\n    === \"if/elseif/else\"\n\n        ```razor\n        if stam = 100\n            say 'Stamina full'\n        elseif stam < 20\n            say 'Still a ways to go'\n        elseif stam < 60\n            say 'Getting closer'\n        else\n            say 'waiting'\n        endif\n        ```\n\n    === \"if/elseif\"\n\n        ```razor\n        if stam = 100\n            say 'Stamina full'\n        elseif stam < 20\n            say 'Still a ways to go'\n        elseif stam < 60\n            say 'Getting closer'\n        endif\n        ```\n\n    === \"Using 'not'\"\n\n        ```razor\n        if not stam = 100\n            say 'Stamina is not full'    \n        endif\n        ```\n\n## for\n\n**Syntax**:\n\n```razor\nfor ('number')\n    // commmands to execute the number of times defined in the for statement\nendfor\n```\n\n**Description**: This allows you to execute a block of commands a specific number of times. All `for` loops must end with `endfor`.\n\n!!! tip\n    You can use the [index](variables.md#index-variable) variable to track your position in the for loop.\n\nWhen using `for` or `while` you have access to the `index` variable. This can be used with `overhead` (for example) to indicate the current loop number.\n\n!!! example\n\n    === \"Say 'Hello' 10 times\"\n\n        ```razor        \n        for 10\n            say 'hello'\n            wait 1000\n        endfor\n        ```\n\n    === \"Output current loop number\"\n\n        ```razor\n        for 10\n            wait 1000\n            overhead 'index'\n        endfor\n        ```\n\n## foreach\n\n**Syntax**:\n\n```razor\nforeach ('variable') in ('list')\n    // commands to execute for each item that is in a list\nendfor\n```\n\n**Description**: This allows you to iterate over a list containing values. All `foreach` loops must end with `endfor`.\n\n!!! example\n\n    === \"Loop through each item in a list\"\n\n        ```razor        \n        createlist 'mylist'\n        pushlist 'mylist' '0x1'\n        pushlist 'mylist' '0x2'\n\n        foreach 'item' in 'mylist'\n           overhead 'item'\n        endfor\n        ```\n\n## while\n\n**Syntax**:\n\n```razor\nwhile ('expression')\n    // commands to execute as long as the expression is remains true\nendwhile\n```\n\n**Description**: This allows you execute a block of commands while a certain expression is true. All `while` loops must end with `endwhile`.\n\n!!! example\n\n    === \"While\"\n\n        ```razor\n        while hits < 100\n            say 'I need a heal!'\n            wait 1000\n        endwhile\n        ```\n\n# Expression Operators\n\nWhen using the `if` or `while` conditions, you can access the following expressions in the statement.\n\nThe following operators are supported:\n\n| Operator | Description           |\n| -------- | --------------------- |\n| =        | Equal                 |\n| ==       | Equal                 |\n| !=       | Not equal             |\n| <        | Less than             |\n| <=       | Less than or equal    |\n| >        | Greater than          |\n| >=       | Greater than or equal |\n\n# Expressions\n\nExpressions are combined with statements like `if` and `while` to alter the execution path of your script.\n\nBelow are the several different types of expressions you can use broken into categories.\n\n# List Expressions\n\n## inlist\n\n- `inlist ('list name') ('list item')`\n\nDescription: Used to check if a specific item is in a list\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if inlist 'my_list' 'item1'\n            overhead 'found item!'\n        endif\n        ```   \n\n## list\n\n- `list ('list name')`\n\nDescription: Used to check how many items are in a specific list\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if list 'mylist' = 10\n            overhead '10 items in your list'\n        endif\n        ```\n\n## listexists\n\n- `listexists ('list name')`\n\nDescription: Used to check if a list exists with a specific name.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if not listexists 'mylist'\n            createlist 'mylist'\n        endif\n        ```\n\n## poplist\n\n- `poplist ('list name') ('list value'/'front'/'back')`\n\nDescription: This command will remove (pop) an item from the list. You can either pass in the specific item, or use `front` or `back` to remove the item from the front or back of the list.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if poplist 'mylist' back as 'item'\n            overhead 'item'\n        endif\n        ```\n\n# Misc Expressions\n\n## count/counter\n\n- `count ('name of counter')`\n- `counter ('name of counter')`\n- `count ('name of item') [hue]`\n- `count (graphicID) [hue]`\n\nDescription: Used to get the current amount of a specific item in player's backpack.\nOmitting the hue argument will result in count of all items of the specified type regardless of their hue.\nThe expression can be used either directly by item type and hue, or by referencing a named counter manually set up in the Counters tab.\n[More info](../help/displaycounters.md#counters)\n\n!!! example\n\n    === \"Counting garlic\"\n\n        ```razor\n        if count 'garlic' < 5\n            say 'getting low on garlic'\n        endif\n        ```\n        \n    === \"Counting runebooks\"\n    \n        ```razor\n        if count 'spellbook' '1121' == 0\n            say 'no runebooks found!'\n        endif\n        ```\n        \n    === \"Detecting fancy coins\"\n\n        ```razor\n        if count 'gold coin' > count 'gold coin' 0\n            overhead 'woot woot fancy coins in the pack!'\n        endif\n        ```\n\n## findtype\n\n- `findtype ('name of item') [inrangecheck (true/false)/backpack] [hue]` OR `findtype (graphicID) [inrangecheck (true/false)/backpack] [hue]`\n\nDescription: Used to check if a specific item name of graphic ID exists. Range check, if true, will check within 2 tiles.\n\n!!! tip \"The `as` keyword\"\n    If you use `findtype` along with `as` you can assign a temporary variable to use throughout the script. See example below.\n\n!!! tip \"In-Game Info Gump\"\n    Not sure what name to enter or graphic ID to enter? Type `>info` and click on any item or mobile for more information.\n\n    ![item-command](../images/infocommand.png)\n\n    Click the blue dot next to the value you want to copy to the clipboard.\n\n!!! example\n\n    === \"Find a saw\"\n\n        ```razor\n        if findtype 'saw'\n            say 'found saw'\n        endif\n        ```\n    \n    === \"Find a saw using graphic id\"\n\n        ```razor\n        if findtype '4148'\n            say 'found saw'\n        endif\n        ```\n\n    === \"Find a saw within 2 tiles\"\n\n        ```razor\n        if findtype 'saw' true\n            say 'found saw within 2 tiles'\n        endif\n        ```\n\n    === \"Find a saw in your backpack\"\n\n        ```razor\n        if findtype 'saw' backpack\n            say 'found saw in my pack'\n        endif\n        ```\n\n    === \"Find a dagger and use it (using as)\"\n\n        ```razor hl_lines=\"1\"\n        if findtype 'dagger' as 'mydagger'\n            overhead 'found dagger'\n            dclick 'mydagger'\n        endif\n        ```\n\n    === \"Find a dagger in backpack with a hue\"\n\n        ```razor\n        if findtype 'dagger' backpack 45 as 'mydagger'\n            overhead 'found dagger'\n            dclick 'mydagger'\n        endif\n        ```\n\n## insysmsg\n\n- `insysmsg ('message to look for')`\n- `insysmessage ('message to look for')`\n\nDescription: Used to check if certain text appears within the system message log.\n\n!!! tip \"System Message Queue\"\n    Not sure if a specific message is in Razor's system message queue? Type `>sysmsgs` to see what Razor can find.\n\n    Using `clearsysmsg` will clear out the queue completely.\n\n!!! example\n\n    === \"Check for message\"\n\n        ```razor\n        if insysmsg 'too far away'\n            overhead 'You are too far away'\n        endif\n        ```   \n\n## itemcount\n\n- `itemcount`\n\nDescription: Used to return the current number of items you're carrying\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if itemcount < 125\n            overhead 'I still have room!'\n        endif\n        ```\n\n## queued\n\n- `queued`\n\nDescription: Used to check if your current queue is active (from restocking, organizing, etc)\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n            if queued\n                overhead 'Queue is active'\n            else\n                overhead 'No queue'\n            endif\n        ```\n\n    === \"Organizer\"\n\n        ```razor\n        overhead 'Organizing'\n\n        organizer 1\n\n        while queued\n            overhead 'Currently Organizing'\n            wait 500 \n        endwhile\n\n        overhead 'Organized'\n        ```\n\n    === \"Restock\"\n\n        ```razor\n        overhead 'Restocking'\n\n        restock 11\n        waitfortarget \n        target 'self'\n\n        while queued\n            overhead 'Currently restocking'\n            wait 500 \n        endwhile\n\n        overhead 'Restocked'\n        ```\n\n## targetexists\n\n- `targetexists ['any'/'beneficial'/'harmful'/'neutral']`\n\nDescription: Used to check if the client current has a target cursor up\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if targetexists 'beneficial'\n            overhead 'Beneficial target found'\n        elseif targetexists 'harmful'\n            overhead 'Harmful target found'\n        endif\n        ```\n\n## varexist\n\n- `varexist`\n- `varexists`\n\nDescription: Used to check if a variable exists.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if not varexist 'myrunebook'\n            overhead 'Runebook variable not found -- select one'\n            setvar 'myrunebook'\n        endif\n\n        dclick 'myrunebook'\n        waitforgump 'any'\n        gumpresponse 5\n        ```\n\n# Player Attribute Expressions\n\n## diffhits\n\n- `diffhits`\n- `diffhp`\n\nDescription: Used to get the difference between you max hits and current hits.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if diffhits > 40\n            overhead 'I need a heal!'\n        endif\n        ```\n\n## diffmana\n\n- `diffmana`\n\nDescription: Used to get the difference between you max mana and current mana.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if diffmana > 40\n            skill 'Meditation'\n        endif\n        ```\n\n## diffstam\n\n- `diffstam`\n\nDescription: Used to get the difference between you max stamina and current stamina.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n         if diffstam > 30\n            overhead 'Need stamina'\n        endif\n        ```\n\n## diffweight\n\n- `diffweight`\n\nDescription: Used to get the difference between you max weight and current weight.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if diffweight > 20\n            overhead 'I can lift 20 more stone'\n        endif\n        ```\n\n## followers\n\nDescription: Used to get the current number of followers.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if followers = 0\n            overhead 'No one following me!'\n        else\n            overhead 'I have followers'\n        endif\n        ```\n\n    === \"..used with maxfollowers\"\n\n        ```razor\n        if followers < maxfollowers\n            overhead 'You can have more followers!'\n        else\n            overhead 'You hit your followers limit'\n        endif\n        ```\n\n## findbuff\n\n- `findbuff 'name of buff/debuff`\n\nDescription: Used to check if a specific buff/debuff is applied to you.\n\n!!! example\n\n    === \"Check for magic reflection\"\n\n        ```razor\n        if findbuff 'magic reflection'\n            overhead 'Im set!'\n        else\n            cast 'magic reflection'\n            wft\n            target 'self'\n        endif\n        ```\n\n## hidden\n\n- `hidden`\n\nDescription: Used to check if you are hidden.\n\n!!! example\n\n    === \"Check if hidden\"\n\n        ```razor\n        if hidden\n            overhead 'they cant see me'\n        endif\n        ```\n\n## hp & maxhp\n\n- `hp`\n- `maxhp`\n- `hits`\n- `maxhits`\n\nDescription: Used to get your current or max hit points/health levels.\n\n!!! example\n\n    === \"Example 1\"\n\n        ```razor\n        while hp < 100\n            say 'not at 100 yet'\n            wait 5000\n        endwhile\n        ```\n\n    === \"Example 2\"\n\n        ```razor\n        if maxhp = 120\n            say 'Full hp!'\n        endif\n        ```\n\n## lhandempty\n\n- `lhandempty`\n\nDescription: Used to check if your left hand is empty\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if lhandempty\n            hotkey 'empty right hand!'\n        endif\n        ```\n\n## invuln\n\n- `invuln`\n- `invul`\n- `blessed`\n\nDescription: Used to get your invulnerable status\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if invuln\n            overhead 'I feel.. so powerful.'\n        endif\n        ```\n\n\n## mana & maxmana\n\n- `mana`\n- `maxmana`\n\nDescription: Used to get your current or max mana levels.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        while mana < maxmana\n            skill 'meditation'\n            wait 11000\n        endwhile\n        ```\n\n## maxfollowers\n\nDescription: Used to get the maximum number of allowed followers.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if followers = maxfollowers\n            overhead 'You hit your limit'       \n        endif\n        ```\n\n    === \"..used with followers\"\n\n        ```razor\n        if followers < maxfollowers\n            overhead 'You can have more followers!'\n        else\n            overhead 'You hit your followers limit'\n        endif\n        ```\n\n## maxweight\n\n- `maxweight`\n\nDescription: Used to get your max allowed weight.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if weight <= maxweight\n            say 'I am overweight'\n        endif\n        ```\n\n## mounted\n\n- `mounted`\n\nDescription: Used to check if you are currently on a mount\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if mounted\n            say 'mounted'\n        else\n            say 'not mounted'\n        endif\n        ```\n\n## name\n\n- `name`\n\nDescription: Used to get your name of the currently logged in character\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if name = 'Quick'\n            overhead 'thats me!'\n        endif\n        ```\n\n## paralyzed\n\n- `paralyzed`\n\nDescription: Used to check if you are currently paralyzed.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if paralyzed\n            overhead 'I cannot move!'\n        endif\n        ```\n\n## poisoned\n\n- `poisoned`\n\nDescription: Used to check if you are currently poisoned.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if poisoned\n            hotkey 'drink cure'\n        endif\n        ```\n\n## position\n\n- `position (x, y)`\n- `position (x, y, z)`\n\nDescription: Used to check if your current position matches the provided.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if position 2729 2133\n            overhead 'You are currently in front of the Bucs Den teleporter'\n        elseif position 2728 2133 5\n            overhead 'You are standing on the Bucs Den teleporter'\n        endif\n        ```\n\n## rhandempty\n\n- `rhandempty`\n\nDescription: Used to check if your right hand is empty\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if rhandempty\n            hotkey 'empty right hand!'\n        endif\n        ```\n\n## skill\n\n- `skill ('name')`\n\nDescription: Used to get the current skill level for a given skill.\n\n!!! tip \"Supported skill names\"\n    Razor used to rely on a static list of names but now reads from your client's skills.mul file for the names of the skill.\n\n!!! tip \"Real vs Shown (or Value)\"\n    By default, Razor will compare against the shown skill value that includes other factors such as your stats. If you'd like to compare to the real skill value, use the `!` in front of `skill`.  See the example below.\n\n!!! example\n\n    === \"Compare Shown Skill\"\n\n        ```razor\n        if skill 'magery' < 62.5\n            cast 'invisibility'\n            waitfortarget\n            target 'self'\n        endif\n        ```\n    \n    === \"Compare Real Skill\"\n\n        ```razor\n        // Note the ! at the end of the skill expression command\n        // This tells Razor to look at the real value, not the shown value\n        if skill! 'magery' < 62.5\n            cast 'invisibility'\n            waitfortarget\n            target 'self'\n        endif\n        ```\n\n## stam & maxstam\n\n- `stam`\n- `maxstam`\n\nDescription: Used to get your current stamina or max stamina.\n\n!!! example\n\n    === \"General (stam)\"\n\n        ```razor\n        if stam < 30\n            say 'I need to rest'\n        endif\n        ```\n\n    === \"General (maxstam)\"       \n\n        ```razor\n        if maxstam = 120\n            say 'I feel so powerful!'\n        endif\n        ```\n\n## str, dex & int\n\n- `str`\n- `dex`\n- `int`\n\nDescription: Used to get your current strength, dexterity and intelligence.\n\n!!! example\n\n    === \"Strength\"\n\n        ```razor\n        if str = 100\n            say 'Strength does not come from physical capacity. It comes from an indomitable will.'\n        endif\n        ```\n\n    === \"Dexterity\"\n\n        ```razor\n        if dex = 100\n            say 'Dexterity comes by experience and practice.'\n        endif\n        ```\n\n    === \"Intelligence\"\n\n        ```razor\n        if str = 100\n            say 'The true sign of intelligence is not knowledge but imagination.'\n        endif\n        ```\n\n## warmode\n\n- `warmode`\n\nDescription: Used to get your current combat/war status\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if warmode\n            overhead 'Lets fight'\n        else\n            overhead 'Peace to you'\n        endif\n        ```\n\n## weight\n\n- `weight`\n\nDescription: Used to get your current weight.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if weight = 300\n            say 'I feel heavy'\n        endif\n        ```\n\n# Timer Expressions\n\n## timer\n\n- `timer ('name')`\n\nDescription: Used to check how much time is left in an existing timer\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        // Create a new timer\n        if not timerexists 'sample'\n            createtimer 'sample'\n        endif\n\n        // Reset every 10 seconds\n        if timer 'sample' > 10000\n            settimer 'sample' 0\n        endif\n        ```\n\n    === \"Alert\"\n\n        ```razor\n        # Create a new timer\n        createtimer 'alert'\n\n        while not dead            \n    \n            // Reset every 10 seconds\n            if timer 'alert' > 10000\n                overhead 'ALERT TRIGGERED!'\n                settimer 'alert' 0\n            endif\n\n        endwhile\n\n        \n        ```\n\n## timerexists\n\n- `timerexist ('name')`\n\nDescription: Used to check if a timer exists\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        // Create a new timer\n        if not timerexists 'sample'\n            createtimer 'sample'\n        endif\n\n        // Reset every 10 seconds\n        if timer 'sample' > 10000\n            settimer 'sample' 0\n        endif\n        ```\n"
  },
  {
    "path": "help/docs/guide/index.md",
    "content": "---\ndescription: A comprehensive guide to the UO Razor scripting engine, including descriptions & examples for all commands, expressions, keywords\n---\n\n# Introduction\n\nThe **UO Razor Scripting Engine** is a _\"command based scripting language\"_ designed to make it easier to read, create, edit and share UO Razor scripts.\n\nTo learn more about this version of Razor, please visit the [home page](https://www.razorce.com).\n\n# Quick Start\n\nCheck out the various [Commands](commands.md), [Expressions](expressions.md), and [Keywords](keywords.md) that are available along with working examples.\n\n# Design\n\nThis scripting engine attempts to maintain and improve existing Razor functionality, offer quality of life improvements over the existing macro system, and provide an easily approachable syntax that is accessible regardless of skill level.\n\nFor example, instead of having to do the following with a Razor macro:\n\n1. Record macro\n2. Double click dagger\n3. Stop recording\n4. Right-click on dagger\n5. Select Double Click use by type\n\nYou can simply type:\n\n```razor\ndclicktype 'dagger'\n```\n\n# Razor Scripts vs. Razor Macros\n\nWhile updates to Razor have made it easier to edit and share macros, one of the core issues is that they weren't designed to be read and edited by users directly, instead the serialized format they're saved in expects you to use the macro editor in Razor.\n\nFor example, even a basic macro that casts blade spirit, waits for the target and casts a relative location based on your position can be difficult to read to the untrained eye.\n\n```razor\nAssistant.Macros.MacroCastSpellAction|33\nAssistant.Macros.WaitForTargetAction|30\nAssistant.Macros.TargetRelLocAction|3|1\n```\n\nWith a Razor script, it becomes:\n\n```razor\ncast 'blade spirits'\nwaitfortarget\ntargetrelloc 3 1\n```\n\nAnother example using a script that uses detect hidden, waits for target, targets self, waits .40 seconds, checks for a system message, says something and targets the closest mobile.\n\n```razor\nAssistant.Macros.UseSkillAction|14\nAssistant.Macros.WaitForTargetAction|30\nAssistant.Macros.HotKeyAction|1059|\nAssistant.Macros.PauseAction|00:00:00.4000000\nAssistant.Macros.IfAction|4|0|you can see nothing\nAssistant.Macros.ElseAction\nAssistant.Macros.SpeechAction|0|38|3|ENU|2|16|52|I Ban Thee\nAssistant.Macros.WaitForTargetAction|30\nAssistant.Macros.HotKeyAction|2003|\nAssistant.Macros.EndIfAction\n```\n\nWith a UO Razor script, it becomes:\n\n```razor\nskill 'detecthidden'\nwaitfortarget\ntarget 'self'\n\nwait 400\n\nif insysmsg 'you see nothing'\n    overhead 'All clear'\nelse\n    say 'I ban thee'\n    waitfortarget\n    target closest grey humanoid\nendif\n```\n\nAs you can see, while maintaining the same functionality of macros, a Razor script is much easier to read, edit and share.\n\n!!! tip \"Convert Macros to Scripts\"\n    **Right-Click** on any macro to convert it to a script.\n\n# Script Editor\n\nUO Razor scripts can be written using any text editor. The script editor built into Razor offers syntax highlighting and auto-completion.\n\n!!! tip \"Window Size\"\n    You can resize the Razor window to make the script editor larger. You can also adjust the size of the script list to give you additional room.\n\nHere are a list of some of keyboard shortcuts available in the editor:\n\n## General/Misc\n\nCommon text editor shortcuts (such as `Ctrl-C` and `Ctrl-V` for copy/paste are not listed):\n\n- ++ctrl+g++: Goto to a specific line dialog\n\n- ++ctrl+f++: Find/Search dialog\n- ++f3++: Find next\n- ++ctrl+h++: Search & replace dialog\n- ++ctrl+shift+c++: Comment / Uncomment selected code\n- ++alt+\"Mouse Drag\"++: Select multiple lines of text\n- ++ctrl+home++: Go to the first line\n- ++ctrl+end++: Go to the last line\n- ++alt+up++: Move selected lines up\n- ++alt+down++: Move selected lines down\n\n## Bookmarks\n\n- ++ctrl+b++: Bookmark line\n- ++ctrl+shift+b++: Remove bookmark\n- ++ctrl+b++: Move cursor to next bookmark\n- ++ctrl+shift+n++: Move cursor to previous bookmark\n\n## Auto-Complete\n\n- ++ctrl+space++: Open auto-complete menu\n\n## Zoom\n\n- ++ctrl+\"Mouse Wheel Up\"++: Zoom in\n- ++ctrl+\"Mouse Wheel Down\"++: Zoom out\n- ++ctrl+0++: Reset zoom\n\n# About\n\nThe **Razor Scripting Engine** was designed and implemented by [Quick](https://github.com/markdwags) and is released under GPLv3."
  },
  {
    "path": "help/docs/guide/keywords.md",
    "content": "---\ntitle: Script Keywords\ndescription: A list of all script keywords for Razor, complete with descriptions and examples\n---\n\n# Keywords Overview\n\n## and\n\nSyntax: `(statement) and (statement)`\n\nDescription: The `and` keyword links statements together and if all statements are `true` the condition is met.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if insysmsg 'hello' and insysmsg 'bye'\n            say 'found'\n        endif\n        ```\n\n## as\n\nSyntax: `(statement) as (variable)`\n\nDescription: The `as` keyword works in conjunction with the `findtype` expression.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if findtype 'dagger' as 'mydagger'\n            overhead 'found dagger'\n            dclick 'mydagger'\n        endif\n        ```\n\n## break\n\nSyntax: `break`\n\nDescription: The `break` keyword terminate the closest enclosing loop such as a `for` loop.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        for 100\n            if stam = 100\n                break\n            else\n                say 'loop again'\n            endif\n        endfor\n        ```\n\n## continue\n\nSyntax: `continue`\n\nDescription: The `continue` keyword passes control to the next iteration of the enclosing `for` or `while` loop which the keyword appears.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        while stam < 100\n\n            if stam = 50\n               say 'At 50!'\n               // Skip saying 'Not at 50'\n               continue\n            endif\n\n            say 'Not at 50'\n\n        endwhile\n        ```\n\n## in\n\nSyntax: `(word) in (variable string)`\n\nDescription: The `in` keyword works in conjunction with the `getlabel` command.\n\n!!! example\n\n    === \"General\"\n\n        ```razor hl_lines=\"4\"\n        \n        if findtype '217' as 'a_dog'\n            getlabel 'a_dog' 'dog_label'\n\n            if 'Fido' in 'dog_label'\n                overhead 'found mydog!' 5\n                overhead 'dog_label' 67\n            endif    \n        endif\n        ```\n\n\n## loop/replay\n\nSyntax: `loop` OR `replay`\n\nDescription: The `loop` or `replay` keyword will restart the currently run script back to the beginning indefinitely.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if mana = 100\n            say 'all done!'\n            stop\n        else\n            say 'still meditating'\n        endif\n\n        wait 1000\n\n        loop\n        ```\n\n## not\n\nSyntax: `not (statement)`\n\nDescription: They `not` keyword returns the opposite of the statement result.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if not 'dead'\n            say 'I live!'\n        endif\n\n        if 'dead'\n            say 'I died!'\n        endif\n        ```\n\n        ```razor\n        while not hp = 100\n            overhead 'My HP isnt full'\n        endwhile\n        ```\n\n## or\n\nSyntax: `(statement) or (statement)`\n\nDescription: The `or` keyword links statements together and if one statements is `true` the condition is met.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if insysmsg 'hello' or insysmsg 'bye'\n            say 'found'\n        endif\n        ```\n\n## stop\n\nSyntax: `stop`\n\nDescription: The `stop` keyword will stop the execution of the current script.\n\n!!! example\n\n    === \"General\"\n\n        ```razor\n        if stam = 100\n            say 'all done!'\n            stop\n        else\n            say 'still waiting'\n        endif\n\n        wait 1000\n\n        loop\n        ```\n"
  },
  {
    "path": "help/docs/guide/layers.md",
    "content": "---\ntitle: Script Layers\ndescription: A list of all script layers for Razor\n---\n\n# Layers Overview\n\nIf the command you're using requires a `layername` (such as `dropitem`) can use any of the following keywords (case insensitive):\n\n- `RightHand`\n- `LeftHand`\n- `Shoes`\n- `Pants`\n- `Shirt`\n- `Head`\n- `Gloves`\n- `Ring`\n- `Talisman`\n- `Neck`\n- `Hair`\n- `Waist`\n- `InnerTorso`\n- `Face`\n- `Bracelet`\n- `FacialHair`\n- `MiddleTorso`\n- `Earrings`\n- `Arms`\n- `Cloak`\n- `Backpack`\n- `OuterTorso`\n- `OuterLegs`\n- `InnerLegs`\n"
  },
  {
    "path": "help/docs/guide/variables.md",
    "content": "---\ntitle: Script Variables\ndescription: A list of all script variables for Razor with descriptions\n---\n\n# Variables Overview\n\nVariables (also referred to as aliases) are commonly used values designed to be referenced in any of your scripts.\n\nYou can either define your own variables or you can use this list of pre-defined variables.\n\n# Defining Variables\n\nYou can create custom variables that are available in your scripts.  This can be done one of two ways.  First, you can create custom variables in the Razor UI by going to the Options tab under the Scripts tab.\n\n![variables](../images/scripts-options.png)\n\nSimply click Add, give it a name and target the item or mobile and that variable is available in your scripts.  In the screenshot above, `regbag` is set to a bag.  To use this variable in a script, you simply reference it.\n\n* Open your reg bag\n\n```razor\ndclick 'regbag'\n```\n\nYou can also set variables in scripts by using the `setvar` command.  To update the `regbag` command, you might do something like this:\n\n* Get target cursor to select item or mobile\n\n```razor\nsetvar 'regbag'\n```\n\nThe script will pause until you select a target. After you select a target, it will update and move on to the next line in the script.\n\n# Pre-Defined Variables\n\nAlong with defining your own variables, you can use these pre-defined variables in your scripts.\n\n| Variable          | Description                                                |\n| ----------------- | ---------------------------------------------------------- |\n| `backpack`          | `Returns:` The serial of your own backpack                 |\n| `hands`             | `Returns:` The serial of the item in either hand           |\n| `index`             | `Returns:` The index of the current loop iteration           |\n| `lasttarget` / `last` | `Returns:` The serial of your current last target in Razor |\n| `lastobject`        | `Returns:` The serial of your last used object in Razor    |\n| `lefthand`          | `Returns:` The serial of the item in your left hand        |\n| `righthand`         | `Returns:` The serial of the item in your right hand       |\n| `self`              | `Returns:` The serial of your player                       |\n\n## Index Variable\n\nWhen using `for` or `while` you have access to the `index` variable. This can be used with `overhead` (for example) to indicate the current loop number.\n\nFor example, this script snippet will output the numbers 0-9 overhead every second.\n\n```razor\nfor 10\n    wait 1000\n    overhead 'index'\nendfor\n```\n\n```razor\nfor 10\n    if index == 7\n        overhead '7th loop'\n    endif\nendfor\n```\n"
  },
  {
    "path": "help/docs/help/advanced.md",
    "content": "# Advanced\n\n![advanced](../images/advanced.png)\n\nThis tab will show some data regarding Razor internals and give you access to some staff related functionality. The data on the left is purely for informational purposes only.\n\n## Options\n\n|Feature|Description|\n|-------|-----------|\n|Open Data Directory|Opens Windows Explorer to the folder containing your profiles and macros.|\n|Enable packet logging|This feature will save all packets flowing between the UO client and server. Useful for debugging purposes but when enabled can slow down Razor and eventually cause a large file to be created if not disabled.|\n|Negotiate features with server|This allows Razor to communicate with the server to enable/disable certain features in Razor. When this box is not checked, Razor will fail to respond to a negotiation packet and you will subsequently be disconnected from the server you are connected to.|\n|Enable UOA API|This opens up a limited API that can be used by 3rd party applications (such as various mapping tools) to get some data from Razor.|\n\n## Disable SmartCPU\n\nSmartCPU has been completely removed from this version, but the option to disable it remains in place in case it was enabled in an older version.\n\n## Backup\n\nTo create a backup, click the `Create Backup` button. This will copy all your profiles, macros and scripts to the `Backups` folder in the root of your Razor folder.\n\n# Decoration\n\nThis tab gives shard staff an easy way to add new items in-game. You can manage the item list by editing `items.xml` in the Razor root path.\n\n![advanced](../images/advanced-deco.png)\n\n# Doors\n\nThis tab gives shard staff an easy way to add new doors in-game. You can manage the item list by editing `doors.xml` in the Razor root path.\n\n![advanced](../images/advanced-doors.png)\n"
  },
  {
    "path": "help/docs/help/agents.md",
    "content": "# Agents\n\nThe Agents tab is for organizing, restocking and moving items.\n\n![agents](../images/agents.png)\n\n## Aliases\n\n!!! tip \"Aliases\"\n\n    You can right-click on an agent and assign it an aliases to help identify it easier.\n\n    ![agent-aliases](../images/agent-aliases.gif)\n\n## Use Once Agent\n\nThis agent lets you set item(s) in your backpack to be used via a hotkey.\n\nOnce the item is used, it is removed from the list. This is very useful for for trapped pouches. Add all your trapped pouches to the list and use them on the run. The list will remove each one as it's popped, and warn you when your list is empty.\n\n* **Add (Target)**\n    - Use this option to add items, one at a time.\n* **Add Container (Target)**\n    - Use this option to add the contents of an entire bag. Open the bag before targeting so Razor can 'see' the contents. This is the best option for adding multiple trapped pouches with the **Use Once Agent**. Keep them inside another bag and add the bag.\n* **Remove (Target)**\n    - Remove items from the list. This option gives a cursor target. Target the item to be removed.\n* **Clear List**\n    - Clears all items from the list.\n\n## Sell Agent\n\nItems on this list sell automatically to vendors when you begin a sale transaction (you must still be at the appropiate vendor). Choose how many to sell each time; a great tool for BOD collection.\n\nThe listing is done by item type, not item ID. If you have a magic longsword and a player-made longsword in your pack, adding longsword would result in both being sold. If you add plate armor to the list, the agent will attempt to sell all plate armor, colored or not, magic or not. The list can be disable without being cleared.\n\n* **Add (Target)**\n    - Click for a targeting cursor, target the item to add.\n* **Remove**\n    - Highlight an item in the list and click remove to delete it.\n* **Set Hot Bag**\n    - Razor will attempt to sell all items in a specified bag.\n* **Clear**\n    - Clear the list\n* **Max Sell**\n    - Select how many of each item to sell. Each item must be sold to the appropriate vendor. The vendor must have sufficient gold to buy the item. When you are selling you may note a discrepancy between the razor messages, gold received and the vendor replies. Razor will try to sell all items that can be sold to the vendor you are at, and the total it gives is for all those items combined. If the vendor cannot purchase all the items, the amount actually received will be less the the total stated by Razor. This does not mean you have been ripped off, only that the vendor couldn't buy everything. Continue on to the next vendor of the same type to continue selling.\n* **(Push to Disable/Enable)**\n    - Turn the sell agent on or off.\n\n## Organizer Agent\n\nThis agent is used to move items from one container to another.\n\nFor example, if I purchase 20 mortar and pestle for my alchemist, I can easily bag them all without having to click and drag each one individually. If I click 20 potions from kegs and want them in my pvp supply bag, it can be done quickly without accidentally using one, without all the click and drag. There are 10 different organizers so there is room to set and keep frequently used lists. Hot keys will allow you to use the organizer and reset the target bag organized to.\n\n* **Add (Target)**\n    - Use this option to add items.\n* **Set Hot Bag**\n    - Set the hot bag to organize the items to. When it is already set, the tab changes to say 'Clear Hot Bag'. Both give a targeting cursor.\n* **Organize Now**\n    - Once everything is set, click this tab to activate the organizer.\n* **Remove**\n    - Highlight an item and click this tab to remove the item from the list.\n* **Clear**\n    - Clear the organizer; it can now be reset.\n* **Stop Now**\n    - Stops the organizer mid-process.\n\n## Scavenger Agent\n\nThis agent is for automatically picking up items off the ground that are in range. Very useful, for example, during an IDOC.\n\n* **Add (Target)**\n    - Click for a targeting cursor, target the item to add.\n* **Remove**\n    - Highlight an item in the list and click remove to delete it.\n* **Set Hot Bag**\n    - Razor will put all items scavenged into this bag. If not bag is set, it will go into your main backpack.\n* **Clear**\n    - Clear the list.\n* **Clear Scavenger Cache**\n    - Razor will only try to pick up an item once, and move on. If Razor missed some items on the ground, click this button so it will try again.\n* **(Push to Disable/Enable)**\n    - Turn the scavenger agent on or off.\n\n## Buy Agent\n\nThe buy agent is for setting lists of items to buy at vendors.\n\nUsed for purchasing large quantities or multiple items. Remember to check vendor prices each time Before enabling and using this agent. Use with caution, it is possible for the vendors to have items listed incorrectly. This will cause an erroneous purchase for you.\n\n* **Add (Target)**\n    - Target the item to be added to the list. A second gump (see below) prompts you to enter the amount to be purchased.\n* **Edit**\n    - Highlight any item in the list and click Edit to change the amount to purchase. A gump prompts you to enter the amount.\n* **Remove**\n    - Highlight any item and click Remove to delete it from the list.\n* **Clear List**\n    - Clear the entire list.\n* **(Push to Disable/Enable)**\n    - Use this tab to turn the agent off and on. Each buy agent can be set separately.\n\n## Restock Agent\n\nThe Restock agent is used to drag items from a container to be placed inside your backpack.\n\nSetting this up will enable you to restock your character at the click of a key. The restock agent will only stock up to the amount you indicate, not simply add the amounts to what you already have. For example, my restock agent is set to include 33 black pearl.\n\nWhen I use the restock agent, it will top my black pearl up to 33; it won't add 33 more.\n\n* **Add (Target)**\n    - Target the item to be added to the list. A second gump (see below) prompts you to enter the amount to be purchased.\n* **Remove**\n    - Highlight any item and click Remove to delete it from the list.\n* **Set Amount**\n    - Highlight any item in the list and click Set Amount to change the restock amount. A gump prompts you to enter the amount:\n* **Clear List**\n    - Clear the entire list.\n* **Clear Hot Bag**\n    - Use this tab to set the hotbag to restock too. If no bag is indicated, Razor restocks to your main backpack.\n* **Restock Now**\n    - Activate the agent. You will receive a targeting cursor. Target the container to restock from. If you are at the bank, with your bank open, you can target your character to refill from the bank. This may also be set as a hotkey.\n\n## IgnoreList Agent\n\nPlayers added to this list will have all the say, yell, emote, etc blocked. Spell power words will still be seen.\n\n* **Add (Target)**\n    - Target the character to be added to the list.\n* **Remove**\n    - Highlight any name and click Remove to delete it from the list.\n* **Remove (Target)**\n    - Gives a targeting cursor. Target the player to remove from the list.\n* **Clear List**\n    - Clear the entire list.\n* **(Push to Disable/Enable)**\n    - Turn the Ignore list off and on."
  },
  {
    "path": "help/docs/help/armdress.md",
    "content": "# Arm / Dress\n\nThe Arm/Dress tab is for setting clothes, armor and weapons for use. These settings are used with hotkeys.\n\n![armdress](../images/armdress.png)\n\n## Arm/Dress Selection\n\n![armdresssel](../images/armdress-selection.png)\n\nThis is the list of arm/dresses can consist of a complete outfit or just one item. Hotkeys can be assigned to each. Use the **Add** and **Remove** buttons to manage.\n\n* **Automatically move conflicting items**\n    - Check this box so Razor can dress you properly. This allows items to be removed when neccesary. For example, you are equiped with a halberd and hit your hotkey to equip a war axe. With this box checked, Razor can un-equip the halberd to equip the war axe. This will apply to all lists and hotkeys.\n\n## Arm/Dress Items\n\n![armdress-item](../images/armdress-items.png)\n\nThis is where you define the items for each list created above. Highlight a list from the left and use the following tabs to set it up. Any entries can be right-clicked for conversion to 'Dress by Type'.\n\n>> ***Note:** 'Dress by type' will tell Razor to look for any item of that type to use, not only the specific item used to set the list. This is most useful for weapons.*\n\n* **Dress**\n    - Highlight a list from the left and click this tab to dress in the items from that list.\n* **Undress**\n    - Highlight a list from the left and click this tab to undress the items from that list.\n* **Add (Target)**\n    - Click this tab to add items to a list. You will get a targeting cursor to target the item to be added.\n* **Add Current**\n    - Adds everything currently being worn to the highlighted list.\n* **Remove**\n    - Highlight an item and click 'Remove' to delete an item from the list.\n* **Clear List**\n    - Clear the current list.\n* **Change Undress Bag**\n    - Gives a targeting cursor. Target the bag you want to undress to."
  },
  {
    "path": "help/docs/help/displaycounters.md",
    "content": "# Display/Counters\n\n![displayscounters](../images/displayscounters.png)\n\n## Display\n\n### Title Bar Display\n\n!!! note\n    If you are using ClassicUO, images will not display in the title bar. It's recommended to use the built-in counter bar.\n\n![titlebar](../images/titlebar.png)\n\nThis feature will display the values of your counters and other information in the title bar of the Ultima Online client. Along with the **Format** of the counter wrapped in `{}`, Razor has the following values built in. Check **Show in UO title bar** to enable.\n\n- `{ar}` - Total Armor Rating\n- `{char}` - This will display your character's name\n- `{crimtime}` - When you become a criminal, this timer will count up until you are not longer one\n- `{buffsdebuffs}` - The buffs/debuffs currently applied to your character\n- `{damage}` - Display your min and max damage\n- `{dex}` - Your current dex\n- `{followersmax}` - The max number of followers allowed by your character\n- `{followers}` - The current number of followers assigned to your character\n- `{gold}` - Total amount of gold in your backpack\n- `{gate}` - When you cast Gate, a timer will display for the 30 seconds the gate is up\n- `{hpmax}` - Your max hit points\n- `{hp}` - Your current hit points\n- `{int}` - Your current intelligence level\n- `{largestatbar}` - Display a large status bar\n- `{manamax}` - Your max mana points\n- `{mana}` - Your current mana level\n- `{maxweight}` - The max number of stones you can carry\n- `{mediumstatbar}` - Display a medium status bar\n- `{shard}` - The name of the Shard you're playing on\n- `{skill}` - When you use a skill from an assigned Razor hotkey, it will start a counter\n- `{stammax}` - Your max stamina\n- `{stam}` - Your current stamina\n- `{statbar}` - Display a small status bar\n- `{stealthsteps}` - The current number of steps taken since you stealthed\n- `{str}` - Your current strength\n- `{uptime}` - The length of time you've been connected\n- `{weight}` - Your current weight in stones\n\nValues that work on AOS+ servers.\n\n- `{coldresist}`\n- `{energyresist}`\n- `{fireresist}`\n- `{luck}`\n- `{physresist}`\n- `{poisonresist}`\n- `{tithe}`\n\nHere is a default title bar to built yours off of:\n\n`{char} - {crimtime} {weight}/{maxweight} - ~#FF0000 {hp}/{hpmax} ~#~ - ~#FE2EF7 {stam}/{stammax}~#~ - ~#0080FF {mana}/{manamax} ~#~ {bp} {bm} {gl} {gs} {mr} {ns} {ss} {sa} Gold: {gold}`\n\n#### Color\n\nYou can color the title bar text using any HTML style 6 digit hex number.  Use the code in the following manner:\n\nHTML hex color code: `~#rrggbb` ('`~#~`' to terminate)\n\nFor the purpose of example, I want to change the color of my hp display to orange. I would use the following code to do so: `~#FF6600 {hp}/{hpmax} ~#~`. The '`~#FF6600`' tells Razor to color everything between it and the '`~#~`' to an orange color, the color orange selected by the six digits, FF6600. The '`~#~`' tells Razor to stop coloring. If you need to know the color codes for this function, try this page.\n\n### Track gold per sec/min/hour\n\nWhen using **Track Gold Per sec/min/hour** these values will work:\n\n- `{goldtotal}` - The amount of gold collected since you checked the **Track gold per sec/min/hour** box\n- `{goldtotalmin}` - The amount of time that has gone by since you started tracking your gold intake\n- `{gpm}` - Display your gold per minute\n- `{gps}` - Display your gold per second\n- `{gph}` - Display your gold per hour\n\n### Other\n\n* **Highlight Spell Reagents on Cast**\n    - Whenever you cast a spell, a red background will highlight the reagents used to cast the spell.\n* **Show noto hue on {char} in TitleBar**\n    - When enabled, the name of your character on the Title bar will show in the same color as it will when you are clicked in the game.\n* **Enable gold per sec/min/hour trackers**\n    - When checked, the counter will start monitoring your gold intake using the values above.\n\n## Counters\n\n![counters](../images/counters.png)\n\nCounters are used to track the number of items you currently have in your backpack. The most commonly used counter is for reagents but this feature can be used on any item. Razor will come with some common counters available to you by default.\n\n#### Adding a counter\n\n  - Click **Add...** under the list of counters.\n  - Click **Target** and target the item to add. The Item ID and color fields should auto-populate for you.\n  - The **Name** (of the item) is the name as you see it when you click the item.\n  - The **Format** is the letter code you want to use. For example, the default for black pearl is `bp`.\n  - Click **OK** once all fields are entered.\n  - If you want this counter to display in the titlebar, check **Display image in title bar**. For example when used with black pearl, the title bar displays a small black pearl beside the count rather than the abbrev `bp`.\n\nTo **Edit or Remove** a counter, select it and click **Del/Edit**.\n\nClick **Recount** to force Razor to check all the containers on your character and get the correct acounts.\n\n### Others\n* **Show Images with Counters**\n    - Check this to show counter images instead of abbreviations. Each counter can be modified individually from the counter table with the edit tab to disable this.\n* **Warn when a counter is below X**\n    - When your counter for any specific item drops below **X**, Razor will provide a warning in red.\n\n## Bandage Timer\n\n![bandagetimer](../images/bandagetimer.png)\n\n* **Show bandage timer**\n    - When you have this enabled, when you use a bandage a timer will display.\n\n## Overhead Messages\n\n![overhead](../images/overhead.png)\n\nCheck `Enabled` to turn on the overhead messages feature.\n\nThis option will display messages above your head that are triggered based on system messages in the lower-left that come in from the server. For example, when the message `You begin applying bandages.` comes through, you can have the message `[Applying bandages]` appear above your head.\n\n!!! tip \"Expand Overhead Messages\"\n    You can extract specific words from the system message to display in the overhead messages (`{1}` for the first word, `{2}` for the second word, etc).\n    If the system message is `You must wait 80 seconds!`, you can set the overhead message to `Wait {4}s` and it would display `Wait 80s` overhead.\n\n| Option | Description |\n| ------ | ----------- |\n| Format | Set the format of the overhead message. It must contain `{msg}` for your custom message to appear. Default is `[{msg}]`.|\n| Message Style | Set the message style to appear overhead depending on your preference. Default is `Unicode`. |\n\n### Create Overhead Message\n\n* Enter part of the message or the whole message into the `Search Text` field.\n* (Optional) If you need help finding the message, click `Search` and select the message you want to capture.\n\n!!! tip\n    If your message is custom to your shard and not on the search list, simply click `Add` to capture it. It doesn't need to be a static message in the client files.\n\n* Click `Add` and enter the message you want to appear overhead and click `OK`.\n* Your overhead message capture will appear at the bottom of the list.\n\n### Demo\n\n![overheaddemo](../images/overheaddemo.gif)\n\n## Waypoints\n\n![waypoints](../images/waypoints.png)\n\nThis feature lets you set waypoints, that will display within the client.\n\n* **Show waypoint messages overhead**\n    - Direct waypoint messages from system message to overhead.\n* **Show tile distance every X**\n    - If checked, it will show the current distance every X seconds.\n* **Hide waypoint within**\n    - When you're within X tiles, hide/clear the waypoint.\n* **Create waypoint on death**\n    - Upon death, create a waypoint.\n\n### Create Waypoint\n\n* Enter the name for the waypoint in the `Name` field.\n* Either manually enter the X and Y coordinates or click `Use Current Position` to auto-fill.\n* Click `Add Waypoint`\n\n!!! tip\n    Double-click a waypoint in the UI to activate it in game. You can also assign hotkeys to cycle between waypoints."
  },
  {
    "path": "help/docs/help/filters.md",
    "content": "# Filters\n\n## General\n\n![filters](../images/filters.png)\n\nFilters will change the way the client will display visuals or play audio.\n\n* **Sound Filters**\n    * Allow you to block the client from playing certain sounds.\n* **Light Filter**\n    * Force the client to always display 100% light levels\n* **Death Filter**\n    * Prevent the \"You are dead\" animation from playing\n* **Filter dragons**\n    * Override the dragon graphic and replace it with something else.\n* **Filter drakes**\n    * Override the drake graphic and replace it with something else.\n* **Filter daemons**\n    * Override the daemon graphic and replace it with something else.\n\n## Text & Messages\n\n* **Text Filter**\n\nEnable the text filter to block all text from any mobile.\n\n* **Filter Messages**\n\nInstead of spamming your screen system or overhead messages, if checked it will keep filtering messages as long as you have the filter delay. When those seconds pass, it will show you the message.\n\n* Filter snooping messages\n* Filter repeating system messages\n* Filter repeating Razor messages\n* Filter repeating overhead messages\n* Filter Delay\n\n## Target Filter\n\n![targetfilters](../images/targetfilters.png)\n\nMobiles on this list will be ignored completely by Razor.\n\n!!! tip\n    This feature is intended to be used to add NPCs that might be picked up during events that take place in towns or where NPCs are.\n\n## Sound & Music\n\n![sound](../images/soundmusic.png)\n\n* Enable Sound Filter\n    - When checked, sounds that are checked will be blocked from playing in the client.\n* Play Selected Sound\n    - Listen to the selected sound. If you check `Play in client` the sound will play in the client if logged in.\n* Show filtered sound info\n    - If a sound is blocked, show the name in system messages.\n* Show non-filtered sound info\n    - If a sound plays, show the name in system messages.\n* Play Music In Client\n    - Plays the specific song in the client if logged in."
  },
  {
    "path": "help/docs/help/friends.md",
    "content": "# Friends\n\n![friends](../images/friends.png)\n\n## Friend Groups & Lists\n\nRazor allows you to manage groups of friends to prevent you from targeting those on the list.\n\n|Feature|Description|\n|-------|-----------|\n|Treat part members as 'Friends'|If enabled, anyone in your party is considered a friend regardless if they are in a friends group.|\n|Show [Party-Friend] overhead|Shows a message overhead on party members who are friends.|\n|Next/Prev Target ignores 'Friends'|Ignore friends when using Next/Prev targeting unless you specifically use the `Next/Prev Friend` hotkey.|\n|Auto-accept party invites from friends|If a friend sends you a party invite, it will auto accept it.|\n|Next/Prev highlights 'Friends'|Your friends will be highlighted when using Next/Prev|\n"
  },
  {
    "path": "help/docs/help/general.md",
    "content": "# General Settings\n\nThe General tab has setting largely related to the client itself and Razor in general.\n\n![general](../images/general.png)\n\n## General\n\n### Profiles\n\nEach character has a profile that contains your settings, such as the options in Razor and your hotkeys.\n\n!!! tip \"Profile Location\"\n        Profiles are stored in the same location as `Razor.exe` under `.\\Profiles\\`. You can create a new profile, which will be based on the *default profile settings* (`default.xml`)\n\n!!! tip \"Multiple Profiles\"\n    It's **highly recommend** that have you have 1 profile per character. If you use the same profile among multiple characters while logged in, you could potentially lose changes to your profile. It's doable, but requires an extra bit a caution to ensure you keep all your profiles synced up.\n\n|Feature|Description|\n|----|----|\n|New|Create a new profile based off of the default Razor profile.|\n|Save|Save all the current Razor settings without having to log out.|\n|Clone|Clone the existing selected profile and create a new one.|\n|Delete|Delete the selected profile.|\n\n#### Creating a new profile\n\nClicking **New** will generate a new profile based on the default profile that comes with Razor. If you rather create a new profile using an existing profile, select that profile first and click the **Clone** button.\n\n#### Saving your profiles\n\nRazor will save your profile two ways.\n\n* When you open your paperdoll in UO, click **Logout** and click **OK**.\n    * This triggers the client to tell Razor that you logged off, which performs the profile save.\n* Click the **Save** button manually to ensure your changes are saved.\n\n### Maps / Boat\n\n#### UOPS\n\n![uops](../images/map-uops.png)\n\nRazor's Ultima Online Position System (UOPS) gives you a basic map.\n\n#### Boat Control\n\n![boat](../images/map-boat.png)\n\n**Boat Control** was inspired by UO Rudder and designed to make navigating the seas of Britannia much easier. This tool is built into Razor.\n\n!!! tip\n    Right-clicking on 1 of the 4 directions will set relative location.\n\n### Other\n\n|Feature|Description|\n|-|-|\n|Show Welcome Screen (Global Setting)|When checked, opening Razor will give you the **Welcome Screen**. This is where you can enter new servers, change your client location, etc.|\n|Use Smart Always on Top|Razor will stay on top of the UO window when it becomes active and hide when it becomes inactive.|\n|Show in Taskbar or System Tray|You can have Razor in the Taskbar or the System Tray. It's all up to you.|\n|Default Client Priority| This changes the priority given to the process. Honestly, leave it at **Normal**. This feature should be removed. It's old.|\n|Opacity|Adjust the transparency of Razor. Useful on a single monitor.|\n|Language|The `.\\Language\\` folder contains all the translations. Some are missing, feel free to translate based on the `.enu` file located in the package.|\n"
  },
  {
    "path": "help/docs/help/hotkeys.md",
    "content": "# Hot Keys\n\n![displayscounters](../images/hotkeys.png)\n\nHot keys tie your keyboard and mouse to specific actions within Ultima Online, or to specific functions within Razor.\n\n## Filter Box\n\nAs you type in this box, the list will be narrowed down helping you find a specific hotkey.\n\n## Hot Key Setup\n\n- **Ctrl - Alt - Shift - Key**\n    - Located on the right, these are used to select the key. Once you have highlighted the hotkey to be set from the left index, click in the key field and type the key to be used for that setting. If you want to use a key with control, shift or alt keys, check them as well.\n- **Unset/Set**\n    - Once you select the key, click Set. If this key combination has already been used by another setting in Razor, a warning is given. If the set is successful, the hotkey will appear beside the entry in the index. Click Unset to remove the key combination.\n- **Command**\n    - You can define a custom command (accessed via `>command`) here that will execute this hotkey wouldn't hitting the key combination.\n- **Pass to UO**\n    - When you set a hotkey, it becomes a key combination for Razor. Check this box to have hotkeys continue on to the client. If you do not check this box, Razor will read the command and it will go no further.\n- **Execute Selected**\n    - Useful for using commands from the hotkey list without setting a key. For rarely used actions or testing.\n\n## Hot Key Categories\n\nHot keys are broken up into several categories.\n\n- **Agents**\n    - Hot keys related to using your agents\n- **Dress**\n    - Hot keys related to arming/disarming yourself and executing one of the **Arm/Dress** selections.\n- **Friends**\n    - Hot keys related to adding friends, enabling and disabling friend groups.\n- **Items**\n    - Hot keys related to using bandages, potions and items in your hand.\n- **Macros**\n    - Hot keys that will run **Macros** you've created.\n- **Misc**\n    - Hot keys that don't fall under any specific category. Notable section is **Special Moves** for Stun or Disarm.\n- **Scripts**\n    - Hot keys related to running scripts.\n- **Skills**\n    - Hot keys related to executing your skills.\n- **Spells**\n    - Hot keys related to casting your spells.\n- **Targets**\n    - Hot keys related to selecting targets.\n\n## Notoriety & Target Definitions\n\n| Type       | Notoriety Color         |\n| ---------- | ----------------------- |\n| Innocent   | Blue                    |\n| Guild/Ally | Green                   |\n| Attackable | Gray (but not criminal) |\n| Criminal   | Gray                    |\n| Enemy      | Orange                  |\n| Murderer   | Red                     |\n\n| Target       | Type                                  |\n| ------------ | ------------------------------------- |\n| Non-Friendly | Attackable, Criminal, Enemy, Murderer |\n| Friendly     | Innocent, Guild/Ally                  |\n| Enemy        | Enemy                                 |\n| Red          | Murderer                              |\n| Grey         | Attackable, Criminal                  |\n| Criminal     | Criminal                              |\n| Innocent     | Innocent                              |\n"
  },
  {
    "path": "help/docs/help/index.md",
    "content": "---\ndescription: A comprehensive guide to all the features found in Razor\n---\n\n# Help with Razor\n\nThis guide is broken down based on the different tabs found in Razor.\n\n* [General](general.md)\n* [Options](options.md)\n* [Display/Counters](displaycounters.md)\n* [Arm/Dress](armdress.md)\n* [Skills](skills.md)\n* [Agents](agents.md)\n* [Filters](filters.md)\n* [Hot Keys](hotkeys.md)\n* [Macros](macros.md)\n* [Scripts](scripts.md)\n* [Friends](friends.md)\n* [Screen Shots](screenshots.md)\n* [Advanced](advanced.md)\n\nIf you're unable to find a solution using the information here or you'd like to submit a feature request or bug report, use the following resources.\n\n* Submit a bug/issue on the [official Razor GitHub Repo](https://github.com/markdwags/Razor/issues).\n* Join us in **#razor** on Discord\n\n[![Chat on Discord status](https://img.shields.io/discord/458277173208547350.svg?logo=discord)](https://discord.gg/VdyCpjQ)\n\nFor more information about the Razor Scripting Engine, go [here](https://www.razorce.com/guide/).\n"
  },
  {
    "path": "help/docs/help/macros.md",
    "content": "# Macros\n\nMacros allow you to run a set of recorded actions. Macros can be used to macro skills or perform other actions even while AFK or while playing another character. Macros can be used for gathering resources and crafting.\n\nMacros are divided into two sections. The column on the left is the macro index of all macros you make. On the right is the action area, used to set and edit the macros you create. Macros are saved to a folder, 'Macros', in your Razor folder. These can be edited in text format.\n\n![macros](../images/macros.png)\n\n## Macros\n\n### Categories\n\nCategories can be created to organize your macros into groups. While, unlike the rest of the profile, macros are shared across all characters. Each character can have their own hot key settings depending on how frequent that character would use the macro (if at all).\n\n**Right click the left column for the following options:**\n\n* **Add Category**\n    - Add a category to place macros in. A gump will prompt you to enter a name.\n* **Delete Category**\n    - Highlight a category and click delete to remove it. Macros inside the category will need to be removed first.\n* **Move to Category**\n    - Move macros to the category you choose.\n* **Refresh Macro List**\n    - Update changes made to the list.\n\n## Creating a macro\n\nTo Create a Macro, begin by clicking the 'New' tab at the bottom of the gump. A second gump prompts you to enter the name of the macro; click 'OK'.\n\nThe macro will now appear in the left index. Highlight the macro name with a left click. A list of functions to set the macro will now show beside the right action window. Right click the macro name to move it into a category if you choose.\n\n### Set/Recording a macro\n\nTo Set/Record a Macro, highlight the macro in the left index. Click the 'Record' tab on the right and go through the actions in-game that you want in the macro. When you have finished, click the 'Stop' tab. Once the macro is created, the 'Stop' tab will change to a 'Play' tab when the macro is not running. To clear the macro entirely for re-recording, click the Record tab again. A prompt warns your original macro will be cleared.\n\nYou now have the basis of a macro. From here, you can fine tune it with a list of options found with a right-click.\n\n* **Reload**\n    * Update Razor folder changes without closing Razor. This option will applies to the entire Razor folder, not specific macros. If you have edited a macro in text format, or added a a pre-made macro to the folder that isn't showing up, use this option.\n* **Save**\n    * Saves changes made to Razor in the text file without closing the program.\n* **Move Up/Down**\n    * Highlight a line and move it up or down with these two commands. Useful for changing text placement, misplaced commands, and more. **Tip:** If you hold down `CTRL-ALT` and use the `UP` and `DOWN` keys.\n* **Remove Action**\n    * Highlight a line and click this option to delete the action from the macro. This cannot be recovered except by re-recording the action.\n* **Begin Recording Here**\n    * Use this option to add actions you have missed. Razor will begin recording in the current macro. The action(s) will appear after the line highlighted.\n* **Play from Here**\n    * Play the macro from the line indicated. Useful for checking macros as you set them.\n* **Special Constructs**    \n    * **Pause/Wait**\n        * This option gives a second gump of choices. A pause can be entered based on a specific amount of time. Waits can be added for gumps, targets, and old-style menus. Waits can also be added based on hitpoints, mana, or dexterity reaching a specified amount.\n        For example: Wait for Mana <= 90\n    * **Set Last Target**\n        * Gives a cursor to set a new last target.\n    * **Comment**\n        * Does not actually appear in the macro. This is for user notes and comments.\n    * **\"If\" Conditional**\n        * Set a command depending on circumstances - If mana is <= ; If black pearl =>\n    * **\"Else\"**\n        * You can continue the \"if\" conditional by adding 'else'. For example: \n        * If black pearl is <= 32\n        * Use restock agent 5\n        * Else If black pearl is => 33\n        * Use organizer agent 5\n        * End if\n        * This would tell razor to restock with restock agent 5 if black pearl if it is equal to or less than 32, use organizer agent 5 if black pearl is equal to or greater than 33.\n    * **\"End If\"**\n        * Use this line to end your 'if' commands. This tells Razor this part of the macro is complete.\n    * **\"For Loop\"**\n        * A command to loop (repeat) all actions following. A gump appears with this option, enter the number of times to repeat.\n    * **\"End For\"**\n        * Use this when actions to be looped have ended. This line tells razor the \"for Loop\" part of the macro has ended.\n\n## Options\n\nThis version of Razor has an expanded section with additional macro options\n\n![macros-advanced](../images/macros-options.png)\n\n#### Absolute Target Variables\n\nThe concept with **Absolute Target Variables** is to remove duplicate macros for the same thing. For example, you have a Recall macro that casts recall, waits for target, and clicks a rune or runebook. If you have 5 characters doing the same thing, you need 5 macros because the unique ID of the rune or runebook is different.\n\nWith **Absolute Target Variables** in that same scenario, you can have one macro cover all 5 characters. Your macro and absolute target variable might look like this:\n\n\n![macros-advanced1](../images/macros-advanced-at1.png) ![macros-advanced](../images/macros-advanced-at.png)\n\nAs long as you have setup a `$rune` variable on your profile, that macro will work across all profiles.\n\n* **Add**\n    * This will give you a target in game to select the item to create a variable based on\n* **Insert**\n    * This will insert the currently selected variable into the selected macro.\n* **Retarget**\n    * If you need to update the variable to a new item, use this.\n* **Remove**\n    * Remove the selected variable from the list.\n\n### Options\n\n* **Force different 'TargetByType'**\n    * Prevents a macro from selecting the same item over and over (for example, the item is out of range)\n* **Range check on 'TargetByType'**\n    * Macros will only target items by type that are in range of your character. This is to prevent a macro from trying to target an item out of range.\n* **Range check on 'DoubleClickType'**\n    * Same idea here. Macros will only double-click items in range of your character.\n* **Step Through Macro**\n    * If checked, each step in the macro will require you to click `Next`. Useful for debugging your macros.\n\n* **Default macro action delay (50ms)**\n    - The OSI client required a 50ms delay, which isn't required by ClassicUO. Some macros were designed with ths 50ms delay in mind. Checking this and restarting Razor will restore it. \n* **Disable Playing/Finished Message**\n    - Hide the message that shows when you run a macro.\n"
  },
  {
    "path": "help/docs/help/options.md",
    "content": "# Options\n\n## Speech & Messages\n\n![options](../images/options.png)\n\n* **Search Exemption Hue**\n    - Used in conjunction with the **AutoSearchExemption** feature on the agents tab. Containers and/or container types added to this agent will appear the *Search Exemption Hue* while in your backpack. Click the set tab to the right to change the color.\n\n!!! note\n    The color of the item does not actually change. When removed from your backpack it will return to the original color.\n\n* **Razor Message Hue**\n    - Razor messages sent to your client will be this color. Click the set tab to change the color.\n* **Warning Message Hue**\n    - Razor messages sent to your client specifically to warn you of something, like low reagents, will be this color. Click the set tab to change the color.\n* **Override Speech Hue**\n    - Check this box to force all speech on your screen to be one color. Click the set tab to select the color.\n* **Last Target Highlight**\n    - When checked, the last target will highlight the selected color. Click the set tab to select the highlight hue.\n* **Override Spell Hues**\n    - Like speech, checking this box allows you to select the color for spell text, both words of power or spell names. Colors may be selected for beneficial, harmful, and neutral spells.\n* **Override Spell Format**\n    - If checked, Razor will transform spell power words into the actual spell name.\n* **Spell Format**\n    - This field determines how you view spells being cast.\n        - `{power}` will show words of power on your screen. These are the actual spell words.\n        - `{name}` or `{spell}` will show the spell name.\n        - `{circle}` will show the circle of the spell.\n* **Show buff/debuff overhead**\n    - Check this option if you want to see when a buff/debuff has been added/removed from your character (ie: `[+Magic Reflection]` or `[+Reactive Armor]`).\n    - **Default Buff/Debuff Format** `[{action}{name}]`\n        - `{action}` will be a `+` or `-` symbol indicating if it was added or removed.\n        - `{name}` will be the official name of the buff/debuff.\n* **Filter Snooping Messages**\n    - Filters out the messages when someone nearby is snooping that can be seen as spam.\n* **Show Incoming People/Creatures**\n    - This will show the names of players and creatures as they enter your screen.\n    \n!!! note\n    This option exist within the UO client itself. It's recommend to disable the one in the UO Client or in Razor or it will produce duplicated names when new players or creatures enter the screen.*\n\n* **Show New/Incoming Corpses**\n    - As above, but with corpses.\n\n* **Show container labels**\n    - This option will allow you to tag containers and give them a label. This should allow for easier pixel sorting.\n    - **Default Format** `[{label}] ({name})`\n* **Show health above people/creatures**\n    - Check this option to show changes in player's health with a text percentage over their heads. The numbers will show in blue - green at 100%, to yellow at 50%, to purple - red at 0%.\n    - **Default Health Format** - `[{0%}]` or `[NN%]`\n* **Show mana/stam above party members**\n    - As above, but mana and stamina.\n* **Show damage dealt**\n    - Display the damage you've dealt in the lower-left or overhead.\n* **Show damage taken**\n    - Display the damage you're taking in the lower-left or overhead.\n\n## Targeting & Queues\n\n![options-targets](../images/options-targetqueues.png)\n\n* **Queue LastTarget and TargetSelf**\n    - This is used with **Last Target** and/or **Target Self** hotkeys. When this option is selected, `Last Target` and `Target Self` commands will be placed in queue until they can be executed. For example, you cast a spell and hit the `Last Target Hotkey` too soon. The moment the target is up, the last target function will be executed. A hotkey can be set to clear the queue when needed.\n* **Show Action-Queue status messages**\n    - A toggle to turn off/on messages about actions being queued. Unchecking this option will still allow some important messages to come through.\n* **Auto-Queue Object Delay actions**\n    - When checked, Razor will automatically queue up your double-clicks. It will prevents the message \"You must wait to perform another action\". This is an important setting for a well-run macro. The object delay field below should reflect your specific connection. Set the object delay at your average ping to the server + 500 (approx)\n* **Object Delay**\n    - Sets the number of milliseconds between actions. Unchecking the box will set it to 0.\n* **Show Target Self/Last/Clear Overhead**\n    - When checked, the messages for `[Target Self]`, `[Last Target]` and `[Clear Target Queue]` will display overhead instead of in the lower-left corner.\n* **Range check Last Target: *X* tiles**\n    - This option will have Razor check that last target is within range. If it's not, Razor sends a warning message and your target is not cancelled out. Last Target can be selected to try again without having to bring the cursor up a second time.  Select the number of tiles, within game allowances.\n* **Show target flag on single click**\n    - Select to display a text flag over last targets; to be used with Smart Target option. Flags show as `[Current Target]`, `[Beneficial Target]`, or `[Harmful Target]`.\n\n!!! tip\n    To edit this format, go into your profile and search for `PartyStatFmt`. `[{0}% / {1}%]` is the standard format.*\n\n* **Attack/target name overhead**\n    - When you attack a target, or aquire a new target using a hotkey, it will display the name of your target above your head.\n* **Show text target indicator**\n    - When checked, a simple text indicator above the target's head will appear\n\n### Smart Targeting\n\nSmart Targeting enables Razor to use beneficial or harmful spells according to your previous actions.\n\nFor example, in battle if you cast Energy Bolt (a harmful spell) at an enemy and Greater Heal (a beneficial spell) at a friend, Razor will remember the last targets for each spell type. The next time you cast a harmful spell with `Last Target`, Razor will target the enemy even if you just casted Greater Heal on your friend with last target without requiring you to set a new target.\n\n!!! tip \"Smart Targeting Hot Keys\"\n    You can set your `Harmful` and `Beneficial` target manually by using `Set Last Target (Beneficial)` or `Set Last Target (Harmful)`.\n \n* **Use smart last target**\n    - Enables smart targeting\n* **'Next/Prev Friend' sets beneficial only**\n    - Using Next/Prev Friend will only set the beneficial target (this option works in conjunction with the [Friends tab](friends.md))\n* **'Next/Prev Friendly' sets beneficial only**\n    - Using Next/Prev Friendly will only set the beneficial target.\n* **'Next/Prev Non-Friendly' harmful only**\n    - Using Next/Prev Friendly will only set the harmful target.\n\n## Additional Options\n\n![options-additional](../images/options-additional.png)\n\n* **Use Pre-AOS status window**\n    - The default status window is from the AOS expansion. If you check this box, it will look like the Pre-AOS window.\n    \n!!! tip\n    You will need to close, then re-open your status bar in-game for the change to take effect.*\n\n* **Auto-Stack Ore/Fish/Logs at Feet**\n    - When checked, when these items are placed into your bag, they will stack at your feet instead. Useful for gathering resources.\n* **Open new corpses within *X* tiles**\n    - This option automatically opens new corpses within the selected number of tiles.\n\n!!! tip\n    Use with caution, this function does not differentiate between a blue, grey, or red corpse.\n\n* **Block opening corpses twice**\n    - Used with the above option, if checked a corpse that was auto-opened will not auto-open again. Manually opening a corpse does not prevent it from auto-opening.\n* **Block Dismount in War Mode**\n    - Double-clicking yourself will dismount from any ride you may be on. This selection will cause Razor to block dismount while you are in war mode, preventing accidental dismount.\n* **Block trade requests**\n    - When checked, any trade request initiated by another person will be auto-blocked.\n* **Block party invites**\n    - When checked, this will block all party invites automatically.\n* **Season**\n    - Set the season in the client.\n* **Light**\n    - Adjust the slider to set the **Light Level** on the client. To keep this setting, be sure **Light Filter** is checked on the **General** tab.\n* **Enable Min/Max**\n    - This feature lets you set the min and max light levels that Razor will allow.\n* **Remember passwords**\n    - Using this option will save your passwords in your Profile.xml file. When logging in the saved password will be entered for you although the field will remain blank on your screen.\n    \n!!! warning\n    Anyone who obtains a copy of your profile maybe be able to decrypt your password and log into your account.\n\n* **Count stealth steps**\n    - Keeps track of steps taken while hidden, displaying the number on the bottom left of your screen unless you check **Overhead** and they will display over your character.\n* **Automatically open doors**\n    - This option will auto-opens a door every time you walk up to, or turn to face, the door.\n* **Auto Unequip hands before casting**\n    - Removes weapons from your hands automatically when you cast a spell, delaying the spell until it can be cast.\n* **Auto Un/Re-equip hands for potions**\n    - The same as above but for using potions. Once the potion is used, the item is returned to your hand.\n* **Block heal if target is poisoned**\n    - This prevents the cast of a wasted heal on a poisoned target.\n* **Force Game Size**\n    - Set your game window to the size you want. Once you have entered the size, it needs to be applied. Open options in-game (ALT+O or use the tab from the paperdoll) and click **Apply**. The game window size will be applied and remembered.\n* **Static magic fields/walls**\n    - This option will replace the field spells with static colored tiles. Checking labels will also show the name of the field.\n"
  },
  {
    "path": "help/docs/help/screenshots.md",
    "content": "# Screen Shots\n\n![ss](../images/screenshots.png)\n\nA self-explanatory section used to take and manage your in-game screenshots.  Set the path, file type, window size, delay from here."
  },
  {
    "path": "help/docs/help/scripts.md",
    "content": "# Scripts\n\nThe Razor Scripting Engine is a \"command based scripting language\" designed to make it easier to read, create, edit and share Razor scripts.\n\nFor a comprehensive guide on how to use it, please go [here](https://www.razorce.com/guide/).\n\n![scripts](../images/scripts.png)\n"
  },
  {
    "path": "help/docs/help/skills.md",
    "content": "# Skills\n\nThe Skills tab gives you general information about your skills.\n\n![skills](../images/skills.png)\n\n## Skill Table\n\n* **Skill Name**\n    - This will list every skill in the game.\n* **Value**\n    - This is your skill level before stat modifiers are applied.\n* **Base**\n    - Your skill level with stat modifiers applied. Also known as the **'Show Real'** skill level. Use these numbers when calculating skill caps.\n* **+/-**\n    - This column shows any change in skill level since you logged in, or used the reset button.\n* **Cap**\n    - The skill cap for each skill.\n* **Lock**\n    - The lock setting for each skill. `'D'` for down, `'U'` for up, and `'L'` for a locked skill.\n\n## Other\n\n* **Reset +/-**\n    - Resets all +/- column entries in the skill table to 0.0\n* **Set all locks**\n    - Set the locks for all skills according to your selection from the drop-down tab.\n* **Copy Selected**\n    - Copies the skill information from the selected skills to the clipboard. Click a skill to highlight it. For multiple skill selection, hold the control key and click all skills to be copied.\n* **Copy All**\n    - As above, all skills are automatically selected with this tab.\n* **Log skill changes**\n    - All your skill changes will be logged and timestamp into a `.csv` file in your Razor folder.\n* **Show skill/stat changes**\n    - When checked, Razor will inform you of each skill level change, the change amount and the total change since the last +/- reset.\n* **Capture MIBs to file**\n    - When you open an MIB, a file is written to the root folder of Razor.\n\n!!! warning\n    This feature only works with the default RunUO MIB Gump.\n\n* **Base Total**\n    - Displays your character's total base skill level."
  },
  {
    "path": "help/docs/history.md",
    "content": "# History\n\n![oldsplash](images/old-splash.jpg){ align=right }\n\nRazor was originally designed by Bryan Pass, known as `Zippy` in the RunUO community as a replacement to UOAssist. Based on commit notes, active development (new features, bug fixes) on Razor ceased some time in the early 2010's with the source code being released in 2014.\n\nThe code initially didn't include `Crypt.dll` and `Loader.dll` which are required to fully integrate with the UO client. At some point, the code for those projects released into the same GitHub repo (at the time of this edit, `https://github.com/msturgill/razor` no longer is available).\n\nThe original project was last updated May 2nd, 2014 which was simply an update from .NET 2.0 to .NET 4.0 and while over 50 forks exist on GitHub, none of them have been active or have made significant changes except for a few exceptions:\n\n* `Jaedan` (which this version is based on) who updated the original Razor project to compile and work in Visual Studio 2017 and made improvements to `Crypt.dll` that enabled this project to move forward.\n* `SaschaKP` who made several performance changes from generic to non-generic collections that I incorporated in the first release.\n\nI have been actively maintaining this project since early April 2018 and based this version off of `1.4.0.3`, which was simply the version `1.0.13.13` updated to .NET 4.0. All the changes for this version of Razor started under version `1.5.0.X`+.\n\nAnother closed source version of Razor exists (the `1.0.14.x` versions) that was maintained by a private shard that made some enhancements, notably around targeting. This version of Razor has long since incorporated the majority of changes you can find in that version.\n\n* In June 2019 integration into [ClassicUO](https://github.com/ClassicUO/ClassicUO) was officially established.\n* In March 2020 the [Razor Scripting Engine](https://www.razorce.com/guide/) was added to make it easier to read, create, edit and share Razor scripts while staying true to the project's state goals.\n* In May 2021 Razor moved from .NET 4.0 to 4.7.2 to bring it in line with ClassicUO.\n\n# Community Edition\n\nWhen I started this project back in early 2018, nearly all the [feedback, ideas, discussion](https://www.uorforum.com/threads/improving-razor-razor-development.33134/) and [testing](https://www.uorforum.com/threads/razor-1-5-bug-issue-release-tracking.33405/) came from the [UO:Renaissance](http://www.uorenaissance.com) community, one of the only freeshards where the rules only allow for the use of Razor. The original **UO:R Community Edition** name was used to not only distinguish between other versions of Razor that were available but give credit to a community that provided so much support early on.\n\nAs the popularity of this version grew, especially after the implementation of ClassicUO support, it became widely used across the whole UO freeshard community, from small private shards to some of the largest shards in the community and continues to be built on the feedback and contributions from all different corners of the community.\n\nWith that said, I find it more appropriate to simply call this version the **Razor Community Edition**.\n\nThank you to everyone across the whole UO freeshard community who has contributed to this version of Razor in some way.\n\nIf you'd like contribute, see the [CONTRIBUTING](https://github.com/markdwags/Razor/blob/master/CONTRIBUTING.md) file for more information.\n"
  },
  {
    "path": "help/docs/index.md",
    "content": "![razor](images/razor.png){ align=right }\n\n# Razor Community Edition\n\nRazor is a free tool designed to help with simple tasks while playing Ultima Online.\n\nThe goal of this project was to revive and continue development and maintenance of the abandoned Razor project, focusing on *quality of life* improvements while attempting to keep the spirit and vision the original developers had for Razor by not driving down the path of advanced automation that's found in other UO assistants.\n\nFor more information about this version of Razor, read the [history](./history.md), review the [release notes](./releasenotes.md), and [download](./download.md) Razor.\n\n# Help & Support\n\n* For information about how to use Razor, please review the [help guide](./help/).\n* For information about UO Razor scripts, please review the [scripting guide](./guide/).\n\nIf you're unable to find a solution using the information here or you'd like to submit a feature request or bug report, use the following resources.\n\n* Submit a feature/bug/issue on our [official Razor GitHub Repo](https://github.com/markdwags/Razor/issues).\n* Join us in `#razor` on Discord (we use the the official [ClassicUO](https://www.classicuo.eu/) Discord server)\n\n[![Chat on Discord status](https://img.shields.io/discord/458277173208547350.svg?logo=discord)](https://discord.gg/zrdyYcc)\n\n# License\n\n!!! info\n    All work is released under the GPLv3 license. This project does not distribute any copyrighted game assets. In order to run this application you'll need to legally obtain a copy of the Ultima Online Classic Client.\n\nSee the [LICENSE](https://github.com/markdwags/Razor/blob/master/LICENSE.md) file for details.\n"
  },
  {
    "path": "help/docs/install/linux.md",
    "content": "---\ntitle: Linux Install\ndescription: A quick guide on how to get Razor up and running on Linux\n---\n\n# Overview\n\nTo run Razor with [ClassicUO](https://www.classicuo.eu/) on Linux, you will need to install [Mono](https://www.mono-project.com/)\n\n!!! info\n    These steps were tested and validated a fresh installation of Linux Mint 19.1, Ubuntu 20.04, and Debian 11.5\n    \n    Based on your current configuration and Linux distribution, the steps may vary.\n\n## Install Mono\n\n!!! warning\n    If you're running another version of Linux, please read the [installation steps](https://www.mono-project.com/download/stable/#download-lin) from the main Mono site and follow those instead.\n\n* Open the command/console/terminal and add the Mono repo to your system\n\n```bash\nsudo apt install gnupg ca-certificates\nsudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF\necho \"deb https://download.mono-project.com/repo/ubuntu stable-bionic main\" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list\nsudo apt update\n```\n\n* Install the latest version of Mono\n\n```bash\nsudo apt install -y mono-complete\n```\n\n* Run the following commands from the console:\n\n```bash\nsudo apt-get install -y libmono-system-windows-forms4.0-cil\nsudo apt-get install -y libmono-system-net-http4.0-cil\nsudo apt-get install -y libmono-system-runtime-serialization4.0-cil\n```\n\n## Install libz\n\nThis package is required for ClassicUO to load gumps successfully.\n\n* Install `libz`\n\n```bash\nsudo apt-get install -y libz-dev\n```\n\n## Install ClassicUO (Launcher)\n\n* Download the latest version of the [ClassicUO Launcher](https://www.classicuo.eu/).\n  \n* Extract `ClassicUOLauncher-linux-x64-release.zip` to a local folder (ie: `/home/username/games/classicuo-launcher`)\n\n```bash\nmkdir /home/username/games/classicuo-launcher\ncd /home/username/games/classicuo-launcher\nunzip ClassicUOLauncher-linux-x64-release.zip.zip\n```\n\n* Run ClassicUO Launcher\n\n```bash\nchmod +x ClassicUOLauncher\n\n./ClassicUOLauncher\n```\n\n* Install ClassicUO by clicking **Update Available**\n\n![cuoinstall](../images/cuolauncher-update.png)\n\n\n## Install Razor\n\n* Download the latest version of [Razor](../download.md).\n* Extract to `/home/username/games/classicuo-launcher/ClassicUO/Data/Plugins/Razor`\n* Click **Edit Profiles** and setup your profile (server name, Ultima Online path, client version, etc)\n* Click **Plugins** and then **Add** and browse to `/home/username/games/classicuo-launcher/ClassicUO/Data/Plugins/Razor` and select `Razor.exe`\n* Save the profile and click **Launch**\n\n!!! tip\n    You can also run ClassicUO without using the launcher.\n\n    Go to `/home/username/games/classicuo-launcher/ClassicUO` and type `mono ClassicUO.exe` or `./ClassicUO`\n\n!!! warning\n\n    On first launch, it might appear stuck on the Razor splash screen.\n\n    ![splash](../images/linuxsplash.png)\n\n    Behind that is a message box warning you that it will use a default profile. If you experience this, simply hit `Enter` with the splash screen active.\n"
  },
  {
    "path": "help/docs/install/windows.md",
    "content": "---\ntitle: Windows Install\ndescription: A quick guide on how to get Razor up and running on Windows\n---\n\n!!! warning \"Client Support\"\n    It's **highly recommended** that you use the [ClassicUO](https://www.classicuo.eu/) client with this version of Razor, however it should work with the original 5.x and 7.x clients though support for any bugs may be limited.\n\n# Install: Razor and ClassicUO\n\nFirst, we need to download and install ClassicUO.\n\n1. Download the [ClassicUO Launcher](https://www.classicuo.eu) and extract the `.zip` file to any location of your choosing (ie: `C:\\CUOLauncher`)\n2. Run `ClassicUOLauncher.exe`\n3. When `ClassicUOLauncher.exe` opens, it will automatically download the latest version of ClassicUO and install it in a sub-folder called `ClassicUO` in the folder you extracted the launcher (ie: `C:\\CUOLauncher\\ClassicUO`). This process should only takes a few seconds.\n4. Setup a profile to connect to your shard by clicking `Edit Profiles`\n5. On the `Profile` tab click `Add`  \n    - Give your profile a name\n    - Enter your username and password if you'd like it to be saved\n    - Enter the server IP and port number of the shard you're connecting to\n    - Enter (or search for) the path to your UO files. These are the actual game files for the shard you're connecting to\n    - Enter the client version number if it isn't auto-detected\n  \nExample of a completed profile:\n\n![cuolauncher](../images/cuolauncher-profile.png)\n\nNow, we need to install Razor.\n\n1. [Download](../download.md) the latest version of Razor and extract the `.zip` file to `C:\\CUOLauncher\\ClassicUO\\Data\\Plugins\\Razor` (replacing `C:\\CUOLauncher` with the location you selected above if you picked something different)\n\n    !!! hint\n        If the `Data` and/or `Plugins` folders don't exist (most likely scenario on a new install) you can just create them first.\n\n2. In the ClassicUO Launcher, go to the `Plugins` tab and click `Add`\n3. Browse to the `\\Data\\Plugins\\Razor` folder and select `Razor.exe`\n\n    ![cuolauncher-plugins](../images/cuolauncher-plugin.png)\n\n4. Click `Save Profile` and then `Back`\n5. Select your profile and click `Launch`\n\nIf everything was setup correctly, you should see ClassicUO along with Razor open.\n\n## Advanced: settings.json\n\nIf you would like to configure ClassicUO and Razor without the launcher, create a file called `settings.json` and copy/paste this template into it and change the following values: `ip, port, ultimaonlinedirectory, clientversion, plugins`\n\n```json\n{\n  username: \"\",\n  password: \"\",\n  ip: \"login.myshard.com\",\n  port: 2593,\n  ultimaonlinedirectory: \"C:/Path/To/UO/Files\",\n  clientversion: \"5.0.8.3\",\n  lastcharactername: \"\",\n  cliloc: \"Cliloc.enu\",\n  lastservernum: 1,\n  fps: 60,\n  window_position: null,\n  window_size: null,\n  is_win_maximized: true,\n  saveaccount: false,\n  autologin: false,\n  reconnect: false,\n  reconnect_time: 30,\n  login_music: true,\n  login_music_volume: 30,\n  shard_type: 0,\n  fixed_time_step: true,\n  run_mouse_in_separate_thread: true,\n  force_driver: 0,\n  use_verdata: false,\n  encryption: 0,\n  plugins: [\n  \"C:/Path/To/Razor/Razor.exe\"\n  ]\n}\n```\n\n# Update: Razor and ClassicUO\n\nThese steps assume that you already have obtained and installed the Ultima Online game asset files in the local system and are already using ClassicUO.\n\n- [Download the latest release of Razor](../download.md).\n\n    !!! warning\n        Windows will sometimes block `.dll` and `.exe` files from being ran after they're downloaded so you may have to open up a Powershell prompt from within the Razor folder and run `gci | Unblock-File`\n\n- Extract the `.zip` into your existing Razor location (ie: `C:\\CUOLauncher\\ClassicUO\\Data\\Plugins\\Razor`), overwriting all files, with the exception of one file:\n    - **counters.xml** - This is the default counters file used to display items in your titlebar. If you've added any new counters, they would be lost if overwritten.\n- Open ClassicUO back up and verify Razor is running the version you upgraded to.  \n\n!!! hint \"Standard OSI Client\"\n\n    The upgrade steps above should also work if you're using the standard OSI client, follow these steps.\n\n    * Right-click on the Razor shortcut or Razor.exe, go to Properties. On the Compatibility tab, select **Run this program in compatibility mode** for and select **Windows XP SP2**. Also select **Run this program as an administrator**\n    * Run Razor either via the shortcut or clicking the Razor.exe directly.\n    * Razor should prompt to **Run As Administrator**. You must allow this for Razor to function correctly.\n\n# Welcome Screen (Legacy Client Only)\n\n!!! error \"ClassicUO Users\"\n    If you're using ClassicUO, you should *never* see this screen. If you're trying to open ClassicUO and see this screen, click **Quit** and launch ClassicUO.\n\nIf you're using the legacy client, to The first time you run Razor, it will open with a **Welcome Screen** and give you an option to import your existing settings if they exist.\n\n![welcome](../images/welcome.png)\n\nBrowse to your `client.exe` that you want to run along with Razor. Set the **UO Data Directory** (most likely the same path as your `client.exe`). Either use the pre-configured servers or enter your own server in the list here.\n\nClick **OK** to open Razor and Ultima Online.\n"
  },
  {
    "path": "help/docs/releasenotes.md",
    "content": "---\ndescription: Stay up-to-date with the latest Razor release notes\n---\n\n# Release Notes\n\nBelow is a list of the latest releases notes going back to the first release of this version of Razor.\n\n## 1.10.X (Dev Version)\n\n* You can always find the latest dev preview [here](https://github.com/markdwags/Razor/releases/tag/Razor-dev-preview).\n* Fixed issue with `setvar` not giving you a target cursor if you stopped the script before selecting a target.\n\n* Changed `setlasttarget` to require you provide a serial or variable as parameter. See [docs](guide/commands.md#setlasttarget).\n\n## 1.9.77.0 (03/23/2023)\n\nThis version includes more updates to the scripting engine, including the ability to create cooldowns that will display as a gump. This version also introduces lists and timers to the scripting engine. Be sure to review the latest scripting docs for details.\n\n* Added the `cooldown` command that generates a gump-based cooldown timer that can be customized (icon, color, name, order, etc)\n* Added [list commands](guide/commands.md#list-commands) and [list expressions](guide/expressions.md#list-expressions)\n* Added [timer commands](guide/commands.md#timer-commands) and [timer expressions](guide/expressions.md#timer-expressions)\n* Added the `foreach` loop to interact with lists\n* Option to disable 25ms delay on script line execution\n* Updated script variables to be part of the same system that sets variables using the `as` operator\n* Fixed missing syntax highlight for `maxweight`, `clearhands`, `cleardragdrop`, `sell`\n* Running a script will show the name in the system message\n* Fixed the `ignore` and `unignore` commands\n* Fixed the `varexists` expression\n* Added the `unsetvar` command\n* Updated the `interrupt` command to let you pass a specific layer\n* Option to disable highlighting on the script UI\n* Better error handling on script syntax issues\n\n## 1.8.61.0 (12/07/2022)\n\nThis version includes several new scripting commands, the ability to resize the Razor window, and Pandora like features. Versioning will slightly change, next versions will be 1.9.X.0, 1.10.X.0, 1.11.X.0, etc where X indicates the build/run ID.\n\n* Fix issue with delete profile button\n* Added `sound` and `music` script commands that will play specific sound or music in the client\n* Added `classicuo/cuo` script commands, `>cuo` manual command to control ClassicUO settings directly\n* Added sound trigger option to overhead messages\n* Fixed issue with buffs/debuff filter not loading on a profile change\n* Reload scripts will read all changes made externally to scripting files\n* Added the ability to resize the Razor window\n* Fixed issue with buy agents not saving/loading correctly\n* Added `itemcount` expression that returns the number of items you carry in total\n* Fixed `lifttype` to pull the correct amount when including a hue\n* Added `rename` command to allow you to rename a follower\n* Added `getlabel` command with the `in` expression to capture text from a single clicked item\n* Fixed script tab not displaying the set hotkey\n* Added Pandora inspired tabs in the Advanced (shard staff specific)\n* Removed the script popout editor now that you can resize the main Razor window\n* Updated the `dress` and `undress` commands to accept a serial or variable\n* Updated `gumpclose` to accept an optional gump id\n* Added an option to trigger male or female sounds base on specific emotes (ie: `*cheer*` or `*laugh*`)\n* Script editor will highlight the current line when executed via the Play button in the UI\n* Updated `setvar` to accept a serial (bypassing the target click) and to set temp variables using `!` (see docs)\n* Fixed issue when using `findtype` with `or` and `as` where the variable wouldn't assign correctly\n* Increased system message queue from 25 to 100 messages\n* Added `ignore`, `unignore`, and `clearignore` commands\n\n## 1.7.4.49 (07/26/2022)\n\n* Added `followers` and `maxfollowers` expressions\n* You can manage your agents in-game using `>restock #`, `>org #`, or `>buy #`\n* `>info` command will display an image of the item\n* Added the option for Next/Prev to be alphabetical\n* Updated how damage when dealt or taken is displayed\n* Fixed the mobile filter so it doesn't rely on movement\n* Mobile filter is applied to mobiles on the screen when changing it in the UI\n* Added wyrm as a mobile filter\n* Added `targetexists` expression\n* Added `diffhits, diffweight, diffmana, diffstam` expressions\n* If the server disables macro loops that will also disable script loops\n* Added an [index variable](https://www.razorce.com/guide/variables/#index-variable) to reference in scripts\n* Added `name, paralyzed, invuln, warmode` expressions\n* You can now assign `>custom` commands to hotkeys and execute using a command\n* Fixed issue with the macro/script key binding not always displaying correctly in the UI\n\n## 1.7.3.36 (01/10/2022)\n\n* Option for buy agents to ignore the amount of gold you have\n* `findtype`, `targettype`, `liftype` will match on the full item name only\n* Agents can be assigned an [alias to be more easily identified in the dropdown](https://www.razorce.com/help/agents/#aliases)\n* Agent aliases can be used in scripts\n* Organizer and restock agent won't force the UI to come to the front when executing via scripts\n* Added Next/Prev Friendly hotkey\n* Added a pause script hotkey\n* Added Pause/Resume to popout script editor\n* When changing values in agents, it will be an in-game gump vs. a Razor UI inputbox\n* Added `varexist` expression\n* Added a `hue` parameter to `findtype`, `targettype`, `dclicktype` and `lifttype` for items\n* Updated how the script `count/counter` expression works, it no longer requires you to have a counter setup under Display->Counters (thanks @sorsarre)\n\n## 1.7.1.7 (10/13/2021)\n\n* Added the keyword `as` when scripting to assign temp variables. See scripting guide.\n* Fixed issue with auto-save of scripts\n* `AutoSearchExemption` will now save by type\n* `menu` command will block popup unless you pass a parameter\n* Sound filter list and sound names are in sync, sorts in alphabetical order, block correct sounds\n* Fixed syntax highlighting on nested quotes in scripts\n* Razor should now run again with the legacy OSI client\n* Razor settings are stored in a simple csv file now\n* Feature flags can be 32-bit\n\n## 1.7.0.12 (5/29/2021)\n\nThis version has two key updates. First, it updates the .NET framework from 4.0 to 4.7.2, bringing it inline with ClassicUO. Secondly, to make script editing a bit easier, there is now a popout editor available.\n\n* Updated Razor to .NET 4.7.2 and increased the version to from 1.6.x to 1.7.x\n* Added a new popout script editor. Right-click on the script editor to use it.\n* Copy screenshots to clipboard and open screenshot folder from UI\n* Fixed undress command when using a layer\n* Fixed issue with `guardlines.ref` not being read by UOPS\n* Added syntax highlighting for `targetloc` command\n* `targetloc` requires two params, z will default to 0 if not included\n* Show incoming name/target only for new mobiles\n* `setvar` command will create the variable if it doesn't exist\n* Added `cleardragdrop` command\n* Added `interrupt` command\n* Added `cancel` param to the `target` command\n* Added `clear` param to the `target` command to clear the target queue\n* Fixed issue with nested for loops and the `break` statement\n* If you clone a profile to an existing name, it will block that\n* When recording a script, it will capture `target 'self'`\n* Fix how auto-script save works on Linux\n\n## 1.6.9.21 (02/27/2021)\n\n* Fixed issue with `setvar` and similar named variables\n* `spirit` and `forensic` are valid `skill` entries for scripting\n* Added `queued` expression to scripting\n* Removed global script range checkboxes, review the guide for the correct syntax\n* Fixed `drop` command to check for the correct params\n* `lifttype` will default to 1 if not value is provided\n* Import/export agents from the UI by clipboard or other profiles\n* `findtype` supports the `backpack` param\n* `lift` and `lifttype` will correctly wait before continuing\n* `dress` and `undress` will also correctly wait before continuing\n* `waitforsysmsg`, `waitforgump`, `waitgformenu`, `waitforprompt` will accept a timeout param\n* Check if a spell needs channeling before triggering unequip\n* Counters correctly save when you click Save\n* Added `clearall` command. See scripting guide for details.\n* Target Closest Friendly Humanoid will only target a humanoid\n* Updated `target` command with new features. See scripting guide for details\n* Added support for `@` quiet prefix for commands\n* Added `clearhands` command to drop what you have in your hands\n* `dclick` now supports `left`, `right` and `hands` to use an item in your hand\n* Added `virtue` command to invoke honor, valor or sacrifice\n* `Cancel Target` will cancel setting a varible if it's active\n* Fixed `TargetByType` and `DoubleClickType` in macros with range check. The range checks were always meant to include in your backpack too\n* Added `random` command to generate a random number you can use with `insysmsg` to help perform a random action\n* Improved support for keycode differences between Windows and X11\n* Additional support for dotnet core 3.1\n\n## 1.6.8.15 (12/15/2020)\n\n* Implemented treeview and categories for scripts\n* Added ability to adjust the size of the script editing window and the list of scripts\n* `script` command can now call the new supported categories\n* Added `findbuff` scripting expression\n* Fixed right-click menu not opening when selecting something in the script editor\n* Script will throw an error if you use `if count` with an counter that isn't setup\n* Fixed issue with the individual sound filter being off by 1\n* Added `guild` and `alliance` scripting commands\n* Converting macros to scripts will retain the same name if available\n* Added `position` scripting expression\n* Added ability to override which weapons Razor consider two handed\n* ++ctrl+s++ will save the current script you're editing\n* Save indicator in main window when editing scripts\n* Fixed issue with `lift` command requiring the optional parameter\n\n## 1.6.7.10 (10/24/2020)\n\n* `>info` command gump will close when you try to close it\n* Split 'Auto-Un/Reequip hands for potions' into 2 options\n* Added in-game gump to show assigned Razor hotkeys. Type `>hotkeys`\n* Added hotkeys for all Razor gumps that were available in commands (`info`, `sysmsg`, `hotkeys`)\n* Added Set Hot Key button to agents\n* New Filters tab on Razor and moved all filtering related features as sub-tabs\n* Ability to block/filter specific text\n* Added `whisper` and `yell` commands to scripting\n* Fixed issue loading files when using the OSI client\n* Option to disable tooltips in the script editor\n* Fixed infinite loop issue with scripts when using nested for loops\n* The script list on the UI will be in alphabetical order on Linux\n* Added `waitforsysmsg` command as this can be achieved already using while loops.\n\n## 1.6.6.15 (09/14/2020)\n\n* Fixed ancient Razor bug that could cause non-existent items to remain in your queue (ie: when you stack a pile of gold on to another). This should fix some instances where scavenger isn't picking up items (thanks @SaschaKP)\n* Fixed another ancient Razor bug where the vendor pack items aren't updated realtime by the server (it's managed client side). Razor should behave exactly like this. This will remove the warning in extinfos with amounts not matching. (thanks @SaschaKP)\n* Fixed issue where party/friends overhead messages\n* Moved the Overhead Messages feature to the `Display/Counters` tab so its more visible to everyone\n* Revamped the General tab UI as it was too cluttered. Removed UOAM and Ultima Mapper shortcuts\n* Moved the `Sound/Music` tab to the main `Filter` tab\n* Moved the `Waypoint` tab to the `Display/Counters` tab\n* Change the hue of the overhead message in the macro UI\n* Fixed issue with scripts not parsing words like `spider's silk` correctly\n* Fixed macro->script conversion for wait/pauses\n* Created hotkeys to help generate script commands for `targettype` and `dclicktype`\n* Added right-click menu to script list (reload, open externally, copy to clipboard)\n* `>info` command will popup a gump that will display information about a mobile or item and let you copy by clicking the blue buttons\n* Fixed some issues loading the previous profile\n* Added `>sysmsgs` to display a gump of the current system messages in Razor's buffer for macro and scripting\n* Prevent empty strings from going into the system message buffer\n\n## 1.6.5.16 (08/08/2020)\n\n* Fixed issue with saving scripts in certain scenarios\n* `targettype` will find mobiles and items by name\n* Moved Friends tab to the main tab list\n* Added stop command to scripts\n* Removed unused dependency\n* Set friend tag and hue per group\n* Attack name overhead \"new targets only\" works on hotkeys\n* Changed default encoding on profiles to UTF8 (cross platform support)\n* Added the ability to set waypoints in-game\n* Create a waypoint to the position of your corpse upon death\n* Added '`backpack`' option to `dclicktype` and `targettype`\n* Moved Filters to the main tab list\n* Added Next/Prev Non-Friendly Targets\n* Added `clearsysmsg`/`clearjournal` to scripts and macros\n\n## 1.6.4.32 (05/17/2020)\n\n* Fixed any errors related to systray and long titles\n* Razor supports Linux again after fixing issues related to the new script editor\n* Fixed issues with `dclicktype` and `targettype` range check (both Macros and Scripts)\n* Fixed a few packet exception issues when logging in or casting spells\n* Script engine optimizations (better error reporting, better timeout/pause handling)\n* Fixed issues related to `waitfortarget`/`wft` not working correctly\n* Fixed issues with nested if/else/endif\n* Fixed the '`lasttarget`' variable\n* Added '`hidden`' expression\n* Fixed '`findtype`' expression\n* Added range check to '`findtype`'\n* Fixed righthand, lefthand and hand variables/aliases\n* Field to filter scripts in the UI\n* Added hotkey to add party members (`/add`)\n* Added feature to convert macros to scripts (right-click macro and convert)\n* Backup will include Razor Scripts\n* Added support for Mystic and Masteries\n* Show Attack message when using Attack Last Target hotkey\n\n## 1.6.4.2 (03/16/2020)\n\nThis version introduces a new scripting engine that makes it easier to create and share macros.\n\nFor more information, visit the [Razor Scripting Engine Guide](https://www.razorce.com/guide/).\n\n* Introduction of the Razor Scripting Engine (thanks to everyone for your time testing and providing feedback)\n* New Sound & Music Tab: Filter out any game sound, trigger music and listen to any sound\n* Added while loop to the macro system\n* Fixed issue with auto-screenshot not working with players with invalid characters in their name\n* Enforce your min light level on login\n* You can extract specific words from the system message to display in the overhead messages (`{1} {2}`, etc for the first, second word)\n* Added Set Macro Variable Target Action to macros that will pause until you set a variable (same behavior as \"Set Last Target\")\n* Razor's Last Object (hotkey and macro/scripts) should work as expected\n* `>hue` and `>item` commands are a bit more informative\n* You can copy/paste friends list when you aren't actually logged in\n* Added option to have next/prev friend highlight friend in Friends tab\n* The Discord overlay shouldn't cause any access violations\n* SysTray will go away on close (instead of leaving ghost ones behind)\n\n## 1.6.2.23 (12/18/19)\n\n* Changed interrupt order to start shirt, shoes, pants\n* Fixed Edit button on Overhead Message UI\n* Capture compressed gumps for WaitForGump\n* Additional UI SafeActions\n* Added ability to filter out mobiles from being targeted\n* Added `if skill` to macros\n* Fixed invalid cast error on `if counter`\n* Fixes a bug were when changing a character in same account, using different profiles (not default), causes a sudden lockdown of razor window, that also locks ClassicUO from * loading, causing a crash after a while.\n* Double clicking Overhead Message macro action now opens Input box for editing message instead of Pause action menu.\n* Bandage timer will restart if bandage is applied before it ends\n* Using 'Add Target' under the friends tab will give you a target\n* Renaming a macro removes the old entry from the hotkey list\n* Added Set HotKey button to macro UI\n* Added `>set` command to set macro variables in-game\n* Prioritize key that triggered event, include number row in SDL keymap\n* For ClassicUO, dont trigger Hotkey.OnKeyDown if key is a modifier key\n* UOPS displays Trammel and TerMur correctly\n* Fixed issue with GumpReponses with text entries not loading\n* Bandage timer will stop on \"You did not stay close enough to heal your target.\n* Bandage timer will reset if you bandage yourself before finishing\n* Remove packet block on 0xF0 when using ClassicUO to allow party tracking in WorldMap\n* Added mobile filter for daemons\n\n## 1.6.1.32 (08/05/19)\n\n* Next/Previous will only set Beneficial when using Next/Prev Friend\n* Changed Razor commands from - to > (ie: -hue is >hue)\n* Next/Previous Target will check if the target is a friend\n* Next/Previous Friendly can be set to only set Beneficial\n* Next/Previous Non-Friendly can be set to only set Harmful\n* Fix to how names are handled per mobile\n* Pet & Boat commands now use the speech override hue\n* Enabled the seasons dropdown when using ClassicUO\n* Fixed ContextMenu not recording & execution\n* AbsoluteTargetVariables and DoubleClickVariables have been merged into MacroVariables.\n* When adding an Overhead Message, if it doesn't exist in the list you will be prompted to add it anyway\n* Fixed issue with Friends and Dress lists not always loading when using ClassicUO\n* Improved the bandage timer to pick up additional start/stop messages\n* Set Last Beneficial & Set Last Harmful now have the proper system message\n* Friend hotkeys now display under a new \"Friends\" hotkey category\n* Buff/Debuff overhead messages can be filtered and hues changed\n* Added check to prevent multiple single-click flag checks\n* Additional SafeActions added to the UI\n* Added {name} as an option for the target indicator\n* Added the ability to edit the bandage start/stop messages\n* Fixed issue using the delete key when removing Friends\n* Updated the screenshot capture on death (option to add a delay, and to capture self death or death of others)\n\n## 1.6.0.57 (06/28/19)\n\nAfter 57 builds, Razor now fully supports [ClassicUO](https://github.com/andreakarasho/ClassicUO). Thanks to KaRaShO for his amazing work on this client. Thanks to Jaedan, DarkLotus, and everyone who helped test Razor and provided feedback.\n\n* Enabled support for ClassicUO and standard OSI client\n* Enabled cross-platform support (specifically Linux)\n* Several optimzations, tweaks, and overall improvements to Razor.\n* Queue Last/Self default to disabled\n* Auto-queue object delay default to disabled\n* Clean Config.cs formatting\n* Merged UltimaSDK\n* Add Grab HotKey & Set Grab Hotbag\n* New Next/Prev Hotkeys\n* Added Criminal, Murderer and Innocent Next/Prev hotkeys\n* Add Next/Previous for Friendly, Gray and Non-Friendly\n* Refactored the Next/Prev code\n* Added target sub-categories in HotKeys\n* Restored {mana} and {stam}\n* Added Toggle War and Toggle Peace only hotkeys\n* Added < and > to if macro actions\n* Added {maxhp}, {maxstam} and {maxmana} as variable options in the IfActions in macros\n* Added a Greater Heal/Cure hotkey, relabeled Heal/Cure Hotkey to \"Smart Heal/Cure\"\n* Support SmartLastTarget in AttackLastTarget\n* Added Set Beneficial and Harmful hotkeys\n* Added option to disable auto-open door when hidden\n* Added use item for Right or Left hotkeys\n* Added option to disable play/finished macro message\n* Next/Prev will ignore ghosts and blessed mobiles (just like random and closest)\n* Added ability to insert overhead messages in macros\n* Hotkey enable/disable messages will use warning or default Razor message hues. This should make it easier to see/read when you're hitting the hotkeys.\n* Next/Prev friend won't set them as a combatant\n* Added Insert Wait For Target for macros\n* Added option under Display/Counters to display bandage timer overhead or in system messages\n* Removed Friends Agent and added new Friends Groups\n* Create groups of friends\n* Enable/disable groups\n* Copy/paste friends in and out of Razor\n* Implemented filtering of repeating messages for system, Razor and overhead messages\n  \n## 1.5.0.17 (03/17/19)\n\nThis version completely changes how Razor handles movement. Prior to this release, Razor would parse movement packets to determine your current X/Y/Z. During certain in-game actions, such as running when casting, this would sometimes cause you to desync. This is when the server thinks you're at a certain X/Y/Z and Razor thinks you're on another.\n\nRazor will instead start a timer in the client that checks if the position has changed in client memory. When your position changes, it will send a message to notify Razor.\n\nThis way, Razor is no longer in the business of reading movement packets which should prevent you from ever desyncing.\n\n### Razor\n\n* Razor should no longer \"desync\" (usually experienced by people with lower pings).\n* Crypt.dll has been cleaned up and optimized. You should notice Razor and UO start up quicker.\n* If Razor has an issue verifying an animation for the filter dropdown, it will just load it by default.\n\n### Macros\n\n* The \"Waiting.. Timeout\" message when you're running a macro is easier to read.\n\n### HotKeys\n\n* If you use the \"Add All Mobiles To Friends\" it won't add the same person twice.\n\n## 1.5.0.16 (03/04/19)\n\n### Razor\n\n* Changed the position of the Quit button on the Welcome screen.\n* Removed packet and AVI recording since the feature has been sunset by modern applications and technology. If you need to watch or record packet videos, please use and older version. If you want to record videos, check out OBS.\n\n### Options->Speech & Messages\n\n* Added an Edit button to the Overhead message window to edit a message.\n* Added an option to show [Friend] overhead if that mobile is on your friends list.\n\n### Options->Targeting & Queues\n\n* Fixed issue with Next/Prev Humanoid still targeting friends even when the checkbox was checked.\n\n### Options->Additional Options\n\n* Combined \"Always show stealth steps\" and \"Count stealth steps\" into one checkbox. The Now counting stealth steps. message has been removed since it didn't have any logic to only fire off when stealth was successful. Utilize the Overhead message feature if you want to see something overhead on a successful stealth.\n* You can now customize the step message overhead.\n* The Static Wall and label checkbox will now load/save properly.\n  \n### Skills\n\n* Added an option to show skill/stat gains overhead.\n\n## 1.5.0.15 (02/17/19)\n\n### Razor\n\n* Revamped the main Razor UI: As the feature set has grown, space has become limited. This initially led me down the road of expanding the window based on the top, but this started to prove to not be a good long term solution. I tried to keep the look and feel as close to Razor as possible.\n* Removed window adjusting size based on the tab. It's now a static size.\n* The \"Options\" tab now has sub-tabs with features broken into smaller categories.\n* The \"More Options\" tab has been removed and condensed into \"Options\"\n* The \"Display/Counters\" tab has been broken into two sub-tabs.\n* The \"Macros\" tab has been broken into two sub-tabs, instead of that little button to expand the window.\n* Numerous other slight adjustments.\n* Revamp of the Welcome UI: Just to go along with the main UI revamp.\n* More easily manage servers from the welcome UI\n* Warning if your UO Client Directory and UO Data Directory don't match (often a source of issues for people)\n\n### Macros\n\n* Razor now will record and play prompt actions (ie: renaming runes, renaming runebooks, etc).\n* Re-targeting a mobile on the DoubleClick action (ie: a horse) will work instead of having to re-record the double-click action.\n\n### HotKeys\n\n* Added a hotkey to add all the mobiles in range to your friends list.\n* Added hotkeys for all pet commands (all follow, all kill, etc). This does the exact same thing as a standard macro recorded saying the command.\n* The following targeting hotkeys exist in another version of Razor (1.0.14.10) that was updated in 2017. They've been added in this version.\n    * Closest Criminal Monster\n    * Closest Innocent Monster\n    * Closest Murderer Humanoid\n    * Closest Murderer Monster\n    * Random Criminal Monster\n    * Random Innocent Monster\n    * Random Murderer Humanoid\n    * Random Murderer Monster\n    * Next Monster Target\n    * Previous Monster Target\n* The following targeting hotkeys are new to this version of Razor and did not exist in previous versions.\n    * Closest Friendly Humanoid\n    * Closest Friendly Monster\n    * Closest Non-Friendly Humanoid\n    * Closest Non-Friendly Monster\n    * Random Friendly Humanoid\n    * Random Friendly Monster\n    * Random Non-Friendly Humanoid\n    * Random Non-Friendly Monster\n    * Closest Mobile\n    * Random Mobile\n  \n### General\n\n* When you change your profile, the animation filter list will properly reload.\n  \n### Options->Targeting & Queues\n\n* Added option to change the text of the target indictor.\n* Added option to prevent Next/Prev target hotkeys from targeting friends.\n\n## 1.5.0.14 (01/16/19)\n\n### Display/Counters\n\n* Added a damage tracker feature that can be enabled/disabled via a hotkey that will track the following:\n    * DPS (Damage Per Second)\n    * Final DPS\n    * Max DPS\n    * Total Damage Dealt\n    * Total Damage Taken\n    * Max Single Damage Dealt (and to which mobile)\n    * Max Single Damage Taken\n    * Top 5 Damage Dealt By Name (ie: if you kill dragons for an hour, it will give you the total damage you dished out to all those dragons)\n* When you stop the damage tracker, the stats above will be displayed in your client and journal.\n* Updated the UO Title Bar to accept the following variables to display the tracked values above: {dps}, {maxdps}, {maxdamagedealt}, {maxdamagetaken}, {totaldamagedealt}, {totaldamagetaken}\n* You can change the text in Razor's title bar just as you can with the UO title bar.\n\n\n### General\n\n* Added the ability to toggle Dragons and Drakes to use a different graphic. This will have the same effect as those who use the \"artmods\" to replace the large dragon graphic will a small dragon or some other graphic completely (Blackthrone is a popular one). In other words, only you will see the graphic change.\n* Minor UI tweaks you may or may not notice.\n\n### Hot Keys\n\n* Added a hotkey that will only enable hotkeys (not toggle on/off).\n* Added a hotkey that will only disable hotkeys (not toggle on/off).\n\n### Maps\n\n* Added UOAssist API support back into Crypt so Ultima Mapper and other applications that use that will work with this version of Razor.\n* Added buttons to quickly open UOAM or Ultima Mapper from the Maps tab.\n\n### Macros\n\n* Added the ability to filter macros for easy searching.\n\n### More Options\n\n* You can now set individual hue colors for overhead messages.\n* Damage indicators in UO don't show up in your journal. Added an option to have damage dealt and damage taken display overhead or in the lower-left which will have it log to your journal.\n\n## 1.5.0.13 (01/01/19)\n\n### More Options\n\n* Added option that will turn magic fields/walls into static tiles.\n* Updated the attack name overhead feature to include the names of targets acquired via hotkeys.\n* Added option to display a text target indicator over a newly acquired target.\n* You can no longer open up multiple container label and overhead message windows.\n\n### Macros\n\n* Along with AbsoluteTarget variables, you can now create DoubleClick variables. NOTE: The goal of these macro variables is allow macros to be shared across multiple characters without requiring cloned copies of the macros.\n* You can retarget to Lift and LiftByType actions (instead of having to record, re-lift new item, stop recording, delete old action)\n* Pausing a macro when one isn't running will no longer cause a crash.\n* Copy/pasted macro lines won't appear \"linked\" and will work across other macros.\n\n### Maps\n\n* The boat control will now let you set relative location. Right-click on the direction you're going to set the relative location.\n\n## 1.5.0.12 (12/25/18)\n\n### Razor\n\n* Fixed the issue that was causing the \"filter exceptions\" popup\n* The -ping command will display the correct value for the average\n* Entering the wrong -command will no longer result in an error popup\n* The previous version reverted Razor from using the updated visual style back to the older looking style due to a Windows patch last month (KB4459942). This has been fixed.\n\n### Macros\n\n* Fixed the issue with Absolute Target Variables not saving correctly in a macro\n\n### Agents\n\n* Like the Organizer Agent, you can no longer enter mulitple items into a Restock Agent\n* Double-clicking on the list when viewing the Restock or Buy agents will popup the dialog to change the value (same behavior as clicking Edit)\n\n## 1.5.0.11 (11/20/18)\n\n### Razor\n\n* Razor will check the value of UODataDir in your config before looking to the registry, making it now fully portable and able to handle computers with multiple versions of UO installed. This should fix missing images in the titlebar on counters for some people.\n* Razor will try to be a little smarter when determining if it's offscreen and reset itself if it is.\n\n### More Options\n\n* If your container has a non-generic name (ie: holiday bags, special chests), you can set an alias so the container label will work on it.\n* Added an option to automatically block trades\n* Added an option to auto-accept party invites from friends\n* You can set an min/max light level. Be sure you have your Light Filter unchecked before using this feature.\n\n### Macros\n\n* Double-click GumpResponse to check button ID\n* Added Use Last Gump Response to macro options (ie: to update a macro using a runebook)\n\n### Hot Keys\n\n* Added a hotkey to interrupt spell casting (same effect as having a macro that picked up and equipped a pair of shoes).\n* You can now capture data from large and small BOD deeds. The file will be saved in a .csv file (BODs.csv) in the root path of Razor.\n  \n## 1.5.0.10 (11/2/18)\n\n### Razor\n\n* Razor won't display extra systray icons\n* Manually typing in a server name will save it correctly to the config\n* Razor will correctly handle different sized maps\n* Razor will import your macros, profiles and counter.xml from %AppData%\\Razor when you run it the first time and the ImportProfilesAndMacros is set to true in the config.\n* Razor will ignore if Window's font is zoomed (Windows 7 is 125% by default on some machines)\n* -ping command will give a litle more detail\n\n### Options\n\n* You can now set the season in Razor that will display in the client. This will only change what you see.\n\n### More Options\n\nYou can now assign container labels to containers (chests, bags, etc) in UO. This label can be colored coded and set to help identify what is in the container.\nOverhead messages can be changed from Unicode to ASCII (more classic look)\n\n### Macros\n\n* Absolute Targets will now save in the profile instead of a separate file.\n* Double-Clicking \"If\", Comments or \"For Loops\" should open the correct dialog\n* Added ability to edit speech in macros\n* Potential fix to WaitForGump action not working\n* After you add a macro via the clipboard, it will desolate your clipboard.\n\n### Agents\n\n* Create a new agent IgnoreList, this allows you to add people to the list and all messages (regular, yell, whisper, emotes), except for spells, will be blocked from displaying in UO. This includes being blocked from going into Razor's internal SysMessage queue to be used for macros.\n\n### Hot Keys\n\n* Add UseOnce Container should no longer crash Razor\n* Added Previous Target hotkeys to match the Next Target hotkeys\n* Organizer and Restock hotkeys sorting has been changed to be more clear (this will require mapping those hotkeys)\n* Instead of trying to figure out the monsters using mobtypes.txt, I changed the logic of targeting monsters to target anything that isn't human. This should prevent scenarios where it wouldn't target a monster using an animal model.\n\n### Advanced\n\n* The backup profile/macros button should now work if a certain folder is missing.\n\n### Display/Counters\n\n* {skill} timer will start when using skills directly in the client\n\n## 1.5.0.9 (9/26/18)\n\n### Map\n\n* Captured MIBs display on screen\n* Boat uses your Razor speech text\n* Fixed Stop from adding slow or one\n* Fixed slow left from not responding (stubborn tillerman)\n\n### Display/Counters\n\n* Added {buffsdebuffs} to display bar with timer countdown\n* Fixed {followers} and {maxfollowers}\n* Gold tracker now shows total minutes {goldtotalmin}\n* Gold tracker will start when you pick up your first gold pile if enabled\n* Added {uptime} to show how long you've been connected\n\n### Options\n\n* Added option to block auto-opening corpses twice in a session\n\n### More Options\n\n* Buffs and debuffs can now be displayed over your head\n\n### Hotkeys\n\n* Added Scavenger Enable/Disable, Scavenger Set Hot Bag and Scavenger Add Target\n* Added HotKey to trigger Gold tracker on or off\n\n### Advanced\n\n* Fixed Advanced tab to show which features are enabled\n\n### Razor\n\n* Default Razor config will be taskbar instead of systray\n\n### Macros\n\n* Added option to do a range check on TargetByType\n* Added option to do a range check on DoubleClickTargetType\n* Fixed the WalkAction macro to no longer cause massive desync issues\n\n### Screenshots\n\n* You can now upload screenshots to Imgur from Razor for easy sharing. All images are uploaded anonymously and are not linked to any Imgur account.\nRazor will keep a history of images uploaded, and store the delete hash so they can be deleted.\n\n## 1.5.0.8 (8/29/18)\n\n### Razor\n\n* I had a talk with the tillerman and he agreed to respond to your boat commands.\n\n### Map\n\n* Party members who are out of range will continue to update their position on your map.\n* When using \"Smart Always On Top\", JMap will react like Razor and UOPS do when you unfocus the current UO client.\n* Added HotKey that will toggle JMap visible/hidden.\n* Fixed issue with MIB coords sometimes being negative.\n* Updating the X/Y changes now update markers correctly.\n* Marker X/Y accept proper inputs.\n* New MIB icons for mib x/y coords.\n* Fixed rendering offset with some markers\n* Mouse coords should now display correctly.\n* TMap and MIB Markers should now highlight their corresponding tile when hovered.\n\n### Options\n\n* Object delay has a checkbox. Unchecking it will set your delay to 0. You can still leave it enabled and enter 0.\n\n## 1.5.0.7 (8/24/18)\n\nThis version includes a new Overhead system that lets you trigger messages that are in the lower-left to appear overhead.\n\n### Razor\n\n* Updated the main UI to use the modern Windows theme if it's enabled. Looks much nicer now.\n* Sound filters for bulls, dragons and chickens.\n* Updated UI size and text size for all input forms.\n* Moved packet logging location to Razor directory\n* Added Save button to Profile (previously you could only save your profile by exiting out of UO completely)\n* Additional updates to Razor to make it fully portable. If the registry keys for UO are missing, it will default and use the UODataDir defined in the config. You should be able to copy/paste your UO folder and Razor to any location now.\n\n### Map\n\n* Enabled JMap\n* Added stop and a close button to the Boat Control Window\n* Added MIB capture feature. When you open an MIB, it will write the X/Y coordinates to a file that can display in JMap.\n\n### Hot Keys\n\n* Added \"Set Sell HotBag\" hotkey\n* Added \"Add UseContainer\" hotkey\n  \n### Display/Counters\n\n* Added gold per second, minute and hour to titlebar. This can be enabled per session and tracked via adding {gps}, {gpm}, {gph} and {totalgold} to your display bar\n* Fixed skill timer ({skill} in the displaybar) to be more accurate\n  \n### More Options\n\n* Added Overhead Message UI\n* Updated Force Screen Size checkbox to tell you to open options and click Apply instead of logging out and back in\n* Added option to put stealth count overhead\n  \n## 1.5.0.6 (7/18/18)\n\n* Added light level bar to change in game\n* Unchecking the light filter will reset it\n* Added boat control UI and functionality (similar to UO Rudder)\n* Added initial Map tab for new map update, most features are not enabled\n* Added a hotkey to only show mobiles\n* Added a hotkey to only show corpses\n* Target Closest Gray Monster will include dire wolves and hellhounds.\n* Option to disable put self/last/clear target messages from being overhead\n* Added option to display stun messages overhead\n* Updated bundled counter.xml to include more useful items\n* Added feature to log your skill gains to a CSV file per character\n* Sound filters for bulls and dragons\n* Removed some responses from the -mobile command that didn't show data\n  \n## 1.5.0.5 (5/18/18)\n* Updated the -mobile command to have some additional information\n* Add IsSeaMonster to each Mobile object\n* Fixed the Target Closest Gray Monster and Random Gray Monster to include Sea Monsters (sea serpents, etc)\n  \n## 1.5.0.4\n\n* Fixed issue with macros not opening up in the editor if they were in categories.\n* Added ability to step through a macro when playing (ie. for debugging)\n* Stepping through a macro now works from \"Play From Here\"\n* Added a button to disable SmartCPU for testing purposes\n* Added Hotkey to Pause current macro\n* Added the -item command to do the same as -hue\n  \n## 1.5.0.3\n\n* \"Fixed\" issue with missing Z axis on player. Compiling Crypt.dll with Optimizations would break it. Need more research but a current work around.\n* Additional check on disabling SmartCPU\n* Additional generic to non-generic array changes\n* Auto-open doors is default true in new profiles\n* Added by type protection based on @uoitalia's code\n* Added Target Next Enemy Humanoid\n* Added a checkbox to force different TargetByType targets. In other words, don't target the same type twice.\n* Added -clearitems and -resync commands. -clearitems is experimental to see if it addresses issues where items out of range are picked up\n* Added Cyclops and Titans sound filter\n* Deer Sound filter works correctly\n* Fixed issue with the Hotkeys filter no resetting when you left the tab and came back\n* You can open a macro externally to your default editor\n\n## 1.5.0.2\n* Added Target Random Grey Monster\n* Added Target Random Enemy Monster\n* Added Target Closest Grey Monster\n* Added Target Closest Enemy Monster\n  \n## 1.5.0.1\n* Fixed issue with organizer agents not saving correctly (and thus not loading correctly)\n* Fixed issue with not being able to delete an absolute target when you had 1 left\n* Razor will remember the last server you picked\n* Additional validation on the OK button to be sure you selected a data dir and UO client\n* Added a few issues with getting PacketFilter errors on values that didn't exist.\n  \n## 1.5.0.0\n\n### Razor\n\n* Remove the auto-update feature check\n* Remove PayPal button on Razor splash\n* Popup windows for input should auto-focus and not require clicking in the text field first\n* Convert much of the old .NET Hashtables and Arraylists to hopefully improve with performance\n* Remove the use the DateTime.Now and use DateTime.UtcNow for the internal mechanism (DateTime.Now is 10 times slower than DateTime.UtcNow)\n* Added -hue command\n* Removed dependancy on InstallDir being in HKLM which should result in more people able to use Force Screen size. GetInstallDirectory now returns the folder the Razor.exe is running in.\n* Removed all dependancy on the HMCU for the registry. All settings are in App.config and all Profiles and Macros are expected to be the sub folder of Razor.exe\n* Additional UI adjustments\n\n### General\n\n* Completely remove the SmartCPU feature\n* Add Clone Profile button to easily create a copy of an existing profile instead of having to use the default\n* Add Checkbox to enable confirmation buttons on buttons that clear lists or delete things\n* Delete confirmation when you deleting a profile\n  \n### Options\n\n* Add {circle} to the Spell Format option to display, if you want, the circle the spell was casted from.\n\n### Macros\n\n* Copy macro to clipboard\n* New button to create macro from clipboard\n* Control-UP / Down to move macro line\n* Rename macro from UI\n* Double click macro action opens Edit dialog instead of having to right-click and Edit..\n* Adding a macro to a group should not require typing in the group name each time\n  \n### Arms/Dress\n\n* Add confirmation box on Clear List\n  \n### Agents\n\n* Add confirmation box on all clear buttons (so tired of accidently clicking clear instead of clear hotbag)\n\n### Hotkeys\n\n* Filter by name to quickly find a hotkey\n"
  },
  {
    "path": "help/docs/stylesheets/extra.css",
    "content": ":root>* {\n  --md-code-hl-function-color: #e72b2b;\n  --md-code-hl-constant-color: #2B90AF;\n  --md-code-hl-keyword-color: #FF860E;\n  --md-code-hl-string-color: #B5F109;\n  --md-code-hl-number-color: #AE81FF;\n}\n"
  },
  {
    "path": "help/docs/uoaapi.md",
    "content": "# UOAssist API (UOA API)\n\nRazor supports the **UO Assist API** to allow basic integration into Razor. This information was pulled from [here](http://web.archive.org/web/20100419122932/http://www.tugsoft.com/uoassist/thirdpartydev.asp). It has been slightly modified for formatting purposes.\n\n## Messages Received\n\nMessages that Razor will process  (WM_USER = 0x0400 or 1024)\n\n### Request Data  (WM_USER+200)\n\nThis is used to register your application with Razor.  Once your application is registered Razor will begin sending your application the messages described below.\n\n* Parameters: WPARAM = The window handle where you want messages sent.  LPARAM = flags  ( 1 = get house notifications, NOTE all notification with a lesser notify value than the house notification will go to all windows that have requested information)\n* Returns 2 on unhook, 1 on success, 0 on failure (failure means all slots full) .  \n!!! note\n    If you have registered a window and wish to unregister just send the message with the window handle again. \n\n### Count Resources (WM_USER+201)\n\nThis will prompt Razor to begin counting resources. \n\n* Parameters:  NONE\n* Returns 1 on successful start or 0 on stop.\n\n!!! note\n    If resources are already being counted the count will be stopped.\n\n    Currently it will always return 0 - this MAY be changed in the future but for now it will be zero\n\n### Get Coords (WM_USER+202)\n\nGets the current location of the character.\n\n* Parameters:  NONE\n* Returns: X in the loword and Y in the hiword.  (x=LOWORD(retVal); y=HIWORD(retVal);)\n* \n!!! note\n    You MUST use SendMessage for the return value to be valid.\n\n### Get Skill (WM_USER+203)\n\nGets the current skill level of specified skill.\n\n* Parameters: WPARAM = skill number ( 0 based )  LPARAM (when 0 the return will be the 'display' value, when 1 it will be the 'base' value, 2 = get lock value, 3 = get skill name  ).\n* Returns:  Skill level * 10.  Meaning if the skill level was 19.4 you would get 194 returned.  Or if lock value was requested the return is 0 = up, 1 = down, 2 = locked.  If the skill name is requested the value is a global atom that you will need to free.\n\n!!! note\n    You MUST use SendMessage for the return value to be valid.\n\n### Get Stat (WM_USER+204)\n\nGets the stat and its related attribute.\n\n* Parameters: WPARAM = stat to get   (str = 0, int = 1, dex = 2, weight = 3, 4 = Max HP, 5 = tithing points)\n* Returns: Requested stat (str,int,dex, weight, max hp) in the loword and (hp,mana,stam, max weight, current hp) in hiword.   You MUST use SendMessage for the return value to be valid.\n\n### Set Active Macro (WM_USER + 205)\n\n!!! tip\n    This is not enabled in Razor\n\nSets the active macro\n\n* Parameters: WPARAM = macro (zero based  0-7)\n\n### Play macro (WM_USER+206)\n\nPlays/Stops active macro\n\n* Parameters: None\n* Returns: 0 - macro stopped  1 - macro playing\n\n### Display text (WM_USER+207)\n\nDisplays text on the game screen\n\n* Parameters: WPARAM loword = color  hiword = (0- over characters head 1- system message)\n                    LPARAM = global atom that contains string - Razor frees the atom after using it (See Windows SDK on ATOMS)\n* Returns 0 - failure either the user isn't logged in or the atom wasn't found,    1 - success\n\n!!! tip\n    Razor will only read strings 255 characters or less, I didn't actually test to see if uo can handle strings that long so if you plan to use long strings you should test that out first.\n\n### Request house/boat information (WM_USER+208)\n\nRequests the information on house(s)/boat(s) in the nearby area.\n\n* Parameters: None\n* Returns:  0 - failure (not logged into game) 1 - success\n\n!!! tip\n    You should make sure you are set to receive updates from Razor first.\n\n### Add command line command (WM_USER+209)\n\nAdd a command line command to Razor.  When the user types the command (prefix is '-') you can receive a notification and the parameters the user enters using this feature.  For example if you add the command 'broadcast' and the user types in '-broadcast run away' your window will receive a message with 'run away' as the parameters (in a global ATOM).\n\n* Parameters: WPARAM - HWND of the window to receive the message. LPARAM - ATOM of the command (NOTE: spaces won't work correct)\n* Returns On failure  0 - All command space has been used,  1 - the command ATOM was not found (must be a global atom)\n    - On success - returns the value of the message your window will receive (should be >= WM_USER + 400). The message you will receive will be like this:\n        - MessageID = return value from add call (remember to use SendMessage)\n        - WPARAM =  NULL - either a global atom couldn't be create or no parameters were entered\n        - or a global ATOM that contains the parameters (You must delete the ATOM yourself)(See Windows SDK on ATOMS)\n\n!!! tip\n    Commands are not case sensitive.  If you add a command '/command' the user will have to type -/command in order for you to get the message.  To remove a command send the command again with a zero as the WPARAM.\n\n### Get User ID (WM_USER+210)\n\nYou must use send message on this one.  It returns a ID that Razor can use to identify the user (NOTE: it is not the actual user ID used by the servers).  This is used to add a player to your party.\n\n* Returns 0 if no user is logged in or a value if a user is logged into the game.\n\n### Get Shard Name (WM_USER+211)\n\n* Returns 0 if no user is logged into the game or if a global atom could not be created.\n* Returns a global atom with the shard name in it. \n\nYou must use SendMessage for this message.\n\n### Add user to party (WM_USER+212)\n\n* Parameters: WPARAM - User ID obtained from Get User ID message.\n* Returns 0 on success, 1 on error (will not work if a macro is playing)  You must use send message if you want the return value.\n\n### Get UO window handle (WM_USER + 213)\n\n* Parameters: None\n* Returns the HWND of the UO window.  NOTE - you must use SendMessage to get the correct value.\n\n### Get poison status  (WM_USER + 214)\n\n* Parameters: None\n* Returns  1 if poisoned or 0 if not poisoned.  NOTE - you must use SendMessage to get the correct value.\n\n### Set skill lock (WM_USER + 215)\n\n* Parameters:  WPARAM = zero based skill number, LPARAM = lock direction  [0 = up, 1 = down, 2 = locked]\n* Returns 0 on success, 1 on failure (will fail with invalid param(s) or not logged into game).  NOTE: when the lock value is set Razor requests the current skill values from the server.  So don't set locks in rapid succession for a long period of time or you may lag yourself out.\n\n### Get account identifier (WM_USER + 216)\n\n* Parameters:  None currently\n* Returns 0 if no character is logged into game otherwise a identifier for the account\n\n## Messages Sent\n\nMessages Razor will send to apps that have registered a valid window.\n\n### Resource Count Finished (WM_USER+301)\n\nThis message is sent when resource counting has finished.\n\n* Parameters : WPARAM is defined below and LPARAM is the count\n    - BloodMoss = 1\n    - BlackPearl = 2\n    - Garlic = 3\n    - Ginseng = 4\n    - Mandrake Root = 5\n    - NightShade = 6\n    - Sulfurous Ash = 7\n    - Spider Silk = 8\n    - User1 = 9\n    - User2 = 10    \n    - User3 = 11\n    - User4 = 12\n    - User5 = 13\n    - User6 = 14\n    - Batwing = 100\n    - DaemonBlood = 101\n    - GraveDust = 102\n    - NoxCrystal = 103\n    - PigIron = 104\n    - Tithing = 200\n\n### Spell was attempted  (WM_USER+302)\n\nThis message is sent when a spell is attempted.  It is not known if the spell will fail or timeout or be cancelled.\n\n* Parameters:  WPARAM is the spell being cast (1 based)\n\n### Logon (WM_USER+303)\n\nSent when a character logs into the game\n\n* Parameters:  WPARAM is a character identifier (number value).\n\n### Magery skill level (WM_USER+304)\n\nSent a few seconds after entering game and then whenever the skills window is opened or the skill level changes.\n\n* Parameters: WPARAM is set to the whole number of the skill.  LPARAM is set to the tenth's.\n\n### Current Int and Mana Level (WM_USER+305)\n\nSent whenever new information is sent from the server.\n\n* Parameters: WPARAM has Intel and LPARAM has current mana level.\n\n### Skill Level (WM_USER+306)\n\nSent a few seconds after entering the game and then whenever the skills window is opened or a skill level changes.\n\n* Parameters: WPARAM is skillnum (0 based).  LPARAM is skill level * 10. Meaning if the skill is 19.4 you will get 194\n\n### Macro Finished (WM_USER+307)\n\nSend when a macro finishes playing through one pass.\n\n### Logout (WM_USER+308)\n\nSent when a character logs out of the game.\n\n### Current Max HP and HP Level (WM_USER+309)\n\nSent whenever new information is sent from the server.\n\n* Parameters: WPARAM has Max HP and LPARAM has current hit point level. (NOTE this changed 8/2001 because of changes OSI made to how max hp are calculated [no longer str = max hp]).\n\n### Current Dex and Stamina Level (WM_USER+310)\n\nSent whenever new information is sent from the server.\n\n* Parameters: WPARAM has Dex and LPARAM has current stamina level.\n\n### Add House/boat (WM_USER+311)  [You must set flag 1 to get this message]\n\nSent whenever a house comes into update range.\n\n* Parameters:    WPARAM - X in the loword and Y in the hiword.  (x=LOWORD(wParam); y=HIWORD(wParam);)\n                      LPARAM - house type\n\n* Types:\n    - 0x4000=small boat (n)\n    - 0x4001=small boat (e)\n    - 0x4002= small boat (s)\n    - 0x4003=small boat (w)\n    - 0x4004=small dragon boat (n)\n    - 0x4005=small boat (e)\n    - 0x4006=small boat (s)\n    - 0x4007=small boat (w)\n    - 0x4008=medium boat (n)\n    - 0x4009=medium boat (e)\n    - 0x400a=medium boat (s)\n    - 0x400b=medium boat (w)\n    - 0x400c=medium dragon boat (n)\n    - 0x400d=medium boat (e)\n    - 0x400e=medium boat (s)\n    - 0x400f=medium boat (w)\n    - 0x4010=large boat (n) \n    - 0x4011=large boat (e)\n    - 0x4012=large boat (s)\n    - 0x4013=large boat (w)\n    - 0x4014=large dragon boat (n)\n    - 0x4015=large boat (e)\n    - 0x4016=large boat (s)\n    - 0x4017=large boat (w)\n    - 0x4064=small plaster\n    - 0x4066=small field stone\n    - 0x4068=small brick\n    - 0x406a=small wood\n    - 0x406c=small wood and plaster\n    - 0x406e=small hut\n    - 0x4070=blue tent\n    - 0x4072=green tent\n    - 0x4074=large house\n    - 0x4076=two story (wood & plaster)\n    - 0x4078=two story (plaster)\n    - 0x407a=tower\n    - 0x407c=keep\n    - 0x407e=castle\n    - 0x408c=generic shop\n    - 0x4096=marble patio\n    - 0x4098=small tower\n    - 0x409a=log cabin\n    - 0x409c=sandstone patio\n    - 0x409e=villa\n    - 0x40a0=stone shop\n    - 0x40a2=marble shop\n    - 0x5388=minax's fortress\n\n### Delete House/Boat (WM_USER+312) [You must set flag 1 to get this message]\n\nSent when a boat moves or is dry docked or disappears (same with house)\n\n* Parameters:    WPARAM - X in the loword and Y in the hiword.  (x=LOWORD(wParam); y=HIWORD(wParam);) LPARAM - house type\n\n### Facet/land info (WM_USER+313) [You must set flag 1 to get this message]\n\nSent when the client receives information on which facet/world you are on.  This happens when you switch facets/worlds and can at other times as well\n\n* Parameters:    WPARAM -  0 = Felucca  1 = Trammel  2 = Ilshenar\n\n### Power hour entered (WM_USER+314)\n\n!!! tip\n    Not used by Razor\n\nSent when the client receives the 'You are in your power hour!' message."
  },
  {
    "path": "help/mkdocs.yml",
    "content": "site_name: UO Razor - Ultima Online Assistant\nsite_description: UO Razor is a free tool designed to help with simple tasks while playing Ultima Online\nsite_author: Project maintained by Quick\nsite_url: https://www.razorce.com\ncopyright: Copyright &copy; 2023 Quick\nrepo_url: https://github.com/markdwags/Razor\nrepo_name: Razor\nedit_uri: \"tree/master/help/docs\"\nextra_css:\n  - stylesheets/extra.css\nnav:\n- UO Razor Home: index.md\n- Download: download.md\n- Install:\n    - Windows: install/windows.md\n    - Linux: install/linux.md\n- Release Notes: releasenotes.md\n- Help Guide:\n    - Help Overview: help/index.md    \n    - General: help/general.md\n    - Options: help/options.md    \n    - Display/Counters: help/displaycounters.md\n    - Arm/Dress: help/armdress.md\n    - Skills: help/skills.md\n    - Agents: help/agents.md\n    - Filters: help/filters.md\n    - Hot Keys: help/hotkeys.md\n    - Macros: help/macros.md\n    - Scripts: help/scripts.md\n    - Friends: help/friends.md    \n    - Screen Shots: help/screenshots.md\n    - Advanced: help/advanced.md\n- Scripting Guide:\n    - Scripting Overview: guide/index.md\n    - Commands: guide/commands.md\n    - Comments: guide/comments.md\n    - Expressions: guide/expressions.md\n    - Keywords: guide/keywords.md\n    - Layers: guide/layers.md\n    - Variables: guide/variables.md\n- More Information:\n    - FAQ: faq.md\n    - History: history.md\n    - UOAssist API: uoaapi.md\n\ntheme: \n    name: material    \n    custom_dir: overrides\n    language: en    \n    logo: images/razor.png\n    favicon: images/razor.ico\n    features:\n        - navigation.top\n        - navigation.instant\n        - navigation.tracking\n        - navigation.indexes\n        - search.suggest\n        - search.highlight\n        - search.share\n    icon:\n        repo: fontawesome/brands/github\n    palette:\n        - media: \"(prefers-color-scheme: dark)\"\n          scheme: slate\n          primary: red\n          accent: blue\n          toggle:\n            icon: material/weather-sunny\n            name: Switch to light mode            \n        - media: \"(prefers-color-scheme: light)\"\n          scheme: default\n          primary: red\n          toggle:\n            icon: material/weather-night\n            name: Switch to dark mode\n    font:\n        #text: Mulish\n        #text: Alata\n        #text: Noto Sans JP\n        #text: Lato\n        #text: Ubuntu\n        text: Titillium Web\n        code: Fira Code\n\nmarkdown_extensions:\n  - admonition\n  - toc:\n      baselevel: 3    \n      permalink: true    \n  - pymdownx.highlight:\n      linenums: true\n      linenums_style: pymdownx.inline\n  - pymdownx.inlinehilite\n  - pymdownx.superfences\n  - pymdownx.keys\n  - pymdownx.tabbed:\n      alternate_style: true\n  - attr_list\n  - pymdownx.details\n  - meta\n\nplugins:\n  - search\n  - git-revision-date-localized\n  - social\n\nextra:  \n  social:\n    - icon: fontawesome/brands/github\n      link: https://github.com/markdwags/Razor\n  analytics:\n    provider: google\n    property: G-9ER2MNGL02  \n    feedback:\n      title: Was this page helpful?\n      ratings:\n        - icon: material/emoticon-happy-outline\n          name: This page was helpful\n          data: 1\n          note: >-\n            Thanks for your feedback!\n        - icon: material/emoticon-sad-outline\n          name: This page could be improved\n          data: 0\n          note: >- \n            Thanks for your feedback! Help us improve this page by\n            contributing to <a href=\"https://github.com/markdwags/Razor\" target=\"_blank\" rel=\"noopener\">our repository</a>.\n"
  },
  {
    "path": "help/overrides/main.html",
    "content": "\n{% extends \"base.html\" %}\n\n{% block extrahead %}\n        \n{% endblock %}\n"
  },
  {
    "path": "help/pygments.lexers.razor",
    "content": "\"\"\"\n    pygments.lexers.razor\n    ~~~~~~~~~~~~~~~~~~~~~~~~\n\n    Lexers for languages related to the Razor UO assistant scripting language.\n\n    :copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS.\n    :license: BSD, see LICENSE for details.\n\"\"\"\n\nimport re\nfrom bisect import bisect\n\nfrom pygments.lexer import RegexLexer, bygroups, default, include, this, using\nfrom pygments.lexers.python import PythonLexer\nfrom pygments.token import Comment, Keyword, Name, Number, Operator, \\\n    Punctuation, String, Text, Whitespace\n\n__all__ = ['RazorLexer']\n\nclass RazorLexer(RegexLexer):\n    \"\"\"\n    Lexer for Razor script files.\n\n    .. versionadded:: 2.14.0\n    \"\"\"\n    name = 'RazorL'\n    aliases = ['razor']\n    filenames = ['*.razor']\n    mimetypes = ['text/x-razor']\n    flags = re.MULTILINE\n\n    _python = r'py(?:t(?:h(?:o(?:n)?)?)?)?'\n\n    tokens = {\n        'root': [\n            # Single-line comments\n            (r'(#|\\/\\/).*$\\n?', Comment.Single),\n\n            # Strings\n            (r'(\\\"[^\\\"]*\\\")|(\\'[^\\']*\\')', String),\n\n            # Hex values\n            (r'0x[0-9a-fA-F]+', Number.Hex),\n\n            # Numbers\n            (r'\\b\\d+\\b', Number),\n\n            # Keywords\n            (r'\\b(if|elseif|else|endif|while|endwhile|for|foreach|endfor|break|continue|not|and|or|stop|replay|loop|as|in)\\b', Keyword),\n\n            # Command words\n            (r'\\b(clearhands|sell|cleardragdrop|attack|cast|dress|undress|dressconfig|target|targettype|targetloc|targetrelloc|dress|drop|waitfortarget|wft|dclick|dclicktype|dclickvar|usetype|useobject|droprelloc|lift|lifttype|waitforgump|gumpresponse|gumpclose|menu|menuresponse|waitformenu|promptresponse|waitforprompt|hotkey|say|msg|overhead|sysmsg|wait|pause|waitforstat|setability|setlasttarget|lasttarget|setvar|unsetvar|skill|useskill|walk|script|useonce|organizer|organize|org|restock|scav|scavenger|potion|clearsysmsg|clearjournal|whisper|yell|guild|alliance|emote|waitforsysmsg|wfsysmsg|clearall|virtue|interrupt|sound|music|classicuo|cuo|rename|getlabel|ignore|unignore|clearignore|cooldown|settimer|removetimer|createtimer|poplist|pushlist|removelist|createlist|clearlist)\\b', Name.Builtin),\n\n            # Layer words\n            (r'\\b(RightHand|LeftHand|Shoes|Pants|Shirt|Head|Gloves|Ring|Talisman|Neck|Hair|Waist|InnerTorso|Bracelet|FacialHair|MiddleTorso|Earrings|Arms|Cloak|Backpack|OuterTorso|OuterLegs|InnerLegs|backpack|true|false|criminal|enemy|friend|friendly|grey|gray|innocent|murderer|red|blue|nonfriendly|cancel|clear|minutes|minute|min|seconds|second|sec)\\b', Name.Decorator),\n\n            # Expression words\n            (r'\\b(queued|position|insysmsg|insysmessage|findtype|findbuff|finddebuff|stam|maxstam|hp|maxhp|maxhits|hits|mana|maxmana|str|dex|int|poisoned|hidden|mounted|rhandempty|lhandempty|skill|count|counter|weight|dead|closest|close|rand|random|next|prev|previous|human|humanoid|monster|varexist|varexist|followers|maxfollowers|maxweight|targetexists|diffmana|diffstam|diffhits|diffhp|diffweight|blessed|invul|invuln|warmode|name|paralyzed|itemcount|poplist|atlist|listexists|list|inlist|timer|timerexists)\\b', Name.Function),\n\n            # Default\n            (r'.', Text),\n        ]\n    }\n    \n"
  },
  {
    "path": "help/pygments.mapping.razor",
    "content": "# Automatically generated by scripts/gen_mapfiles.py.\n# DO NOT EDIT BY HAND; run `tox -e mapfiles` instead.\n\nLEXERS = {    \n    'BashLexer': ('pygments.lexers.shell', 'Bash', ('bash', 'sh', 'ksh', 'zsh', 'shell'), ('*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass', '*.exheres-0', '*.exlib', '*.zsh', '.bashrc', 'bashrc', '.bash_*', 'bash_*', 'zshrc', '.zshrc', '.kshrc', 'kshrc', 'PKGBUILD'), ('application/x-sh', 'application/x-shellscript', 'text/x-shellscript')),\n    'JsonLexer': ('pygments.lexers.data', 'JSON', ('json', 'json-object'), ('*.json', 'Pipfile.lock'), ('application/json', 'application/json-object')),\n    'RazorLexer': ('pygments.lexers.razor', 'RazorL', ('razor',), ('*.razor'), ('text/x-razor',)),        \n    'CSharpLexer': ('pygments.lexers.dotnet', 'C#', ('csharp', 'c#', 'cs'), ('*.cs',), ('text/x-csharp',)),\n    'XmlLexer': ('pygments.lexers.html', 'XML', ('xml',), ('*.xml', '*.xsl', '*.rss', '*.xslt', '*.xsd', '*.wsdl', '*.wsf'), ('text/xml', 'application/xml', 'image/svg+xml', 'application/rss+xml', 'application/atom+xml')),\n}\n"
  },
  {
    "path": "help/pygments.styles.razor",
    "content": "\"\"\"\n    pygments.styles.razor\n    ~~~~~~~~~~~~~~~~~~~\n\n    A highlighting style for Pygments, inspired by Razor UO.\n\n    :copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS.\n    :license: BSD, see LICENSE for details.\n\"\"\"\n\nfrom pygments.style import Style\nfrom pygments.token import Keyword, Name, Comment, String, Error, \\\n     Number, Operator, Generic, Whitespace, Token\n\n\nclass RazorStyle(Style):\n    \"\"\"\n    Styles somewhat like UO razor assistant\n    \"\"\"\n\n    background_color = \"#000000\"\n    highlight_color = \"#222222\"\n\n    styles = {\n        Token:                     \"#cccccc\",\n        Whitespace:                \"\",\n        Comment:                   \"#969696\",\n        Comment.Single:            \"#969696\",\n        Comment.Preproc:           \"\",\n        Comment.Special:           \"bold #cd0000\",\n\n        Keyword:                   \"#cdcd00\",\n        Keyword.Declaration:       \"#00cd00\",\n        Keyword.Namespace:         \"#cd00cd\",\n        Keyword.Pseudo:            \"\",\n        Keyword.Type:              \"#00cd00\",\n\n        Operator:                  \"#3399cc\",\n        Operator.Word:             \"#cdcd00\",\n\n        Name:                      \"\",\n        Name.Class:                \"#00cdcd\",\n        Name.Builtin:              \"#2B90AF\",\n        Name.Exception:            \"bold #666699\",\n        Name.Variable:             \"#00cdcd\",\n\n        String:                    \"#B5F109\",\n        Number:                    \"#AE81FF\",\n        Number.Hex:                \"#F9254D\",\n\n        Generic.Heading:           \"bold #000080\",\n        Generic.Subheading:        \"bold #800080\",\n        Generic.Deleted:           \"#cd0000\",\n        Generic.Inserted:          \"#00cd00\",\n        Generic.Error:             \"#FF0000\",\n        Generic.Emph:              \"italic\",\n        Generic.Strong:            \"bold\",\n        Generic.Prompt:            \"bold #000080\",\n        Generic.Output:            \"#888\",\n        Generic.Traceback:         \"#04D\",\n\n        Error:                     \"border:#FF0000\"\n    }\n"
  }
]